美文网首页
鸿蒙应用开发-组件样式

鸿蒙应用开发-组件样式

作者: 程序员阿兵 | 来源:发表于2024-02-05 09:12 被阅读0次

    一、鸿蒙应用开发-初体验
    二、鸿蒙应用开发-基础组件
    三、鸿蒙应用开发-组件样式
    四、鸿蒙应用开发-组件构建函数
    五、鸿蒙应用开发-组件组件状态共享
    六、鸿蒙应用开发-应用状态存储

    目录

    样式处理

    1. 样式-语法(链式&枚举)

    ArkTS以声明方式组合和扩展组件来描述应用程序的UI 同时还提供了基本的属性、事件和子组件配置方法,帮助开发者实现应用交互逻辑。

    1.样式属性

    • 属性方法以 . 链式调用的方式配置系统组件的样式和其他属性,建议每个属性方法单独写一行。
    @Entry
    @Component
    struct Index {
      build() {
        Text('演示')
          .backgroundColor('red')
          .fontSize(50)
          .width('100%')
          .height(100)
      }
    }
    

    2.枚举值

    • 对于系统组件,ArkUI还为其属性预定义了一些枚举类型。文档链接
    @Entry
    @Component
    struct Index {
      build() {
        Text('演示')
         .fontSize(50)
          .width('100%')
          .height(100)
          .backgroundColor(Color.Blue)
          .textAlign(TextAlign.Center)
          .fontColor(Color.White)
      }
    }
    
    • 样式相关属性通过链式函数的方式进行设置
    • 如果类型是枚举的,通过枚举传入对应的值
    2. 样式-单位 vp 和适配
    1. vp 是什么?virtual pixel
    • 屏幕密度相关像素,根据屏幕像素密度转换为屏幕物理像素,当数值不带单位时,默认单位 vp;在实际宽度为1440物理像素的屏幕上,1vp 约等于 3px(物理像素)
      image.png
    • 上图的意思是,使用这个单位在不同屏幕物理分辨率的实际尺寸一致(A设备1英寸,B设备1英寸)。

    2.之前 vwremrpx 相对于屏幕宽度的单位,可以实现等比例适配,vp 可以吗?

    import promptAction from '@ohos.promptAction'
    
    @Entry
    @Component
    struct Index {
      build() {
        Text('演示')
          .width('100%')
          .backgroundColor('red')
          .onAreaChange((oldArea, newArea) => {
            promptAction.showToast({
              // 1. onAreaChange改变尺寸后会触发
              // 2. newArea为现在元素尺寸
              message: newArea.width.toString()
            })
          })
      }
    }
    

    我们发现:不同的设备屏幕的宽度 vp 是不一致的,那怎么适配呢?

    1. 根据官方的文档,结合自己的理解,采用:伸缩布局,网格系统,栅格系统进行布局适配。

    伸缩 layoutWeight(flex: number)占剩余空间多少份,可以理解成CSS的 flex: 1

    @Entry
    @Component
    struct Index {
      build() {
        Row(){
          Text('left')
            .layoutWeight(1)
            .backgroundColor('red')
          Text('right')
            .layoutWeight(2)
            .backgroundColor('green')
        }
        .width('100%')
      }
    }
    

    等比例,设置元素宽高比 aspectRatio(ratio: number)

    @Entry
    @Component
    struct Index {
      build() {
        Text('left')
          .width('50%')
            // 宽高比例
          .aspectRatio(1)
          .backgroundColor('red')
      }
    }
    
    • vp 是鸿蒙默认单位,和屏幕像素有关,最终表现视觉大小在任何设备一致
    • 鸿蒙一般以伸缩 layoutWeight、网格、栅格进行布局适配,如要等比例缩放可以设置高宽比 aspectRatio
      📕📕📕 案例→实现知乎评论回复-评论区域
    1.jpeg

    设计稿一般是1080px:(这里没有设计稿,提供了一些尺寸)

    • Nav
      • 左侧返回按钮24vp高宽背景颜色#f5f5f5,图标12vp尺寸颜色#848484
      • 标题18vp
    • Comment
      • 头像尺寸32vp高宽,右侧间距10vp
      • 标题15vp,颜色默认
      • 内容16vp,颜色#565656
      • 底部12vp,颜色#c3c4c5
    @Entry
    @Component
    struct Index {
      build() {
        Column(){
          // 导航
          Row(){
            Row(){
              Image($r('app.media.ic_public_arrow_left'))
                .width(16)
                .aspectRatio(1)
                // svg 图标可以使用填充颜色
                // .fillColor('red')
            }
            .width(24)
            .aspectRatio(1)
            .backgroundColor('#f5f5f5')
            .borderRadius(12)
            .justifyContent(FlexAlign.Center)
            .margin({ left: 16 })
    
            Text('评论回复')
              .layoutWeight(1)
              .textAlign(TextAlign.Center)
              .padding({ right: 40 })
          }
          .height(40)
          .border({ width: { bottom: 0.5 }, color: '#e4e4e4' })
          // 评论
          Row(){
            Image($r('app.media.avatar'))
              .width(32)
              .aspectRatio(1)
              .borderRadius(16)
            Column({ space: 5 }){
              Text('周杰伦')
                .width('100%')
                .fontWeight(FontWeight.Bold)
                .fontSize(15)
              Text('大理石能雕刻出肌肉和皮肤的质感,那个年代的工匠好牛啊')
                .width('100%')
              Row(){
                Text('10-21 · IP属地北京')
                  .fontSize(12)
                  .fontColor('#c3c4c5')
                Row({ space: 4 }){
                  Image($r('app.media.ic_public_heart'))
                    .width(14)
                    .aspectRatio(1)
                    .fillColor('#c3c4c5')
                  Text('100')
                    .fontSize(12)
                    .fontColor('#c3c4c5')
                }
              }
              .width('100%')
              .justifyContent(FlexAlign.SpaceBetween)
            }
            .layoutWeight(1)
            .padding({ left: 10 })
          }
          .padding(15)
          .alignItems(VerticalAlign.Top)
        }
      }
    }
    
    • 华为官方图标下载 链接

    样式-@Styles 复用

    在开发过程中会出现大量代码在进行重复样式设置,@Styles 可以帮我们进行样式复用

    • 当前 @Styles 仅支持 通用属性通用事件
    • 支持 全局 定义和 组件内 定义,同时存在组件内覆盖全局生效。
    // 全局
    @Styles 
    function functionName() { ... }
    
    @Entry
    @Component
    sturt Index{
      // 组件内
      @Styles 
      functionName() { ... }
    
      build() {
        Text('Text')
          .functionName()
      }
    }
    

    案例:文字和按钮相同背景,点击+1

    2.jpeg
    • 全局
    @Styles function sameStyle() {
      .backgroundColor(Color.Green)
      .onClick(() => {
        this.count++
      })
    }
    
    @Entry
    @Component
    struct Index {
      @State
      count: number = 10
    
      build() {
        Column() {
          Text(this.count.toString())
            .width(100)
            .height(50)
            .margin({ bottom: 10 })
            .textAlign(TextAlign.Center)
            .sameStyle()
    
          Button('+1')
            .sameStyle()
        }
        .height('100%')
        .width('100%')
        .justifyContent(FlexAlign.Center)
      }
    }
    
    • 组件内
    @Entry
    @Component
    struct Index {
      @State
      count: number = 10
    
      // 不需要 `function` 关键字,覆盖全局
      @Styles
      sameStyle (){
        .backgroundColor(Color.Pink)
        .onClick(() => {
          this.count += 10
        })
      }
    
      build() {
        Column() {
          Text(this.count.toString())
            .width(100)
            .height(50)
            .margin({ bottom: 10 })
            .textAlign(TextAlign.Center)
            .sameStyle()
    
          Button('+1')
            .sameStyle()
        }
        .height('100%')
        .width('100%')
        .justifyContent(FlexAlign.Center)
      }
    }
    

    📕📕📕 练习案例-登录表单-样式优化


    4.jpeg
    import promptAction from '@ohos.promptAction'
    @Entry
    @Component
    struct Index {
    
      @State
      mobile: string = ''
      @State
      code: string = ''
    
    
      @Styles
      inputStyle () {
        .border({ width: 1, color: Color.Gray })
        .layoutWeight(1)
        .margin({ left: 10, bottom: 10, top: 10 })
        .backgroundColor(Color.White)
      }
    
      build() {
        Column(){
          Row(){
            Text('手机号')
            TextInput({ text: this.mobile })
              .inputStyle()
              .onChange((value)=>this.mobile = value)
          }
          Row(){
            Text('验证码')
            TextInput({ text: this.code })
              .inputStyle()
              .onChange((value)=>this.code = value)
          }
          Row({ space: 15 }){
            Button('重置')
              .backgroundColor('#ccc')
              .onClick(()=>{
                this.mobile = ''
                this.code = ''
              })
            Button('登录')
              .onClick(()=>{
                if (this.mobile && this.code) {
                  promptAction.showToast({ message: `${this.mobile} 登录成功` })
                } else {
                  promptAction.showToast({ message: `请输入手机号或验证码` })
                }
              })
          }
        }
        .padding({ left: 15, right: 15 })
      }
    }
    

    样式-@Extends 复用

    @Extend 用于扩展原生组件样式,通过传参提供更灵活的样式复用

    • 使用 @Extend 装饰器修饰的函数只能是 全局
    • 函数可以进行 传参,如果参数是状态变量,状态更新后会刷新UI
    • 且参数可以是一个函数,实现复用事件且可处理不同逻辑
    // 全局  原生组件                     参数
    //  ↓     ↓                          ↓ 
    @Extend(Text) function functionName(w: number) { 
      .width(w)
    }
    

    需求:把 Text 改成按钮样式,且绑定 click 事件执行不同逻辑

    WechatIMG25.jpeg
    import promptAction from '@ohos.promptAction'
    @Extend(Text) function myClick(color: string, cb: () => void) {
      .backgroundColor(color)
      .width(100)
      .height(50)
      .textAlign(TextAlign.Center)
      .borderRadius(25)
      .onClick(() => cb())
    }
    
    @Entry
    @Component
    struct Other {
      @State
      color: string = '#ccc'
    
      build() {
        Column({ space: 20 }) {
          Text('Text1')
            .myClick(this.color, () => {
              this.color = '#069'
            })
          Text('Text2')
            .myClick('green', () => {
              promptAction.showToast({ message: '做其他事~' })
            })
        }
        .width('100%')
        .height('100%')
        .justifyContent(FlexAlign.Center)
      }
    }
    

    样式-多态

    stateStyles 是属性方法,可以根据UI内部状态来设置样式,类似于 css 伪类,但语法不同。ArkUI 提供以下四种状态:

    • focused:获焦态。

    • normal:正常态。

    • pressed:按压态。

    • disabled:不可用态。

    import promptAction from '@ohos.promptAction'
    
    // 胶囊按钮
    @Extend(Text)
    function capsule(){
      .height(40)
      .borderRadius(20)
      .backgroundColor(Color.Gray)
      .padding({ left: 15, right: 15 })
      .margin({ bottom: 15 })
    }
    
    @Entry
    @Component
    struct Index {
      @State
      disabled: boolean = false
      @State
      focused: boolean = false
    
      build() {
        Column() {
    
          // Button TextInput 默认开启获取焦点,页面中默认第一个这样的元素获取焦点
          // Button 比较多限制,一个是默认开启获取焦点能看,二是禁用状态下样式无法修改
          // Button('Button').focusable(false)
    
          Text('toggle disabled:' + this.disabled)
            .capsule()
            .onClick(()=>{
              this.disabled = !this.disabled
            })
          Text('toggle focused:' + this.focused)
            .capsule()
            .onClick(()=>{
              this.focused = !this.focused
            })
          Text('clickMe')
            .capsule()
            .enabled(!this.disabled)
            .focusable(this.focused)
            .onClick(() => {
              promptAction.showToast({ message: 'click' })
            })
            .fontColor('#fff')
            .stateStyles({
              normal: {
                .backgroundColor(Color.Blue)
              },
              focused: {
                .backgroundColor(Color.Red)
              },
              disabled: {
                .backgroundColor(Color.Black)
              },
              pressed: {
                .backgroundColor(Color.Orange)
              }
            })
        }
      }
    }
    
    • 使用比较多的应该是 norma
      pressed 结合下的按压效果
    • enabled(true|false) 开启|禁用focusable(true|false) 开启获取焦点能力|关闭

    注意:

    • 页面初始化的时候,默认第一个能获取焦点的元素,会自动获取焦点

    相关文章

      网友评论

          本文标题:鸿蒙应用开发-组件样式

          本文链接:https://www.haomeiwen.com/subject/jqsfadtx.html