#夏日挑战赛# 用OpenHarmony eTS 实现一个Huawei app标准布局

Posted 开源基础软件社区官方

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了#夏日挑战赛# 用OpenHarmony eTS 实现一个Huawei app标准布局相关的知识,希望对你有一定的参考价值。

用OpenHarmony eTS 实现一个Huawei app标准布局

本文正在参加星光计划3.0 -- 夏日挑战赛

@TOC

1.介绍

Huawei 的app,我们都能看得出来是用心设计过的,值得学习。如果我们仔细去看Huawei 手机自带的app,我们会发现所有的app,无论是什么类型的app,其布局结构都是一种类似的结构,这说明这种布局结构的用途真的可以很广泛,而且体验很好...

像华为的应用市场app、联系人、浏览器、图库、智慧生活app、音乐app、我的华为、畅连 等等,你去看,全部是这种上中下的布局结构,顶部栏(top+middle)+内容展示区(content)+底部tab栏,那么,今天我们就一起来实现一个这样的布局。

2.效果展示

DAYU200真机

视频地址
https://ost.51cto.com/show/13842

模拟器

3.代码讲解

3.1准备工作

1).添加一个用来保存image资源的ets文件,resource_const.ets

export function initImageMap(): Map<string, Resource> 
  let imageMap = new Map()

  //tappage
  //tab icon
  imageMap.set(tab_01, $r(app.media.ic_public_home))
  imageMap.set(tab_02, $r(app.media.ic_public_appstore))
  imageMap.set(tab_03, $r(app.media.ic_gallery_album_damage_video))
  imageMap.set(tab_04, $r(app.media.ic_gallery_search_things))
  imageMap.set(tab_05, $r(app.media.ic_user_portrait))

  imageMap.set(tab_01_filled, $r(app.media.ic_public_home_filled))
  imageMap.set(tab_02_filled, $r(app.media.ic_public_appstore_filled))
  imageMap.set(tab_03_filled, $r(app.media.ic_gallery_album_damage_video_filled))
  imageMap.set(tab_04_filled, $r(app.media.ic_gallery_search_things_filled))
  imageMap.set(tab_05_filled, $r(app.media.ic_user_portrait_filled))

  //tab color
  imageMap.set(tab_filled_color, $r(app.color.filled_color))
  imageMap.set(tab_unfilled_color, $r(app.color.unfilled_color))

  return imageMap

为什么要这么做,

一是因为我发现,有时候如果直接这样用,有时候图片就会错乱,显示的不是该图片。

二是用改起来方便。

Image($r(app.media.light_power))  //这样直接用
  .width(40)
  .height(40)
  .alignSelf(ItemAlign.End)
  .margin( right: 10%, bottom: 3% )
  .onClick(() => 
    router.push( uri: pages/index )
  )

2).string.json资源文件中定义tab显示文本

  
    "name": "tab_01",
    "value": "家居"
  
,
  
    "name": "tab_02",
    "value": "商城"
  
,
  
    "name": "tab_03",
    "value": "内容"
  
,
  
    "name": "tab_04",
    "value": "场景"
  
,
  
    "name": "tab_05",
    "value": "我的"
  

接下来就是进入正题了,新建一个ets页面,tabpage.ets

3.2实现一个底部tab栏

1).导入需要用的组件

//日志组件
import  CommonLog  as logger  from @ohos/ohos_clogger

//用于数据展示模型
import  NoticeDataModel, initOneNoticeData  from "../model/NoticeDataModel"

//引入定义的常量、视图组件
import  initImageMap  from ../common/resource_const

//资源管理,用于实现屏幕方向的获取
import resourceManager from @ohos.resourceManager;

2).定义tab图标和文本颜色 状态变量

