HarmonyOS 鸿蒙Next应用开发实战-自定义TabBar,并添加动画效果
HarmonyOS 鸿蒙Next应用开发实战-自定义TabBar,并添加动画效果 鸿蒙项目开发中,主界面中都会有TabBar,普通的TabBar大家都会使用了,今天来聊聊异于普通样式的TabBar,并添加一些动画效果,更加的美观。
1.话不多说,先展示样式
2.设计思路
因普通的TabBar样式满足不了开发需求,想要中间添加一个+号会比较困难。基于这一点打算发挥自己创新思维,整体使用Stack()帧布局方式,给TabBar提前预留一个+号的位置,然后使用+号的Image给帧到对应位置,就可以实现了,有想法直接开搞。
3.具体代码
@Entry
@Component
struct MainPage {
@State
activeIndex: number = 0;
@State
angleA: number = 0;
@State
translateY: number = 0;
@State
flag: boolean = false;
/**
* 正常Tab 图片 文字 公共管理
* @param title
* @param targetIndex
* @param defaultImg
* @param selectedImg
*/
@Builder
TabBarBuilder(title: string, targetIndex: number, defaultImg: Resource, selectedImg: Resource) {
Column() {
Image(this.activeIndex === targetIndex ? selectedImg : defaultImg)
.size({ width: vp2vp(20), height: vp2vp(20) })
Text(title)
.fontColor(this.activeIndex === targetIndex ? $r('app.color.tab_selected_color') : $r('app.color.tab_default_color'))
.fontSize(vp2vp(12))
.padding({ top: vp2vp(5) })
.lineHeight(vp2vp(12))
}
.width('100%')
.height(vp2vp(50))
.justifyContent(FlexAlign.Center)
.border({ width: { top: 0.5 }, color: $r('app.color.ih_bg_color'), style: BorderStyle.Solid })
.onClick(() => {
this.activeIndex = targetIndex
})
}
dialogController: CustomDialogController = new CustomDialogController({
builder: SignCustomDialogWidget({}),
customStyle: true,
alignment: DialogAlignment.Center
})
build() {
/*****************首页正常 start **************************/
Stack() {
Tabs({
barPosition: BarPosition.End,
index: this.activeIndex
}) {
TabContent() {
HomePage()
}.tabBar(this.TabBarBuilder('首页', 0, $r('app.media.icon_sy_un'), $r('app.media.icon_sy_sel')))
TabContent() {
TaskCenterPage()
}.tabBar(this.TabBarBuilder('任务中心', 1, $r('app.media.icon_rwzx_un'), $r('app.media.icon_rwzx_sel')))
TabContent() { //加号占位 只是占位 不显示
TaskCenterPage()
}.tabBar().onClick(() => {
this.activeIndex = 1;
})
TabContent() {
NotificationPage()
}.tabBar(this.TabBarBuilder('通知通报', 3, $r('app.media.icon_tz_un'), $r('app.media.icon_tz_sel')))
TabContent() {
MinePage()
}.tabBar(this.TabBarBuilder('我的', 4, $r('app.media.icon_my_un'), $r('app.media.icon_my_sel')))
}
.vertical(false)
.onChange((index) => {
if (index === 2) {
this.activeIndex = 1;
} else {
this.activeIndex = index
}
})
.barHeight(vp2vp(80))
Image($r('app.media.icon_add'))
.width('60vp')
.height('60vp')
.margin({ bottom: 40 })
.onClick(() => {
this.flag = !this.flag;
//+号动画更改值
this.change(45)
this.translateChange(-160)
})
.visibility(this.flag === false ? Visibility.Visible : Visibility.Hidden)
/*****************首页正常 end **************************/
/*****************加号弹出 start **************************/
Stack({ alignContent: Alignment.Bottom }) {
Row() {
Image($r('app.media.btn_qiandao'))
.width('80vp')
.height('80vp')
.objectFit(ImageFit.Fill)
.translate({
y: this.translateY
})
.animation({
duration: 1000
})
.onClick(() => {
this.change(0)
this.translateChange(160)
setTimeout(() => {
this.flag = !this.flag;
}, 1100)
if (this.dialogController != undefined) {
this.dialogController.open();
}
})
Image($r('app.media.btn_shijianshangbao'))
.width('80vp')
.height('80vp')
.objectFit(ImageFit.Fill)
.translate({
y: this.translateY-60
})
.animation({
duration: 700
})
.onClick(() => {
this.change(0)
this.translateChange(160)
setTimeout(() => {
this.flag = !this.flag;
}, 1100)
router.pushUrl({ url: RoutePath.SjsbPage })
})
Image($r('app.media.btn_chuzhi'))
.width('80vp')
.height('80vp')
.objectFit(ImageFit.Fill)
.translate({
y: this.translateY-100
})
.animation({
duration: 500
})
.onClick(() => {
this.change(0)
this.translateChange(160)
setTimeout(() => {
this.flag = !this.flag;
}, 1100)
router.pushUrl({ url: RoutePath.CzsbPage })
})
Image($r('app.media.btn_shixiangshangbao'))
.width('80vp')
.height('80vp')
.objectFit(ImageFit.Fill)
.translate({
y: this.translateY-60
})
.animation({
duration: 700
})
.onClick(() => {
this.change(0)
this.translateChange(160)
setTimeout(() => {
this.flag = !this.flag;
}, 1100)
router.pushUrl({ url: RoutePath.SxsbPage })
})
Image($r('app.media.btn_weekly'))
.width('80vp')
.height('80vp')
.objectFit(ImageFit.Fill)
.translate({
y: this.translateY
})
.animation({
duration: 1000
})
.onClick(() => {
this.change(0)
this.translateChange(160)
setTimeout(() => {
this.flag = !this.flag;
}, 1100)
router.pushUrl({ url: RoutePath.WeeklyReportPage })
})
}.justifyContent(FlexAlign.Center).margin({bottom:-60})
Row() {
Image($r('app.media.icon_add'))
.width('60vp')
.height('60vp')
.objectFit(ImageFit.Fill)
.onClick(() => {
this.change(0)
this.translateChange(160)
setTimeout(() => {
this.flag = !this.flag;
}, 1100)
})
.rotate({
x: 0,
y: 0,
z: 1,
angle: this.angleA,
centerX: 30,
centerY: 30,
})
}.padding({ bottom: 40 }).width('80%')
.justifyContent(FlexAlign.Center)
}
.backgroundColor($r('app.color.transparent_bg'))
.width('100%')
.height('100%')
.visibility(this.flag === true ? Visibility.Visible : Visibility.Hidden)
/*****************加号弹出 end **************************/
}.alignContent(Alignment.Bottom)
}
/**
* 旋转
* @param angle
*/
change(angle: number) {
animateTo({
duration: 1000,
iterations: 1,
curve: Curve.Linear
}, () => {
this.angleA = angle
})
}
/**
* 位移
* @param translateY
*/
translateChange(translateY: number) {
animateTo({
duration: 1000,
iterations: 1,
curve: Curve.Friction
}, () => {
this.translateY = translateY
})
}
}
4.发现问题
开发完具体使用的过程发现了一个问题,TabBar可以左右切换,+号的位置对应的应该也会有TabContent,我就把+号空白部位的点击给赋值了下标1,这样+号Image下面空白的位置点击会跳转到下标1的TabContent,这样在左右滑动的时候下标为1的TabContent会出现2遍,暂时想不到更好的方案,有想法的小伙伴,可以一起探讨一下!
更多关于HarmonyOS 鸿蒙Next应用开发实战-自定义TabBar,并添加动画效果的实战教程也可以访问 https://www.itying.com/category-93-b0.html
更多关于HarmonyOS 鸿蒙Next应用开发实战-自定义TabBar,并添加动画效果的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html
在HarmonyOS(鸿蒙Next)应用开发中,自定义TabBar并添加动画效果可以通过ArkUI框架实现。首先,使用Tabs
组件作为基础容器,结合TabContent
来定义每个标签页的内容。为了自定义TabBar的外观,可以使用@Builder
装饰器创建自定义的TabBar组件,并在其中定义每个Tab项的结构和样式。
在ArkUI中,@State
和@Prop
装饰器可以用来管理TabBar的状态,例如当前选中的Tab项。通过@State
变量来控制TabBar的选中状态,并在@Builder
中根据状态动态调整样式。
要为TabBar添加动画效果,可以使用Animation
组件或animateTo
方法。例如,当用户切换Tab时,可以通过animateTo
方法对Tab项的背景色、图标大小或位置进行平滑过渡。ArkUI支持多种动画类型,包括平移、缩放、旋转等,开发者可以根据需求选择合适的动画效果。
此外,鸿蒙的CustomDialog
组件也可以用于实现更复杂的TabBar交互,例如弹出式菜单或动态加载的Tab项。通过结合CustomDialog
和Tabs
组件,可以实现更灵活的自定义TabBar设计。
总结来说,自定义TabBar并添加动画效果的核心在于使用Tabs
、@Builder
、@State
等ArkUI组件和装饰器,结合Animation
或animateTo
实现动态效果。