鸿蒙ArkTS Tabs组件开发底部导航栏,可自适应平板和手机,相当于Android开发中的MainActivity+Fragment的底部导航栏模式。
一、主页:MainPage.ets
import { BreakpointSystem, BreakpointConstants, StyleConstants, PageConstants, } from '@ohos/common'; // 通用工具
import { Chat } from '@ohos/chat'; // 子模块 相当于Android 的Fragment
import { Contact } from '@ohos/Contact'; // 子模块
import { Work } from '@ohos/Work'; // 子模块
import { Mine } from '@ohos/Mine'; // 子模块
import { buttonInfo, ButtonInfoModel } from '../viewmodel/MainPageData'; // 底部导航数据
@Entry
@Component
struct MainPage {
@StorageProp('currentBreakpoint') currentBreakpoint: string = 'sm';
@State currentPageIndex: number = 0;
private breakpointSystem = new BreakpointSystem();
aboutToAppear() {
this.breakpointSystem.register();
}
aboutToDisappear() {
this.breakpointSystem.unregister();
}
@Builder BottomNavigation(button: ButtonInfoModel) {
Column({ space: PageConstants.BUTTON_SPACE }) { // static readonly BUTTON_SPACE: string = '6vp';
Image(this.currentPageIndex === button.index ? button.selectImg : button.img)
.objectFit(ImageFit.Contain)
.width($r('app.float.main_image_size'))
.height($r('app.float.main_image_size'))
Text(button.title)
.fontColor(this.currentPageIndex === button.index ? $r('app.color.focus_color') : $r('app.color.un_focus_color'))
.opacity(this.currentPageIndex === button.index ? StyleConstants.FULL_OPACITY : StyleConstants.SIXTY_OPACITY)
.fontWeight(StyleConstants.FONT_WEIGHT_FIVE)
.textAlign(TextAlign.Center)
.fontSize($r('app.float.micro_font_size'))
}
.width(StyleConstants.FULL_WIDTH)
.height(StyleConstants.FULL_HEIGHT)
.alignItems(HorizontalAlign.Center)
.justifyContent(FlexAlign.Center)
}
build() {
Column() {
Tabs({
barPosition: this.currentBreakpoint === BreakpointConstants.BREAKPOINT_LG ?
BarPosition.Start : BarPosition.End,
index: this.currentPageIndex,
}) {
TabContent() {
Chat() // 子模块
}.tabBar(this.BottomNavigation(buttonInfo[0]))
TabContent() {
Contact() // 子模块
}.tabBar(this.BottomNavigation(buttonInfo[1]))
TabContent() {
Work() // 子模块
}.tabBar(this.BottomNavigation(buttonInfo[2]))
TabContent() {
Mine() // 子模块
}.tabBar(this.BottomNavigation(buttonInfo[3]))
}
.barWidth(this.currentBreakpoint === BreakpointConstants.BREAKPOINT_LG ?
$r('app.float.bar_width') : StyleConstants.FULL_WIDTH)
.barHeight(this.currentBreakpoint === BreakpointConstants.BREAKPOINT_LG ?
StyleConstants.SIXTY_HEIGHT : $r('app.float.vp_fifty_six'))
.vertical(this.currentBreakpoint === BreakpointConstants.BREAKPOINT_LG)
.scrollable(false)
.onChange((index: number) => {
this.currentPageIndex = index;
// 提前查询数据
// if (index === 1) {
// this.queryShopCart();
// } else if (index === 2) {
// this.queryOrderList();
// }
})
}
.backgroundColor($r('app.color.page_background'))
}
}
StyleConstants.ets:
/**
* Constants for common style.
*/
export class StyleConstants {
/**
* Component width percentage: 100%.
*/
static readonly FULL_WIDTH: string = '100%';
/**
* Component height percentage: 100%.
*/
static readonly FULL_HEIGHT: string = '100%';
/**
* Component height percentage: 70%.
*/
static readonly SEVENTY_HEIGHT: string = '70%';
/**
* Component height percentage: 60%.
*/
static readonly SIXTY_HEIGHT: string = '60%';
/**
* Component width percentage: 60%.
*/
static readonly SIXTY_WIDTH: string = '60%';
/**
* Component height percentage: 50%.
*/
static readonly FIFTY_HEIGHT: string = '50%';
/**
* Component height percentage: 50%.
*/
static readonly HUNDRED_FIFTEEN_WIDTH: string = '115%';
/**
* Component space vp : 4.
*/
static readonly FOUR_SPACE: string = '4vp';
/**
* Component space vp : 12.
*/
static readonly TWELVE_SPACE: string = '12vp';
/**
* Component space vp : 14.
*/
static readonly ITEM_SPACE: string = '14vp';
/**
* Component space vp : 15.
*/
static readonly FIFTEEN_SPACE: string = '15vp';
/**
* Font weight value: 700.
*/
static readonly FONT_WEIGHT_SEVEN: number = 700;
/**
* Font weight value: 500.
*/
static readonly FONT_WEIGHT_FIVE: number = 500;
/**
* Font weight value: 400.
*/
static readonly FONT_WEIGHT_FOUR: number = 400;
/**
* Text line value: 2.
*/
static readonly TWO_TEXT_LINE: number = 2;
/**
* Component opacity value: 1.
*/
static readonly FULL_OPACITY: number = 1;
/**
* Component opacity value: 0.6.
*/
static readonly SIXTY_OPACITY: number = 0.6;
/**
* Component opacity value: 0.8.
*/
static readonly EIGHTY_OPACITY: number = 0.8;
/**
* Component layout value: 1.
*/
static readonly LAYOUT_WEIGHT: number = 1;
/**
* Flex basic value: 1.
*/
static readonly FLEX_BASIC: number = 1;
/**
* Flex shrink value: 1.
*/
static readonly FLEX_SHRINK: number = 1;
/**
* Flex grow value: 1.
*/
static readonly FLEX_GROW: number = 1;
/**
* Swiper or list display count value: 1.
*/
static readonly DISPLAY_ONE: number = 1;
/**
* Swiper or list display count value: 2.
*/
static readonly DISPLAY_TWO: number = 2;
/**
* Swiper or list display count value: 3.
*/
static readonly DISPLAY_THREE: number = 3;
/**
* Swiper or list display count value: 4.
*/
static readonly DISPLAY_FOUR: number = 4;
/**
* Image aspect ratio value: 2.23.
*/
static readonly IMAGE_ASPECT_RATIO: number = 2.25;
/**
* Number of value: 0.5.
*/
static readonly HALF_ONE: number = 0.5;
/**
* Number of value: -1.
*/
static readonly MINUS_ONE: number = -1;
}
二、BreakpointSystem.ets:响应式设计的核心
import mediaQuery from '@ohos.mediaquery';
import { BreakpointConstants } from '../constants/BreakpointConstants';
declare interface BreakPointTypeOption<T> {
sm?: T
md?: T
lg?: T
xl?: T
xxl?: T
}
/**
* 媒体查询(mediaquery)
* 响应式设计的核心
*/
export class BreakPointType<T> {
options: BreakPointTypeOption<T>
constructor(option: BreakPointTypeOption<T>) {
this.options = option
}
getValue(currentBreakPoint: string): T {
return this.options[currentBreakPoint] as T
}
}
export class BreakpointSystem {
private currentBreakpoint: string = '';
private smListener?: mediaQuery.MediaQueryListener;
private mdListener?: mediaQuery.MediaQueryListener;
private lgListener?: mediaQuery.MediaQueryListener;
private updateCurrentBreakpoint(breakpoint: string) {
if (this.currentBreakpoint !== breakpoint) {
this.currentBreakpoint = breakpoint;
AppStorage.Set<string>(BreakpointConstants.CURRENT_BREAKPOINT, this.currentBreakpoint);
}
}
private isBreakpointSM = (mediaQueryResult: mediaQuery.MediaQueryResult) => {
if (mediaQueryResult.matches) {
this.updateCurrentBreakpoint(BreakpointConstants.BREAKPOINT_SM);
}
}
private isBreakpointMD = (mediaQueryResult: mediaQuery.MediaQueryResult) => {
if (mediaQueryResult.matches) {
this.updateCurrentBreakpoint(BreakpointConstants.BREAKPOINT_MD);
}
}
private isBreakpointLG = (mediaQueryResult: mediaQuery.MediaQueryResult) => {
if (mediaQueryResult.matches) {
this.updateCurrentBreakpoint(BreakpointConstants.BREAKPOINT_LG);
}
}
public register() {
this.smListener = mediaQuery.matchMediaSync(BreakpointConstants.RANGE_SM);
this.smListener.on('change', this.isBreakpointSM);
this.mdListener = mediaQuery.matchMediaSync(BreakpointConstants.RANGE_MD);
this.mdListener.on('change', this.isBreakpointMD);
this.lgListener = mediaQuery.matchMediaSync(BreakpointConstants.RANGE_LG);
this.lgListener.on('change', this.isBreakpointLG);
}
public unregister() {
this.smListener?.off('change', this.isBreakpointSM);
this.mdListener?.off('change', this.isBreakpointMD);
this.lgListener?.off('change', this.isBreakpointLG);
}
}
BreakpointConstants.ets:
export class BreakpointConstants {
/**
* Breakpoints that represent small device types.
*/
static readonly BREAKPOINT_SM: string = 'sm';
/**
* Breakpoints that represent middle device types.
*/
static readonly BREAKPOINT_MD: string = 'md';
/**
* Breakpoints that represent large device types.
*/
static readonly BREAKPOINT_LG: string = 'lg';
/**
* Current breakpoints that to query the device types.
*/
static readonly CURRENT_BREAKPOINT: string = 'currentBreakpoint';
/**
* Range of the small device width.
*/
static readonly RANGE_SM: string = '(320vp<=width<520vp)';
/**
* Range of the middle device width.
*/
static readonly RANGE_MD: string = '(520vp<=width<840vp)';
/**
* Range of the large device width.
*/
static readonly RANGE_LG: string = '(840vp<=width)';
}
三、ButtonInfoModel.ets:底部导航按钮数据
export class ButtonInfoModel {
index: number ; // 序号
img: Resource; // 未选中图片
selectImg: Resource ; // 选中图片
title: Resource; // 按钮名称
}
const buttonInfo: ButtonInfoModel[] = [
{
index: 0,
img: $r('app.media.ic_chat_off'),
selectImg: $r('app.media.ic_chat_on'),
title: $r('app.string.chat')
},
{
index: 1,
img: $r('app.media.ic_contact_off'),
selectImg: $r('app.media.ic_contact_on'),
title: $r('app.string.contact')
},
{
index: 2,
img: $r('app.media.ic_work_off'),
selectImg: $r('app.media.ic_work_on'),
title: $r('app.string.work')
},
{
index: 3,
img: $r('app.media.ic_mine_off'),
selectImg: $r('app.media.ic_mine_on'),
title: $r('app.string.mine')
}
]
export { buttonInfo }