欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 教育 > 高考 > HarmonyOS第四章:样式操作及渲染页面

HarmonyOS第四章:样式操作及渲染页面

2024/10/24 10:26:51 来源:https://blog.csdn.net/to_the_Future/article/details/140866792  浏览:    关键词:HarmonyOS第四章:样式操作及渲染页面

🎉 博客主页:【剑九_六千里-CSDN博客】【剑九_六千里-掘金社区】
🎨 上一篇文章:【HarmonyOS第三章:初识ArkTs/ArkUI,常用组件二】
🎠 系列专栏:【HarmonyOS系列】
💖 感谢大家点赞👍收藏⭐评论✍

在这里插入图片描述

在这里插入图片描述
引言
ArkTS,作为ArkUI框架的一个重要组成部分,提供了一套强大且灵活的工具集,旨在帮助开发者构建高性能且美观的应用程序。无论是新手还是经验丰富的开发者,掌握ArkTS中的样式操作和渲染技术都是必不可少的技能。本文将深入探讨如何利用ArkTS中的样式设置、适配单位、样式复用、多态样式以及条件渲染和循环渲染等功能,帮助您更高效地构建美观、响应迅速的应用界面。让我们一同探索这些强大的工具和技术,开启您的ArkTS之旅吧!

文章目录

  • 1. 样式操作
    • 1.1. 样式语法
      • 1.1.1. 样式属性
      • 1.1.2. 枚举值
    • 1.2. 像素单位
      • 1.2.1. `"vp"` 是指 "虚拟像素"(virtual pixel)
      • 1.2.2. 像素单位转换
      • 1.2.3. 也可以采用伸缩布局(layoutWeight)、网格系统和栅格系统来进行布局适配。
    • 1.3. 复用 @Styles
    • 1.4. 复用 @Extend
    • 1.5. 多态样式
  • 2. 渲染页面
    • 2.1. 条件渲染 if/else
    • 2.2. 循环渲染 ForEach

1. 样式操作

1.1. 样式语法

ArkTS采用声明式方法来组合和扩展组件,从而构建应用程序的用户界面。此外,它还提供了一系列基础属性、事件处理能力和子组件的配置选项,以支持开发者设计和实现应用程序的交互逻辑。

1.1.1. 样式属性

  • 属性方法可以通过点(.)进行链式调用来配置系统组件的样式和其他属性。
  • 为了提高代码的可读性,建议将每个属性方法分别写在单独的一行上。
@Entry
@Component
struct StylePage {build() {Row() {Text("测试链式调用").width(100).height(100).backgroundColor("#f40")}.width("100%").height("100%").justifyContent(FlexAlign.Center)}
}

测试:

在这里插入图片描述

1.1.2. 枚举值

ArkUI为系统组件的属性提供了预定义的枚举类型,以简化配置过程。

@Entry
@Component
struct StylePage {build() {Row() {Text("测试样式枚举值").width(200).height(100).backgroundColor(Color.Gray).textAlign(TextAlign.Center).fontWeight(FontWeight.Bold).fontColor(Color.Blue)}.width("100%").height("100%").justifyContent(FlexAlign.Center)}
}

测试:

在这里插入图片描述

注意:

  • 样式相关的属性应该使用链式函数进行设置。
  • 当属性类型为枚举时,应该通过传入相应枚举值来设定。

1.2. 像素单位

Harmony为开发者提供4种像素单位,框架采用 vp 为基准数据单位。

名称描述
px屏幕物理像素单位。
vp屏幕密度相关像素,根据屏幕像素密度转换为屏幕物理像素,当数值不带单位时,默认单位vp。在实际宽度为1440物理像素的屏幕上,1vp约等于3px。
fp字体像素,与vp类似适用屏幕密度变化,随系统字体大小设置变化。
lpx视窗逻辑像素单位,lpx单位为实际屏幕宽度与逻辑宽度(通过designWidth配置)的比值,designWidth默认值为720。当designWidth为720时,在实际宽度为1440物理像素的屏幕上,1lpx为2px大小。

