华为鸿蒙应用--底部导航栏Tabs(自适应手机和平板)

鸿蒙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 }

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,723评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,080评论 2 379
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,604评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,440评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,431评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,499评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,893评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,541评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,751评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,547评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,619评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,320评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,890评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,896评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,137评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,796评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,335评论 2 342

推荐阅读更多精彩内容