//tab icon
@State tab_01_icon: Resource = initImageMap().get(tab_01_filled)
@State tab_02_icon: Resource = initImageMap().get(tab_02)
@State tab_03_icon: Resource = initImageMap().get(tab_03)
@State tab_04_icon: Resource = initImageMap().get(tab_04)
@State tab_05_icon: Resource = initImageMap().get(tab_05)
//tab 文本颜色
@State tab_01_color: Resource = initImageMap().get(tab_filled_color)
@State tab_02_color: Resource = initImageMap().get(tab_unfilled_color)
@State tab_03_color: Resource = initImageMap().get(tab_unfilled_color)
@State tab_04_color: Resource = initImageMap().get(tab_unfilled_color)
@State tab_05_color: Resource = initImageMap().get(tab_unfilled_color)

3).接下来看看build() 的布局,

最外层用Column容器布局,然后是Flex布局,top栏,middle,Content都是一行一行的,所以用Row容器布局,先占个位。

底部的tab栏用Flex布局,每个tab用Column布局,Column是上下2层,一个image,一个文本。

5个tab,所以每个tab的width设为20%,为了更美观,给最外层的Column设置个背景图片 。

build() 
  Column() 
    //用Flex布局  
    Flex( direction: FlexDirection.Column, wrap: FlexWrap.NoWrap ) 
        //top栏
        Row() .width(100%).height(80vp)
        //middle
        Row() .width(100%).height(150vp)
        //content
        Row() .width(100%).height(100%)
        //bottom tab
        Flex() 
          Column() 
            Image(this.tab_01_icon)
              .width(100%)
              .height(50%)
              .flexShrink(0)
              .objectFit(ImageFit.Contain)
            Text($r(app.string.tab_01))
              .width(100%)
              .height(50%)
              .flexShrink(0)
              .fontColor(this.tab_01_color)
              .fontSize(15fp)
              .textAlign(TextAlign.Center)
          .onClick(() => 
            this.current_tab_index = 1
            this.switchTab()
          )
          .width(20%)
          .height(100%)

          Column() 
            Image(this.tab_02_icon)
              .width(100%)
              .height(50%)
              .flexShrink(0)
              .objectFit(ImageFit.Contain)
            Text($r(app.string.tab_02))
              .width(100%)
              .height(50%)
              .flexShrink(0)
              .fontColor(this.tab_02_color)
              .fontSize(15fp)
              .textAlign(TextAlign.Center)
          
          .onClick(() => 
            this.current_tab_index = 2
            this.switchTab()
          )
          .width(20%)
          .height(100%)

          Column() 
            Image(this.tab_03_icon)
              .width(100%)
              .height(50%)
              .flexShrink(0)
              .objectFit(ImageFit.Contain)
            Text($r(app.string.tab_03))
              .width(100%)
              .height(50%)
              .flexShrink(0)
              .fontColor(this.tab_03_color)
              .fontSize(15fp)
              .textAlign(TextAlign.Center)
          
          .onClick(() => 
            this.current_tab_index = 3
            this.switchTab()
          )
          .width(20%)
          .height(100%)

          Column() 
            Image(this.tab_04_icon)
              .width(100%)
              .height(50%)
              .flexShrink(0)
              .objectFit(ImageFit.Contain)
            Text($r(app.string.tab_04))
              .width(100%)
              .height(50%)
              .flexShrink(0)
              .fontColor(this.tab_04_color)
              .fontSize(15fp)
              .textAlign(TextAlign.Center)
          
          .onClick(() => 
            this.current_tab_index = 4
            this.switchTab()
          )
          .width(20%)
          .height(100%)

          Column() 
            Image(this.tab_05_icon)
              .width(100%)
              .height(50%)
              .flexShrink(0)
              .objectFit(ImageFit.Contain)
            Text($r(app.string.tab_05))
              .width(100%)
              .height(50%)
              .flexShrink(0)
              .fontColor(this.tab_05_color)
              .fontSize(15fp)
              .textAlign(TextAlign.Center)
          
          .onClick(() => 
            this.current_tab_index = 5
            this.switchTab()
          )
          .width(20%)
          .height(100%)
        
        .width(100%)
        .height(90vp)
        .align(Alignment.Center)
        .flexShrink(0)
        .backgroundColor(#ffdbc9c9)
        .margin( top: 5vp)
        .padding( top: 5vp, bottom: 5vp, left: 5vp, right: 5vp )

    
  
  .width(100%)
  .height(100%)
  .alignItems(HorizontalAlign.End)
  //设置个背景图片  
  .backgroundImage($r(app.media.community_notice), ImageRepeat.XY)

4).实现点击tab 切换的效果

