【鸿蒙开发】HarmonyOS Next UI开发技巧

前言

不久前华为已经宣布全新HarmonyOS NEXT 鸿蒙星河版将在今年秋天正式和消费者见面,并已经面向开发者开放申请。鸿蒙星河版会有更智能、更极致的原生体验,也标志着鸿蒙迈向其发展的第二阶段。因此,对于鸿蒙生态建设而言,2024年可谓至关重要,而生态建设的前提,就是要有足够的开发人才。与之对应的,今年春招市场上与鸿蒙相关岗位和人才旺盛的热度,一方面反应了鸿蒙生态的逐渐壮大,另一方面也让人们对鸿蒙下一阶段的发展更具信心。

这里跟大家讲一讲鸿蒙UI的开发技巧

1、TextInput 输入框获取焦点(弹起键盘)

让TextInput再次获取焦点,并弹出键盘,可调用下面方法,参数为TextInput的id/key

focusControl.requestFocus("_TextInput") 

注意:这个方法虽然可以让TextInput获取到焦点,但经测试,不一定能保证键盘弹出。如果我们手动调用过隐藏键盘的方法,那么下次即使调用获取焦点,键盘也不会弹出。

为保险起见,这里需要再手动调用一下展示键盘的方法,确保键盘弹起。

手动调用弹起/收起键盘,callback也会返回有失败的情况:
{“code”:12800009,“message”:“input method not attached.”}

如上面所说,经测试,和我们手动调用和系统自动收起有关,手动调用的时候注意一下。

2、弹出对话框

CustomDialogController

构建一个CustomDialogController即可:

  private dialogController: CustomDialogController = new CustomDialogController({
    builder: Dialog(), // 自定义布局视图
    alignment: DialogAlignment.Center, // 显示位置
    customStyle: true
  })
  
  dialogController.open() //打开对话框

显示对话框,调用CustomDialogController的open()方法

Dialog内部视图

和普通创建视图组件无异,就是多了一个装饰器:@CustomDialog

@Component
@CustomDialog
export default struct CustomDialog {
  controller: CustomDialogController
  ...
  
  // 内部关闭对话框:
  this.controller.close()
}

内部需要关闭对话框,调用CustomDialogController的close()方法即可

3、RelativeContainer 如何实现宽/高自适应

如图所示,想实现视图中上半部分的布局样式。很显然,用RelativeContainer这个布局控件很合适。
在这里插入图片描述

然后,让第一个组件顶部与RelativeContainer的顶部对齐,下面密码视图与RelativeContainer的底部对齐。
对于开发过android的相对布局,按我们理解的来说,RelativeContainer的高度,此时就应该按最后贴齐方式,计算其内部组件的高度为RelativeContainer的高度。但实际效果却是如下图所示:
在这里插入图片描述

直接按类似高度 100% 实现了。

如何让RelativeContainer能够自适应其高度

这里就需要将宽/高设置为auto,同时,还要注意锚点的设置,不能有同方向的与__container__的锚定设置:

●宽度自适应:水平方向不能有类似:left: { anchor: ‘container’, align: HorizontalAlign.Start }
●高度自适应:垂直方向不能有类似:top: { anchor: ‘container’, align: VerticalAlign.Top }
●宽/高度必须设置为auto

所以,最后布局的代码改写这样,就可以实现高度自适应了

    RelativeContainer() {
        Text("更多登录方式")
          ...
          .alignRules({
            // top: { anchor: '__container__', align: VerticalAlign.Top }, // 不能有垂直方向上的与RelativeContainer的锚定
            left: { anchor: '__container__', align: HorizontalAlign.Start },
          })
          .id("title")
        Column() {
            ...
        }
        .alignRules({
          top: { anchor: 'title', align: VerticalAlign.Bottom },
          left: { anchor: '__container__', align: HorizontalAlign.Start },
          // bottom: {anchor: '__container__', align: VerticalAlign.Bottom} // 不能有垂直方向上的与RelativeContainer的锚定
        })
        .id("pwd")
      }
      .height('auto')  // 高度一定要设置为auto,不可以不写!

4、List与AlphabetIndexer组合,实现索引联动效果

