鸿蒙应用开发-组件样式

样式处理
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(物理像素)

  • 上图的意思是,使用这个单位在不同屏幕物理分辨率的实际尺寸一致(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
    📕📕📕 案例→实现知乎评论回复-评论区域

设计稿一般是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

  • 全局
@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)
  }
}

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

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 事件执行不同逻辑

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) 开启获取焦点能力|关闭
注意:
  • 页面初始化的时候,默认第一个能获取焦点的元素,会自动获取焦点

最后资料分享

如果你还没有掌握鸿蒙,现在想要在最短的时间吃透它,大家可以参考一下这份鸿蒙学习路线图以及《鸿蒙(HarmonyOS)开发学习笔记》,内容包含ArkTS、ArkUI、Web开发、应用模型、资源分类…等知识点。

【扫描下方二维码即可免费领取!!】

在这里插入图片描述

快速入门

  • 开发准备
  • 构建第一个ArkTS应用(Stage模型)
  • 构建第一个ArkTS应用(FA模型)
  • 构建第一个JS应用(FA模型)
    在这里插入图片描述

开发基础知识

  • 应用程序包基础知识
  • 应用配置文件(Stage模型)
  • 应用配置文件概述(FA模型)
    在这里插入图片描述

资源分类与访问

  • 资源分类与访问
  • 创建资源目录和资源文件
  • 资源访问
    在这里插入图片描述

学习ArkTs语言

  • 初识ArkTS语言
  • 基本语法
  • 状态管理
  • 其他状态管理
  • 渲染控制
    在这里插入图片描述

基于ArkTS声明式开发范式

  • UI开发(ArkTS声明式开发范式)概述
  • 开发布局
  • 添加组件
  • 显示图片
  • 使用动画
  • 支持交互事件
  • 性能提升的推荐方法

在这里插入图片描述

兼容JS的类Web开发范式

  • 概述
  • 框架说明
  • 构建用户界面
  • 常见组件开发指导
  • 动效开发指导
  • 自定义组件
    在这里插入图片描述

Web组件

  • 概述
  • 设置基本属性和事件
  • 并发
  • 窗口管理
  • WebGL
  • 媒体
  • 安全
  • 网络与连接
  • 电话服务
  • 数据管理

  • 在这里插入图片描述

应用模型

  • 概述
  • Stage模型开发指导
  • FA模型开发指导
    在这里插入图片描述
有需要完整鸿蒙学习资料的朋友,扫描下方二维码即可免费领取!!!
  • 23
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值