定义当前操作的tab索引

//当前操作的tab
current_tab_index = 1

5).定义切换tab函数switchTab()

设置当前点击tab的选中效果,同时其它tab取消选中效果。该方法还可以继续优化。

//切换Tab
switchTab() 

  if (this.current_tab_index == 1) 
    if (this.tab_01_icon.id != initImageMap().get(tab_01_filled).id) 

      logger.getInstance(this).debug(`===========$JSON.stringify(this.tab_01_icon)`)
      logger.getInstance(this).debug(`===========$JSON.stringify(initImageMap().get(tab_01_filled))`)
      //当前选中
      this.tab_01_icon = initImageMap().get(tab_01_filled)
      this.tab_01_color = initImageMap().get(tab_filled_color)
      //重置其它
      this.tab_02_icon = initImageMap().get(tab_02)
      this.tab_02_color = initImageMap().get(tab_unfilled_color)

      this.tab_03_icon = initImageMap().get(tab_03)
      this.tab_03_color = initImageMap().get(tab_unfilled_color)

      this.tab_04_icon = initImageMap().get(tab_04)
      this.tab_04_color = initImageMap().get(tab_unfilled_color)

      this.tab_05_icon = initImageMap().get(tab_05)
      this.tab_05_color = initImageMap().get(tab_unfilled_color)
    
  
  if (this.current_tab_index == 2) 
    if (this.tab_02_icon.id != initImageMap().get(tab_02_filled).id) 

      logger.getInstance(this).debug(`===========$JSON.stringify(this.tab_02_icon)`)
      logger.getInstance(this).debug(`===========$JSON.stringify(initImageMap().get(tab_02_filled))`)
      //当前选中
      this.tab_02_icon = initImageMap().get(tab_02_filled)
      this.tab_02_color = initImageMap().get(tab_filled_color)
      //重置其它
      this.tab_01_icon = initImageMap().get(tab_01)
      this.tab_01_color = initImageMap().get(tab_unfilled_color)

      this.tab_03_icon = initImageMap().get(tab_03)
      this.tab_03_color = initImageMap().get(tab_unfilled_color)

      this.tab_04_icon = initImageMap().get(tab_04)
      this.tab_04_color = initImageMap().get(tab_unfilled_color)

      this.tab_05_icon = initImageMap().get(tab_05)
      this.tab_05_color = initImageMap().get(tab_unfilled_color)
    
  
  if (this.current_tab_index == 3) 
    if (this.tab_03_icon.id != initImageMap().get(tab_03_filled).id) 

      logger.getInstance(this).debug(`===========$JSON.stringify(this.tab_03_icon)`)
      logger.getInstance(this).debug(`===========$JSON.stringify(initImageMap().get(tab_03_filled))`)
      //当前选中
      this.tab_03_icon = initImageMap().get(tab_03_filled)
      this.tab_03_color = initImageMap().get(tab_filled_color)
      //重置其它
      this.tab_02_icon = initImageMap().get(tab_02)
      this.tab_02_color = initImageMap().get(tab_unfilled_color)

      this.tab_01_icon = initImageMap().get(tab_01)
      this.tab_01_color = initImageMap().get(tab_unfilled_color)

      this.tab_04_icon = initImageMap().get(tab_04)
      this.tab_04_color = initImageMap().get(tab_unfilled_color)

      this.tab_05_icon = initImageMap().get(tab_05)
      this.tab_05_color = initImageMap().get(tab_unfilled_color)
    
  
  if (this.current_tab_index == 4) 
    if (this.tab_04_icon.id != initImageMap().get(tab_04_filled).id) 

      logger.getInstance(this).debug(`===========$JSON.stringify(this.tab_04_icon)`)
      logger.getInstance(this).debug(`===========$JSON.stringify(initImageMap().get(tab_04_filled))`)
      //当前选中
      this.tab_04_icon = initImageMap().get(tab_04_filled)
      this.tab_04_color = initImageMap().get(tab_filled_color)
      //重置其它
      this.tab_02_icon = initImageMap().get(tab_02)
      this.tab_02_color = initImageMap().get(tab_unfilled_color)

      this.tab_03_icon = initImageMap().get(tab_03)
      this.tab_03_color = initImageMap().get(tab_unfilled_color)

      this.tab_01_icon = initImageMap().get(tab_01)
      this.tab_01_color = initImageMap().get(tab_unfilled_color)

      this.tab_05_icon = initImageMap().get(tab_05)
      this.tab_05_color = initImageMap().get(tab_unfilled_color)
    
  
  if (this.current_tab_index == 5) 
    if (this.tab_05_icon.id != initImageMap().get(tab_05_filled).id) 

      logger.getInstance(this).debug(`===========$JSON.stringify(this.tab_05_icon)`)
      logger.getInstance(this).debug(`===========$JSON.stringify(initImageMap().get(tab_05_filled))`)
      //当前选中
      this.tab_05_icon = initImageMap().get(tab_05_filled)
      this.tab_05_color = initImageMap().get(tab_filled_color)
      //重置其它
      this.tab_02_icon = initImageMap().get(tab_02)
      this.tab_02_color = initImageMap().get(tab_unfilled_color)

      this.tab_03_icon = initImageMap().get(tab_03)
      this.tab_03_color = initImageMap().get(tab_unfilled_color)

      this.tab_04_icon = initImageMap().get(tab_04)
      this.tab_04_color = initImageMap().get(tab_unfilled_color)

      this.tab_01_icon = initImageMap().get(tab_01)
      this.tab_01_color = initImageMap().get(tab_unfilled_color)
    
  