1.2.1. "vp" 是指 “虚拟像素”(virtual pixel)

在设置样式时,如果使用的是 px 作为单位,它直接对应于物理像素,即屏幕的分辨率。由于不同手机的屏幕分辨率密度各异,用 px 表示的值难以适应所有屏幕密度,因此使用 vp(虚拟像素)作为单位可以自动根据手机的屏幕密度进行适配。这样,vp 提供了一种灵活的方法来确保不同屏幕密度下的显示效果保持一致。

例如,设计图如果是按照1080px宽度设计的,那么在编写样式时,可以将这个尺寸换算成360vp来适配不同的屏幕。

1.2.2. 像素单位转换

其他单位与px单位互相转换的方法。

接口描述
vp2px(value : number) : number将vp单位的数值转换为以px为单位的数值。从API version 9开始,该接口支持在ArkTS卡片中使用。
px2vp(value : number) : number将px单位的数值转换为以vp为单位的数值。从API version 9开始,该接口支持在ArkTS卡片中使用。
fp2px(value : number) : number将fp单位的数值转换为以px为单位的数值。从API version 9开始,该接口支持在ArkTS卡片中使用。
px2fp(value : number) : number将px单位的数值转换为以fp为单位的数值。从API version 9开始,该接口支持在ArkTS卡片中使用。
lpx2px(value : number) : number将lpx单位的数值转换为以px为单位的数值。从API version 9开始,该接口支持在ArkTS卡片中使用。
px2lpx(value : number) : number将px单位的数值转换为以lpx为单位的数值。从API version 9开始,该接口支持在ArkTS卡片中使用。

示例:

@Entry
@Component
struct VPPage {@State pageSize: string = "";build() {Column() {// 预览器宽度:360vpText(`屏幕宽度是${this.pageSize}vp`)// vp和px之间的转换比例是1:3Text(`1080px可以转换成${px2vp(1080)}vp`) // 将px转换成vpText(`360vp可以转换成${vp2px(360)}px`) // 将vp转换成px}.width('100%').height('100%').onAreaChange((oldValue, newValue) => {// 视口发生变化时触发this.pageSize = newValue.width.toString();})}
}

测试:

在这里插入图片描述

1.2.3. 也可以采用伸缩布局(layoutWeight)、网格系统和栅格系统来进行布局适配。

在伸缩布局中,layoutWeight(flex: number)可以用来指定组件占据剩余空间的比例,类似于CSS中的 flex: 1 属性。这意味着组件可以根据指定的权重来分配剩余空间,以实现灵活的布局。

@Entry
@Component
struct LayoutWeight {build() {Row() {Text('left').width(100).height(100).backgroundColor(Color.Pink)Text('right').width(100).height(100).backgroundColor(Color.Red).layoutWeight(1)}.width('100%').height(100)}
}

在这里插入图片描述

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

@Entry
@Component
struct AspectRatio {build() {Text('测试').width(200).backgroundColor(Color.Blue).aspectRatio(2) // 宽高比}
}

在这里插入图片描述

1.3. 复用 @Styles

在开发过程中,我们经常需要在大量的代码中进行重复的样式设置。@Styles 可以帮助我们实现样式的复用,从而减少重复的代码。

  • 当前 @Styles 仅支持 通用属性 和 通用事件。
  • 它支持在全局范围和组件内部进行样式的定义,并且允许组件内的样式覆盖全局样式以实现个性化效果。

按照之前的写法,我们会写出如下的代码:

// 全局
@Entry
@Component
struct Index {build() {Row() {Column() {Text('1')}.width(100).height(100).backgroundColor(Color.Brown)Column() {Text('2')}.width(100).height(100).backgroundColor(Color.Pink)Column() {Text('3')}.width(100).height(100).backgroundColor(Color.Gray)}.height('100%').width('100%')}
}

在这里插入图片描述

可以看到这其中有些样式代码是重复的,因此可以将上面的代码进行改造:


@Entry
@Component
struct Index {@Styles commonColumnStyle() {.width(100).height(100).onClick(() => {AlertDialog.show({message: '我被点击了~~~~',alignment: DialogAlignment.Top})})}build() {Row() {Column() {Text('1')}.commonColumnStyle().backgroundColor(Color.Brown)Column() {Text('2')}.commonColumnStyle().backgroundColor(Color.Pink)Column() {Text('3')}.commonColumnStyle().backgroundColor(Color.Gray)}.height('100%').width('100%')}
}

代码的复用性更强,逻辑更清晰。

在这里插入图片描述

1.4. 复用 @Extend

@Extend 装饰器用于扩展原生组件的样式,通过传递参数来提供更灵活的样式复用功能。