这个场景最经典的用法就是国家区号与索引值互相联动,如下图所示
在这里插入图片描述

这个视图效果由两个空间组合完成,List与AlphabetIndexer。这里有几个地方需要注意:

1.两个List的嵌套

在左边列表视图中,索引和索引内的内容,是一个整体的List,而索引内容又是一个List。所以这里是两个List嵌套完成的布局样式。所以,要用到ListItemGroup和ListItem:
在这里插入图片描述

2.List嵌套都要用LazyForEach

之前论坛里面有人用普通的forEach代替,但出现了内容错乱的问题。所以,这样都用LazyForEach就不会有这个问题。配合ListItemGroup和ListItem的写法如下:

List() {
    LazyForEach ...
        ListItemGroup ...
            LazyForEach ...
                ListItem() 
        }   
    }
}

3.索引列表AlphabetIndexer的实现

直接用官方的API就可以,注意的是:

●构造方法入参的index,传入全局索引变量,并且增加上状态装饰符如@state,以实现联动效果。List的滚动也要对应实现onScollIndex的监听,变更全局索引变量。

@State currentIndex: number = 0
List({ scroller: this.listScroller }) {
    ...
    .onScrollIndex((startIndex: number) => {
        this.currentIndex = startIndex
    })

●实现onSelected的时候,需要将index设置给List的listScroller的scrollToIndex方法,这样当选择右侧索引的时候,就可以让列表也滚动到对应的位置。这个位置对应的就是第一层ListItemGroup的位置。

AlphabetIndexer({ arrayValue: this.dataSource, selected: this.currentIndex })
    .color(Color.Gray)
    .selectedColor(0xFFFFFF)// 选中项文本颜色
    .selectedBackgroundColor(Color.Blue)// 选中项背景颜色
    .selectedFont({ size: 11, weight: FontWeight.Normal })// 选中项字体样式
    .itemSize(32)
    .width(32)
    .usingPopup(false)// 是否显示弹出框
    .onSelect((index: number) => {
        this.listScroller.scrollToIndex(index)
    })

4.实现粘性标题效果

这一步就很简单了,一句api搞定

List()
  .sticky(StickyStyle.Header)

这样就实现了实现左右联动效果,还配合上了粘性标题。

5、底部弹框实现

上面介绍过如何构建并使用 CustomDialog,虽然可以设置dialog显示的位置,比如设置让其在底部展示,但并不能实现从底部滑出那种显示效果。比如上面这个选择手机的国家地区时,希望是从底部弹出的效果:
在这里插入图片描述

如果要实现,就得使用普通的view配合动画来实现,主要用到下面这两个关键方法:

●animateTo
●translate

具体做法如下:

1.先为视图设置垂直方向上的translateY

@State translateY: string = "100%";

build(){
  Column()
    ...
    .translate({y: this.translateY})
}

2.然后重写aboutToAppear方法

aboutToAppear(): void {
    animateTo({
        duration: 200, curve: Curve.EaseInOut, onFinish: () => {

        }
    }, () => {
    this.translateY = "0%"
    this.backgroundOpacity = 0.3 // 可以多增加一个背景变深的效果
    })
}

3.当关闭的时候,统一调用关闭函数处理

close() {
    animateTo({
        duration: 200, curve: Curve.EaseInOut, onFinish: () => {
        }
    }, () => {
        this.translateY = "100%"
        this.backgroundOpacity = 0
    })
}    

6、Navigation内部布局的坑

如果你想将Navigation作为第一个视图显示,也不是不可以,但要注意这个坑:
从视图可以看出,本来黄色部分应紧贴在底部,但却出现了空出一块:
在这里插入图片描述

如果想最后黄色贴底,就需要设置.hideTitleBar(true)

在这里插入图片描述

写在最后

总的来说,华为鸿蒙不再兼容安卓,对中年程序员来说是一个挑战,也是一个机会。随着鸿蒙的不断发展以及国家的大力支持,未来鸿蒙职位肯定会迎来一个大的爆发,只有积极应对变化,不断学习和提升自己,我们才能在这个变革的时代中立于不败之地。在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值