6).在点击tab时设置当前操作的tab索引并调用switchTab() 函数

      .onClick(() => 
        this.current_tab_index = 5
        this.switchTab()
      )

3.3实现一个顶部工具栏

因为我们想实现一个,向上滑动时,隐藏middle栏的内容,在top栏显示缩减版的middle信息。

所以定义一个show_top_title 变量,用于控制top title的显隐,定义一个show_mid_title状态变量控制middle title的显隐。

//控制组件显隐
@State show_top_title: boolean = false
@State show_mid_title: boolean = true

top栏包含一个文本(初始时不显示),一个搜索按钮,一个添加按钮,我们希望top栏的操作按钮能靠右边,所以注意设置

.alignItems(HorizontalAlign.End)

//top栏
Row() 
  Column() 
    if (this.show_top_title) 
      Text(步二神探的家)
        .height(100%)
        .width(100%)
        .fontSize(24)
        .fontWeight(FontWeight.Bolder)
        .fontWeight(#CCFFF)
    
  
  .width(60%)
  .height(100%)
  .padding( left: 10 )

  Column() 
    Image($r(app.media.ic_public_search))
      .width(50vp)
      .height(100%)
      .borderRadius(30)
      .margin( right: 10 )
      .objectFit(ImageFit.ScaleDown)
    //.backgroundColor(#bbdd11)
  
  .width(20%)
  .height(100%)
  //.backgroundColor(#bbdd11)
  .alignItems(HorizontalAlign.End)
  .onClick(() => 
    logger.getInstance(this).debug(`you click 

以上是关于#夏日挑战赛# 用OpenHarmony eTS 实现一个Huawei app标准布局的主要内容,如果未能解决你的问题,请参考以下文章

#夏日挑战赛# OpenHarmony - ArkUI(TS)开发翻页时钟

#夏日挑战赛# OpenHarmony基于JS实现的贪吃蛇

#夏日挑战赛#FFH分布式数据服务简单实现(OpenHarmony JS UI)

#夏日挑战赛# HarmonyOS 实现一个手绘板

#夏日挑战赛#OHOS构建自定义服务实战

#夏日挑战赛#ELT.ZIP啃论文俱乐部——学术科研方法论沉淀辑