  • 使用 @Extend 修饰的函数必须是全局函数。
  • 这些函数可以接受参数,如果参数是状态变量,当状态更新时,UI将被刷新。
  • 参数还可以是函数,从而实现事件的复用,并能够处理不同的逻辑。
// 全局  原生组件                     参数
//  ↓     ↓                          ↓ 
@Extend(Text) function functionName(w: number) { .width(w)
}

需求:点击 click 事件执行不同逻辑:

import promptAction from '@ohos.promptAction'@Extend(Text) function commonTextStyle(size:number, color:string, width: number, height: number, cb:()=>void){.fontSize(size).fontColor(color).width(width).height(height).backgroundColor(Color.Red).onClick(()=>{cb()})
}@Entry
@Component
struct Index {build() {Column(){Text("元素1").commonTextStyle(30, "#fff",100, 100, ()=>{promptAction.showToast({ message: 'hello' })})Text("元素2").commonTextStyle(40, "#ccc", 200, 200, ()=>{promptAction.showToast({ message: 'world' })})}.width("100%").height("100%")}
}

在这里插入图片描述

1.5. 多态样式

stateStyles() 是一个属性方法,它可以根据组件内部状态的不同,快速设置不同的样式。这种功能类似于CSS中的伪类选择器,但在语法上有所不同。在ArkUI中,您可以使用stateStyles 来定义四种不同的状态样式,分别是:

  • focused:获得焦点的状态。
  • normal:正常状态。
  • pressed:按压状态。
  • disabled:不可用状态。

通过这些状态样式的定义,您可以根据组件的不同状态来动态调整样式,以实现更灵活的界面效果。

@Entry
@Component
struct Index {@State disabled: boolean = falsebuild() {Column() {Text('toggle disabled:' + this.disabled).height(100).fontSize(30).backgroundColor(Color.Grey).onClick(()=>{this.disabled = !this.disabled})Button("普通按钮").stateStyles({// 正常状态normal:{.backgroundColor(Color.Blue)},// 按压状态pressed:{.backgroundColor(Color.Red)}})TextInput({placeholder:"请输入用户名"}).stateStyles({// 正常状态normal:{.backgroundColor(Color.Pink)},// 获得焦点的状态focused:{.backgroundColor(Color.Red)}})Button("禁用按钮").enabled(this.disabled).stateStyles({// 正常状态normal:{.backgroundColor(Color.Red)},// 禁用状态disabled:{.backgroundColor(Color.Black)}})}}
}

在这里插入图片描述

注意:

  • 在实际使用中,最常见的情况是使用 normalpressed 样式结合来实现按压效果。
  • 使用 enabled(true|false) 可以控制组件的启用或禁用状态,而 focusable(true|false) 可以控制组件是否具备获取焦点的能力。
  • 请注意,页面初始化时,默认情况下第一个具备获取焦点能力的组件会自动获得焦点

2. 渲染页面

2.1. 条件渲染 if/else

条件渲染是一种根据应用的不同状态使用 ifelseelse if 来渲染相应状态下的UI内容的方法。

  • 条件渲染是根据状态数据进行判断,以展示不同的UI
  • 在条件渲染中,组件会根据条件的变化而销毁和创建,因此组件的状态不会被保留。

使用 if else 实现 下拉列表选择 效果:

interface ISelectData {value: string
}
@Entry
@Component
struct Index {@State SelectData: ISelectData[] = [{ value: "霍建华" },{ value: "周深" },{ value: "杨丽萍" }]@State selected: number = -1build() {Column() {Select(this.SelectData).selected(0).value("请选择").onSelect((index) => {this.selected = index})if(this.selected === 0) {Text("演员")} else if(this.selected === 1) {Text("歌手")} else if(this.selected === 2) {Text("舞蹈家")} else {Text("普通人")}}.height("100%").width("100%")}
}

测试:

在这里插入图片描述

控制元素高宽:

Text("1111").width(this.isOn ? 100 : 0).height(this.isOn ? 100 : 0).borderRadius(8)

控制visibility属性- Hidden(占空间)和 None(不占空间)两种隐藏属性:

@Entry
@Component
struct APage {@State flag:boolean=truebuild() {Column() {Text("1111").visibility(this.flag?Visibility.Visible:Visibility.Hidden).borderRadius(8)Text("222")}}
}

2.2. 循环渲染 ForEach

ForEach 接口用于在数组类型的数据上进行循环渲染,并需要与容器组件一起使用以展示循环生成的内容。
语法:

ForEach(// 数据源arr: Array,// 组件生成函数itemGenerator: (item: Array, index?: number) => void,// 键值生成函数keyGenerator?: (item: Array, index?: number): string => string
)

应用1:

interface IArrObj {id:number,name:string
}
@Entry
@Component
struct Index {@State arrObj: IArrObj[] = [{ id:1, name: "lili" },{ id:2, name: "Tom" },{ id:3, name: "Janny" }]build() {Column() {// ForEach(this.arrObj,(item)=>{//    Text(`${new Date().getTime()}---${item.name}`)// },(item,index)=>index+JSON.stringify(item))//复用性更强ForEach(this.arrObj,(item: IArrObj) => {Text(`${new Date().getTime()}---${item.name}`)},(item: IArrObj) => JSON.stringify(item))Button("尾部新增一项").onClick(()=>{this.arrObj.push({id:this.arrObj.length,name:"丽萍"})})Button("调换位置").onClick(() => {this.arrObj=[this.arrObj[2],this.arrObj[0],this.arrObj[1]]})}.width('100%').height('100%')}
}

测试:

在这里插入图片描述

应用2:

class NameClass {firstName:string = ""nameContent:string[] = []constructor(firstName: string, nameContent: string[]) {this.firstName = firstNamethis.nameContent = nameContent}
}@Entry
@Component
struct APage {private NameList:NameClass[] = [new NameClass("李",["李里","李芳","李月","李飞","李藏"]),new NameClass("刘",["刘备","刘彻","刘思雨"]),new NameClass("王",["王玉华","王岁","王喜文","王华"])]@BuilderHeaderTitle(title:string) {Text(title).fontSize(20).fontWeight(900).height(50).backgroundColor('#ccc').width('100%')}@BuilderdelButton() {Button("删除")}build() {Column(){List({ space:10 }) {ForEach(this.NameList,(item: NameClass) => {ListItemGroup({header:this.HeaderTitle(item.firstName),space:20}) {ForEach(item.nameContent,(itemCon: string) => {ListItem() {Text(itemCon)}.width('100%').height(50).swipeAction({end:this.delButton()})})}.width("100%").divider({ strokeWidth: 3, color:"#ccc" })},(item: NameClass) => JSON.stringify(item))}.width("100%").height("100%").alignListItem(ListItemAlign.Center).listDirection(Axis.Vertical).scrollBar(BarState.Auto)}.width("100%").height("100%")}
}

测试:

在这里插入图片描述

有关 keyGenerator 键生成函数的一些建议如下:

  • 必须提供 keyGenerator 函数,不能省略。
  • 尽量避免在最终生成的键中包含索引(index)。
  • 当处理对象数组时,建议使用对象中的唯一标识符(如 id)作为键。
  • 如果处理基本数据类型的数组,建议先将其转换为具有唯一标识符的对象,然后再使用 keyGenerator 生成键。

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com