1、Image图片组件
鸿蒙内置组件Image的4种写法
// 鸿蒙内置Image图片组件案例
@Entry
@Component
struct ImagePage {
build() {
Column({space:20}){
// 1、图片的第一种写法 media文件夹下
Image($r('app.media.pig')).width(200).height(200);
// 2、图片的第二种写法 rawfile文件夹下
Image($rawfile('avatar2.jpg')).width(200).height(200);
// 3、图片的第三种写法 网络图片 (需要在module.JSON5文件中申请网络权限)
Image('https://img1.baidu.com/it/u=3621655768,3950011962&fm=253&fmt=auto&app=138&f=JPEG?w=400&h=400').width(200).height(200);
// 4、图片的第四种写法 图片资源放在ets文件夹下
Image('images/gx5.gif').width('200').height('200');
}.width('100%').height('100%')
}
}
2、像素单位(默认):vp
鸿蒙提供的长度像素单位为:px 与 vp
● HarmonyOS中提供的长度像素单位为:px 与 vp
● px: Pixel,屏幕物理像素单位。
●问题:相同px值在不同像素密度的手机上显示的尺寸是不同的(如下图所示)
●注意:不同于CSS中的px,CSS中的px类似于下面的vp
● vp: Virtual Pixel,虚拟像素
○它是屏幕像素密度相关像素
○应用运行时,会根据屏幕像素密度转换为屏幕物理像素进行显示
○在不同像素密度的手机上,1vp对应的像素数是不同的,像素密度越高,1vp对应的像素数就越多。从而达到:用vp作为长度单位,在尺寸相同但像素密度不同的手机上,显示大小相同。(如下图所示)
○当数值不带单位时,默认单位为vp。
○HarmonyOS提供了针对运行设备的vp与px转换的全局计算函数
■ px2vp(val): 得到指定px值对应的vp值
■ vp2px(val): 得到指定vp值对应的px值
@Entry
@Component
struct VpExample {
build() {
Column(){
Text('我的宝宝呢').width('1080px').height('100px').backgroundColor('red')
Text('当前设备1vp=多少px'+vp2px(1)).width(200).height(200).fontSize(20)
Image($r('app.media.avatar')).width('100px').height('100px')
Image($r('app.media.avatar')).width(100).height(100)
Image($r('app.media.avatar')).width('100vp').height('100vp')
Image($r('app.media.avatar')).width(vp2px(100)+'px').height(vp2px(100)+'px')
}
}
}
3、Text文本组件
@Entry
@Component
struct TextExample {
build() {
Column(){
// 1、文本的第一种写法
Text('文本的第一种写法')
.fontSize(20) // 文字大小
.fontColor('green') // 文字颜色
// 2、文本的第二种写法
Text($r('app.string.text_example'))
.fontWeight(500) // 文字宽度
.width(100) // 文本宽度
.height(100) // 文本高度
.backgroundColor(Color.Orange) // 背景颜色
.textAlign(TextAlign.End) // 文本对齐方式
.textOverflow({
overflow:TextOverflow.Ellipsis // 文本长度溢出显示省略号
})
.maxLines(1) // 最大一行
}.width('100%')
}
}
4、Button按钮组件
@Entry
@Component
struct ButtonExample {
build() {
// 列
Column() {
Button('按钮')
.type(ButtonType.Normal) // 按钮样式
.onClick(() => { // 绑定事件
console.log('点击事件')
});
// Button放置子组件
Button() {
Image($r('app.media.icon')).width(30).height(30)
}.width(100)
.height(100)
.onClick(() => {
console.log('onClick事件')
})
}.width('100%')
}
}
5、Toggle组件
@Entry
@Component
struct ToggleExample {
build() {
Column(){
// 切换按钮
Toggle({type:ToggleType.Checkbox,isOn:false}) // 复选框
Toggle({type:ToggleType.Switch,isOn:true}) // 开关
Toggle({type:ToggleType.Button,isOn:true }){// 按钮
Text('自定义')
// Button('button')
}.selectedColor(Color.Pink).onClick((event) => {
console.log('自定义按钮')
}).onChange((isOn) => {
console.log(JSON.stringify(isOn))
})
}.width('100%')
}
}
6、TextInput文本输入框组件
@Entry
@Component
struct TextInputExample {
// 用户名
@State username: string = ''
// 密码
@State password: string = ''
// 方法
login(username: string, password: string) {
console.log(`发送登录请求~~~ username:${username} password:${password}`)
if(username != '' && password != ''){
console.log('登录成功')
}else {
console.log('登录失败')
}
}
build() {
Column() {
// 表单
TextInput({ placeholder: '请输入用户名', text: this.username })
.onChange((value) => {
this.username = value
console.log(`username:${value}`)
})
.maxLength(5)
.type(InputType.Number)
.margin({ top: 10 });
Divider().margin({top:10}); // 分割线
TextInput({ placeholder: '请输入密码', text: this.password })
.onChange((value) => {
this.password = value
console.log(`password:${value}`)
})
.maxLength(6)
.type(InputType.Password)
.margin({ top: 10 });
Button("登录")
.type(ButtonType.Normal)
.margin({ top: 10 })
.onClick(() => this.login(this.username,this.password))
}.width('100%').padding(20)
}
}
7、Progress进度条组件
@Entry
@Component
struct ProgressExample {
build() {
Column(){
// 进度条组件
Progress({value:10,total:100,type:ProgressType.ScaleRing})
Progress({value:30,total:100,type:ProgressType.Linear})
Progress({value:50,total:100,type:ProgressType.Eclipse})
Progress({value:70,total:100,type:ProgressType.Capsule})
Progress({value:100,total:100,type:ProgressType.Ring})
}.width('100%').padding(10)
}
}
8、弹窗组件之API弹窗
// 引入api弹窗
import promptAction from '@ohos.promptAction';
@Entry
@Component
struct ApiPopupExample1 {
build() {
Column() {
/**
* 弹窗分类:
* 1、API弹窗 :需要引入相关模块,只能做简单弹窗
* 2、预制弹窗 :直接使用
*/
Row() {
// 1、提示信息弹窗
Button('提示信息').onClick(() => {
promptAction.showToast({
message: '苦命后端学鸿蒙', // 弹窗内容
duration: 1000, // 弹窗显示时间
bottom: 200 // 弹窗离底部距离
})
})
}
Row() {
// 对话框
Button('对话框').onClick(() => {
promptAction.showDialog({
title: '你确定删除王者荣耀么?',
message: '玩的心累',
buttons: [
{
text: '确定',
color: '#CF539'
},
{
text: '取消',
color: '#aaa'
},
]
}).then(res => {
// 通过index区分 确定 还是 取消
console.log('res执行了'+res.index)
}).catch(err => {
console.log('err执行了'+err)
}).finally(() => {
console.log('finally执行了')
})
})
}.margin({ top: 10 })
Row(){
// 菜单弹窗
Button('菜单弹窗').onClick(() => {
promptAction.showActionMenu({
title:'你想要什么',
buttons:[
{
text:'Iphone15ProMax',
color:'8F4D68'
},
{
text:'笔记本电脑',
color:'333840'
}
]
}).then(res => {
console.log('选择的是哪个选项'+res.index)
}).catch(() => {
// 取消执行
console.log('catch')
})
})
}.margin({top:10})
}.width('100%').padding(10)
}
}
9、预制弹窗
@Entry
@Component
struct YuZhiPopupExample {
@State selectedDate: Date = new Date("2023-02-06");
@State selectTime: Date = new Date('2020-12-25T08:30:00')
@State select: number = 2
@State fruits: string[] = ['apple1', 'orange2', 'peach3', 'grape4', 'banana5']
private selectCount: number = 10
build() {
Column({ space: 20 }) {
//警告弹窗
Row() {
Button('警告弹窗').onClick((event: ClickEvent) => {
AlertDialog.show({
title: '操作提示', // 弹窗标题
message: '确认删除吗?', // 弹窗内容
autoCancel: false, //点击遮障层时,是否关闭弹窗。
alignment: DialogAlignment.Center, //弹窗位置
gridCount: 4, // 弹窗容器宽度所占用栅格数
offset: { dx: 30, dy: -20 }, //弹窗相对alignment所在位置的偏移量
/* 多个按钮 -- 开始 */
// primaryButton: { //主按钮的文本内容、文本色、按钮背景色和点击回调。
// value: '确认', //按钮文字
// action: () => { //按钮回调
// console.info('你点击了确定按钮')
// },
// fontColor:'red'
// },
// secondaryButton: { //副按钮的文本内容、文本色、按钮背景色和点击回调。
// value: '取消', //按钮文字
// action: () => { //按钮回调
// console.info('你点击了取消按钮')
// },
// fontColor:'#aaa'
// },
/* 多个按钮 -- 结束 */
/* 单个按钮 -- 开始 */
confirm: {
value: '确认',
action: () => {
console.info('xxxxxx')
}
}
})
})
}
//列表弹窗
Row() {
Button('列表弹窗').onClick(() => {
ActionSheet.show({
title: '操作提示', // 弹窗标题
message: '请选择类型', //弹窗内容
autoCancel: true, //点击遮障层时,是否关闭弹窗。
// 确认按钮的文本内容和点击回调
confirm: {
value: '确定', //文字内容
action: () => { //回调
console.log('你点击了确认按钮')
}
},
// 点击遮障层关闭dialog时的回调
cancel: () => {
console.log('弹窗关闭了')
},
// 弹窗在竖直方向上的对齐方式。
alignment: DialogAlignment.Bottom,
// 弹窗相对alignment所在位置的偏移量
offset: { dx: 0, dy: -10 },
// 设置选项内容,每个选择项支持设置图片、文本和选中的回调
sheets: [
{
title: '打折商品', // 标题
action: () => { // 回调
console.log('goods1')
}
},
{
title: '限购商品',
action: () => {
console.log('goods2')
}
},
{
title: 'VIP商品',
action: () => {
console.log('goods2')
}
},
{
title: '预售商品',
action: () => {
console.log('goods3')
}
}
]
})
})
}
// 日期滑动选择器
Row() {
Button('阳历').onClick((event: ClickEvent) => {
DatePickerDialog.show({
start: new Date("2000-1-1"),
end: new Date("2100-12-31"),
selected: this.selectedDate,
onAccept: (value: DatePickerResult) => {
// 通过Date的setFullYear方法设置按下确定按钮时的日期,这样当弹窗再次弹出时显示选中的是上一次确定的日期
this.selectedDate.setFullYear(value.year, value.month, value.day)
console.info("DatePickerDialog:onAccept()" + JSON.stringify(value))
},
onCancel: () => {
console.info("DatePickerDialog:onCancel()")
},
onChange: (value: DatePickerResult) => {
console.info("DatePickerDialog:onChange()" + JSON.stringify(value))
}
})
});
Button('阴历').onClick((event: ClickEvent) => {
DatePickerDialog.show({
start: new Date("2000-1-1"),
end: new Date("2100-12-31"),
selected: this.selectedDate,
lunar: true,
onAccept: (value: DatePickerResult) => {
this.selectedDate.setFullYear(value.year, value.month, value.day)
console.info("DatePickerDialog:onAccept()" + JSON.stringify(value))
},
onCancel: () => {
console.info("DatePickerDialog:onCancel()")
},
onChange: (value: DatePickerResult) => {
console.info("DatePickerDialog:onChange()" + JSON.stringify(value))
}
})
})
}
//时间滑动选择器
Row() {
Button('12小时制').onClick(() => {
TimePickerDialog.show({
selected: this.selectTime,
onAccept: (value: TimePickerResult) => {
// 设置selectTime为按下确定按钮时的时间,这样当弹窗再次弹出时显示选中的为上一次确定的时间
this.selectTime.setHours(value.hour, value.minute)
console.info("TimePickerDialog:onAccept()" + JSON.stringify(value))
},
onCancel: () => {
console.info("TimePickerDialog:onCancel()")
},
onChange: (value: TimePickerResult) => {
console.info("TimePickerDialog:onChange()" + JSON.stringify(value))
}
})
});
Button('24小时').onClick(() => {
TimePickerDialog.show({
selected: this.selectTime,
useMilitaryTime: true,
onAccept: (value: TimePickerResult) => {
this.selectTime.setHours(value.hour, value.minute)
console.info("TimePickerDialog:onAccept()" + JSON.stringify(value))
},
onCancel: () => {
console.info("TimePickerDialog:onCancel()")
},
onChange: (value: TimePickerResult) => {
console.info("TimePickerDialog:onChange()" + JSON.stringify(value))
}
})
})
}
//文本滑动选择器
Row() {
Button('文本滑动选择器').onClick((event: ClickEvent) => {
TextPickerDialog.show({
range: this.fruits,
selected: this.selectCount,
onAccept: (value: TextPickerResult) => {
// 设置select为按下确定按钮时候的选中项index,这样当弹窗再次弹出时显示选中的是上一次确定的选项
this.select = value.index
console.info("TextPickerDialog:onAccept()" + JSON.stringify(value))
},
onCancel: () => {
console.info("TextPickerDialog:onCancel()")
},
onChange: (value: TextPickerResult) => {
console.info("TextPickerDialog:onChange()" + JSON.stringify(value))
}
})
})
}
}
.width('100%');
}
}
10、线性布局
@Entry
@Component
struct LayoutExample {
private arr: Array<number> = [1, 2, 3, 4, 5]
private colors: Array<Color> = [Color.Red, Color.Green, Color.Blue, Color.Orange, Color.Pink]
build() {
// 线性布局
Column({ space: 20 }) {
Row() {
}.width(360).height(50).backgroundColor(Color.Red)
Row() {
}.width(360).height(50).backgroundColor(Color.Orange)
Row() {
}.width(360).height(50).backgroundColor(Color.Yellow)
Row() {
}.width(360).height(50).backgroundColor(Color.Blue)
Row() {
// 遍历
ForEach(this.arr, (index) => {
Column() {
}.width('10%').height(100).backgroundColor(this.colors[index-1]).margin({ left: 10 })
}, item => JSON.stringify(item))
//
//
// Column() {
// }.width('20%').height(100).backgroundColor(Color.Pink)
//
// Column() {
// }.width('20%').height(100).backgroundColor(Color.White)
//
// Column() {
// }.width('20%').height(100).backgroundColor(Color.Gray)
//
// Column() {
// }.width('20%').height(100).backgroundColor(Color.Brown)
}
// .justifyContent(FlexAlign.Center)
.justifyContent(FlexAlign.SpaceAround).height(300).alignItems(VerticalAlign.Top)
}
}
}
11、层叠布局
@Entry
@Component
struct CascadeLayoutExample {
build() {
Stack() {
Row() {
Text('子元素1')
}.width(300)
.height(300)
.backgroundColor(Color.Red)
// 设置层叠索引
.zIndex(2)
Row(){
Text('子元素2')
}.width(150)
.height(150)
.backgroundColor(Color.Orange)
Row(){
Text('子元素3')
}.width(75)
.height(75)
.backgroundColor(Color.Blue)
}
.width('100%')
.height(400)
.backgroundColor(Color.Green)
// 设置层叠对其方式
.alignContent(Alignment.BottomStart)
}
}
层叠布局与position一起使用
@Entry
@Component
struct PositionExample {
build() {
Stack(){
Image($r('app.media.pig')).width(100).height(100)
// position:绝对定位
.position({x:100,y:100})
}.width('100%')
.height(500)
.backgroundColor(Color.Black)
}
}
12、Flex弹性布局
@Entry
@Component
struct FlexExample {
build() {
Flex({direction:FlexDirection.RowReverse,justifyContent:FlexAlign.SpaceEvenly,alignItems:ItemAlign.Stretch}) {
Row() {
}.width(60).height(60).backgroundColor(Color.Red)
Row() {
}.width(60).height(60).backgroundColor(Color.Orange)
Row() {
}.width(60).height(60).backgroundColor(Color.Yellow)
Row() {
}.width(60).height(60).backgroundColor(Color.Green)
}.width('100%')
.height(300)
.backgroundColor('#ccc')
}
}
13、网格布局
@Entry
@Component
struct GridLayoutExample {
build() {
// Grid(){
// GridItem().backgroundColor(Color.Red).rowStart(1).rowEnd(2)
// GridItem().backgroundColor(Color.Green)
// GridItem().backgroundColor(Color.Yellow)
// GridItem().backgroundColor(Color.Blue)
// GridItem().backgroundColor(Color.Pink)
// GridItem().backgroundColor(Color.Brown)
// GridItem().backgroundColor(Color.Orange)
// GridItem().backgroundColor(Color.Grey)
// GridItem().backgroundColor(Color.White)
// }.width('100%')
// .height(500)
// .backgroundColor('#ccc')
// .rowsTemplate('1fr 1fr 1fr')
// .columnsTemplate('1fr 1fr 1fr')
// .rowsGap(5)
// .columnsGap(5)
Grid(){
GridItem(){}.width('25%').height(100).backgroundColor(Color.Red)
GridItem(){}.width('25%').height(100).backgroundColor(Color.Orange)
GridItem(){}.width('25%').height(100).backgroundColor(Color.Yellow)
GridItem(){}.width('25%').height(100).backgroundColor(Color.Pink)
GridItem(){}.width('25%').height(100).backgroundColor(Color.Pink)
GridItem(){}.width('25%').height(100).backgroundColor(Color.Yellow)
GridItem(){}.width('25%').height(100).backgroundColor(Color.Red)
GridItem(){}.width('25%').height(100).backgroundColor(Color.Orange)
GridItem(){}.width('25%').height(100).backgroundColor(Color.Pink)
GridItem(){}.width('25%').height(100).backgroundColor(Color.Yellow)
GridItem(){}.width('25%').height(100).backgroundColor(Color.Red)
GridItem(){}.width('25%').height(100).backgroundColor(Color.Orange)
GridItem(){}.width('25%').height(100).backgroundColor(Color.Pink)
GridItem(){}.width('25%').height(100).backgroundColor(Color.Yellow)
GridItem(){}.width('25%').height(100).backgroundColor(Color.Red)
GridItem(){}.width('25%').height(100).backgroundColor(Color.Orange)
}.width('100%')
.height(300)
// 只能指定行|列 父组件空间不足则可以滚动
.backgroundColor(Color.Gray)
.columnsTemplate('1fr 1fr')
.rowsGap(10)
.columnsGap(10)
}
}
14、List列表布局
@Entry
@Component
struct ListLayoutExample {
build() {
List(){
ListItem(){
Text('周杰伦').width(100).height(40).fontSize(20)
}.backgroundColor(Color.Red).width('100%')
ListItem(){
Text('林俊杰').width(100).height(40).fontSize(20)
}.backgroundColor(Color.Red).width('100%')
ListItem(){
Text('许嵩').width(100).height(40).fontSize(20)
}.backgroundColor(Color.Red).width('100%')
ListItemGroup(){
ListItem(){
Flex({justifyContent:FlexAlign.SpaceBetween}){
Text('园游会').fontSize(30)
Text('一路向北').fontSize(30)
}
}
ListItem(){
Flex({justifyContent:FlexAlign.SpaceBetween}){
Text('断桥残血').fontSize(30)
Text('清明雨上').fontSize(30)
}
}
}
}.width('100%')
.height(300)
.listDirection(Axis.Horizontal)
}
}
List列表布局案例
@Entry
@Component
struct ListLayoutExample {
@State userArr: object[] = [
{ title: 'A', data: ['A001', 'A002', 'A003', 'A004', 'A005'] },
{ title: 'B', data: ['B001', 'B002', 'B003', 'B004', 'B005'] },
{ title: 'C', data: ['C001', 'C002', 'C003', 'C004', 'C005'] },
{ title: 'D', data: ['D001', 'D002', 'D003', 'D004', 'D005'] },
{ title: 'E', data: ['E001', 'E002', 'E003', 'E004', 'E005'] }
]
// UI组件复用 @Builder
@Builder header(item){
Text(item.title).backgroundColor(Color.Red).textAlign(TextAlign.Center)
.width('100%')
}
build() {
List(){
ForEach(this.userArr,(item,index) => {
ListItemGroup({header:this.header(item)}){
ForEach(item.data,(name,i) => {
ListItem(){
Text(name).fontSize(20).fontWeight(500)
}
},item => JSON.stringify(item))
}
},item => JSON.stringify(item))
}.width('100%')
.height(300)
}
}
写在最后
有很多小伙伴不知道学习哪些鸿蒙开发技术?不知道需要重点掌握哪些鸿蒙应用开发知识点?而且学习时频繁踩坑,最终浪费大量时间。所以有一份实用的鸿蒙(HarmonyOS NEXT)资料用来跟着学习是非常有必要的。
这份鸿蒙(HarmonyOS NEXT)资料包含了鸿蒙开发必掌握的核心知识要点,内容包含了(ArkTS、ArkUI开发组件、Stage模型、多端部署、分布式应用开发、音频、视频、WebGL、OpenHarmony多媒体技术、Napi组件、OpenHarmony内核、OpenHarmony南向开发、鸿蒙项目实战等等)鸿蒙(HarmonyOS NEXT)技术知识点。
希望这一份鸿蒙学习资料能够给大家带来帮助,有需要的小伙伴自行领取,限时开源,先到先得~无套路领取!!
获取这份完整版高清学习路线,请点击→纯血版全套鸿蒙HarmonyOS学习资料
鸿蒙(HarmonyOS NEXT)最新学习路线
有了路线图,怎么能没有学习资料呢,小编也准备了一份联合鸿蒙官方发布笔记整理收纳的一套系统性的鸿蒙(OpenHarmony )学习手册(共计1236页)与鸿蒙(OpenHarmony )开发入门教学视频,内容包含:ArkTS、ArkUI、Web开发、应用模型、资源分类…等知识点。
获取以上完整版高清学习路线,请点击→纯血版全套鸿蒙HarmonyOS学习资料
《鸿蒙 (OpenHarmony)开发入门教学视频》
《鸿蒙生态应用开发V3.0白皮书》
《鸿蒙 (OpenHarmony)开发基础到实战手册》
OpenHarmony北向、南向开发环境搭建
《鸿蒙开发基础》
●ArkTS语言
●安装DevEco Studio
●运用你的第一个ArkTS应用
●ArkUI声明式UI开发
.……
《鸿蒙开发进阶》
●Stage模型入门
●网络管理
●数据管理
●电话服务
●分布式应用开发
●通知与窗口管理
●多媒体技术
●安全技能
●任务管理
●WebGL
●国际化开发
●应用测试
●DFX面向未来设计
●鸿蒙系统移植和裁剪定制
……
《鸿蒙进阶实战》
●ArkTS实践
●UIAbility应用
●网络案例
……