鸿蒙开发自定义TabBar,实现tabBar 上中间按钮凸起效果
第一步、定义数据模型
TypeScript
export default class TabItemData{
defaultIcon: Resource
selectedIcon: Resource
title: string
isMiddle: boolean
constructor(defaultIcon:Resource, selectedIcon:Resource, title:string, isMiddle: boolean) {
this.defaultIcon = defaultIcon
this.selectedIcon = selectedIcon
this.title = title
this.isMiddle = isMiddle
}
}
第二步、定义一个ViewModel, 设置数据源
TypeScript
export class MainViewModel {
getTabBarImage(): Array<TabItemData>{
let tabItems: TabItemData[] = [
new TabItemData($r('app.media.home_normal'), $r('app.media.home_selected'), "首页", false),
new TabItemData($r('app.media.discover_normal'), $r('app.media.discover_selected'), "", true),
new TabItemData($r('app.media.mine_normal'), $r('app.media.mine_selected'), "我", false),
]
return tabItems
}
}
export default new MainViewModel();
第三步、自定义组件,定义一个TabItem,用了两个Column 嵌套,代表两个视图容器,由于鸿蒙没有类似Flutter 中Container 这样的组件,所以选择用Column 代替
TypeScript
@Component
export struct TabBarItem{
@Prop isSelected: boolean
itemData: TabItemData
build(){
Column(){
Column(){
Image(this.isSelected? this.itemData.selectedIcon: this.itemData.defaultIcon)
.width(this.itemData.isMiddle? '45vp': '25vp')
.height(this.itemData.isMiddle? '45vp': '25vp')
.interpolation(ImageInterpolation.High)
if (!this.itemData.isMiddle){
Text(this.itemData.title)
.margin({ top: $r('app.float.mainPage_baseTab_top') })
.fontSize($r('app.float.main_tab_fontSize'))
.fontColor(this.isSelected? '#1698CE' : '#6B6B6B')
}
}
.justifyContent(FlexAlign.Center)
.backgroundColor(this.itemData.isMiddle?Color.White: Color.Transparent)
.padding(this.itemData.isMiddle?{top:2,left:2, right:2, bottom: 2}: 0)
.borderRadius('23.5vp')
}.justifyContent(FlexAlign.Center)
.height($r('app.float.mainPage_barHeight'))
.width(Constants.FULL_PARENT)
}
}
第三步、自定义TabBar 组件
TypeScript
@Component
export struct LMTabBar{
@Prop tabIdx:number
tabItemClick:(index)=>void
build(){
Flex(){
ForEach(mainViewModel.getTabBarImage(),(item,index: number)=>{
TabBarItem({itemData: item, isSelected: this.tabIdx === index })
.offset({y: item.isMiddle? '-25': '0'})
.onClick(()=>{
this.tabIdx = index
this.tabItemClick(index)
})
})
}
}
}
第四步、用自定义的TabBar覆盖原来Tabs
TypeScript
@Preview
@Entry
@Component
struct MainPage{
@State currentIndex: number = 0
private tabsController: TabsController = new TabsController()
build(){
Stack(){
Tabs({barPosition: BarPosition.End, controller: this.tabsController }){
TabContent(){
Home()
}
.padding({ left: $r('app.float.mainPage_padding'), right: $r('app.float.mainPage_padding') })
.backgroundColor($r('app.color.mainPage_backgroundColor'))
TabContent(){
Text("发现")
}
TabContent(){
Mine()
}
.padding({ left: $r('app.float.mainPage_padding'), right: $r('app.float.mainPage_padding') })
.backgroundColor($r('app.color.mainPage_backgroundColor'))
}
.barHeight(0)
.onChange((index: number)=>{
this.currentIndex = index
})
LMTabBar({tabIdx: this.currentIndex,tabItemClick: (index)=>{
this.tabsController.changeIndex(index)
} })
.backgroundColor(Color.White)
}.align(Alignment.Bottom)
}
}