鸿蒙UI开发

鸿蒙 UI 开发

本文旨在分享一些鸿蒙UI布局开发上的一些建议,特别是对屏幕宽高比发生变化时的应对思路和好的实践。

折叠屏适配

一般情况( 自适应布局/响应式布局

1. 自适应布局

1.1 自适应拉伸

左右组件定宽

|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| TypeScript //左右定宽 Row() { Text("健康使用手机") .fontSize(16) .width(135) Blank() Toggle({ type: ToggleType.Switch }) .width(36) } .borderRadius(12) .padding({ left: 13, right: 13 }) .backgroundColor('#FFFFFF') .width('100%') |

左右组件不定宽(左组件占剩余宽度,右组件不定宽)

|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| TypeScript //layoutWeight //左右不定宽, Row() { ... Text("我的宽度占剩余的宽度"+"111111111111") .maxLines(1) .textOverflow({ overflow: TextOverflow.Ellipsis }) ... } .layoutWeight(1) Text("我的宽度不固定") .textAlign(TextAlign.End) //这个margin自我调整,一般为做组件所有icon的宽度和 .margin({ left: 54 }) } .width('100%') |

1.2 均分拉伸

灵活使用弹性布局Flex

|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| TypeScript //不换行 Flex({ justifyContent: FlexAlign.SpaceEvenly }) { ForEach(this .list, () => { this .Item() }) } //换行 Flex({ justifyContent: FlexAlign.Center ,wrap:FlexWrap.Wrap}) { ForEach(this .list, () => { this .Item() }) } |

1.3 自适应延伸

|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| TypeScript Scroll() { Row({ space: 10 }) { ForEach(this .appList, () => { Column() { Image(r('app.media.icon')) .width(48) .height(48) Text(r('app.string.show_app_name')) .fontSize(12) .textAlign(TextAlign.Center) }.width(80).height(102) }) } } .scrollable(ScrollDirection.Horizontal) .width("100%") |

2. 响应式布局

2.1 媒体查询

|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| TypeScript //核心代码 private breakpoints: BreakpointEntity[] = [ { name: 'xs', size: 0 }, { name: 'sm', size: 320 }, { name: 'md', size: 600 }, { name: 'lg', size: 840 } ] /** * 更新当前断点 * 当传入的断点与当前断点不同时,更新当前断点并持久化 */ private updateCurrentBreakpoint(breakpoint: string) { if (this.currentBreakpoint !== breakpoint) { this.currentBreakpoint = breakpoint; AppStorage.Set<string>('currentBreakpoint', this.currentBreakpoint); console.log('on current breakpoint: ' + this.currentBreakpoint); } } /** * 注册断点监听器 * 为每个断点创建媒体查询监听器,当屏幕尺寸匹配时,更新当前断点 */ public register() { this.breakpoints.forEach((breakpoint: BreakpointEntity, index) => { let condition :string = ''; // 监听句柄,反应视窗宽度和 breakpoint.size 的关系 if (index === this.breakpoints.length - 1) { condition = '(' + breakpoint.size + 'vp<=width' + ')'; } else { condition = '(' + breakpoint.size + 'vp<=width<' + this.breakpoints[index + 1].size + 'vp)'; } console.log(condition); // breakpoint.size vp <= width 的条件改变时触发回调,传递此时视窗大小 breakpoint.mediaQueryListener = mediaQuery.matchMediaSync(condition); breakpoint.mediaQueryListener.on('change', (mediaQueryResult) => { if (mediaQueryResult.matches) { this.updateCurrentBreakpoint(breakpoint.name); } }) }) } |

3. 典型布局场景

3.1 挪移布局

|---|---|
| | |

栅格布局GridRow

|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| TypeScript GridRow() { GridCol({ span: { sm: 12, md: 6, lg: 6 } }) { Text("图片内容") } .width("100%") .height("50%") .backgroundColor(Color.Red) GridCol({ span: { sm: 12, md: 6, lg: 6 } }) { Text("文字标题") } .width("100%") .height("50%") .backgroundColor(Color.Blue) } |

3.2 重复布局

|----------------------------------------------------------------------------|----------------------------------------------------------------------------|
| | |

栅格布局GridRow

|------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| TypeScript Scroll() { GridRow() { ForEach([0, 1, 2, 3, 4, 5, 6, 7], () => { GridCol({ span: { sm: 12, md: 6, lg: 6 } }) { Column() { RepeatItemContent() } } }) } } |

3.3 顶部布局

|----------------------------------------------------------------------------|----------------------------------------------------------------------------|
| | |

栅格布局GridRow

|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| TypeScript @State needWrap: boolean = true build() { GridRow() { // 第一行布局 GridCol({ span: { sm: 12, md: 6, lg: 7 } }) { Row() { Text(r('app.string.recommended')).fontSize(24) Blank() Image(r('app.media.ic_public_more')) .width(32) .height(32) .visibility(this .needWrap ? Visibility.Visible : Visibility.None) } .width('100%') .alignItems(VerticalAlign.Center) } // 第二行布局 GridCol({ span: { sm: 12, md: 6, lg: 5 } }) { Flex({ alignItems: ItemAlign.Center }) { Search({ placeholder: '猜您喜欢: 万水千山' }) Image(r('app.media.audio_fm')) .width(32) .height(32) Image(r('app.media.ic_public_more')) .width(32) .height(32) .visibility(this .needWrap ? Visibility.None : Visibility.Visible) } }//控制显隐多余元素 }.onBreakpointChange((breakpoint: string) => { if (breakpoint === 'sm') { this .needWrap = true } else { this .needWrap = false } }) } |

3. 复杂情况(判断手机的状态)

3.1 折叠屏适配

|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| TypeScript // 当前折叠屏状态(若当前为折叠屏设备才有效) @State curFoldStatus: display.FoldStatus = display.getFoldStatus(); if (display.isFoldable()) { // 监听折叠屏状态变更,更新折叠态 display.on('foldStatusChange', (curFoldStatus: display.FoldStatus) => { this .curFoldStatus = curFoldStatus; }) } build() { // 折叠屏UI展示 if (display.isFoldable()) { ... } } else { // 非折叠屏UI展示 ... } } } |

相关推荐
小小小小小星3 小时前
鸿蒙开发之ArkUI框架进阶:从声明式范式到跨端实战
harmonyos·arkui
鸿蒙小灰3 小时前
鸿蒙开发对象字面量类型标注的问题
harmonyos
鸿蒙先行者4 小时前
鸿蒙Next不再兼容安卓APK,开发者该如何应对?
harmonyos
YF云飞6 小时前
.NET 在鸿蒙系统(HarmonyOS Next)上的适配探索与实践
华为·.net·harmonyos
Quarkn10 小时前
鸿蒙原生应用ArkUI之自定义List下拉刷新动效
list·harmonyos·arkts·鸿蒙·arkui
AlbertZein11 小时前
HarmonyOS5 凭什么学鸿蒙 —— Context详解
harmonyos
whysqwhw19 小时前
鸿蒙音频播放方式总结
harmonyos
whysqwhw19 小时前
鸿蒙音频录制方式总结
harmonyos
zhanshuo21 小时前
HarmonyOS 实战:用 @Observed + @ObjectLink 玩转多组件实时数据更新
harmonyos
zhanshuo21 小时前
鸿蒙任务调度机制深度解析:优先级、时间片、多核与分布式的流畅秘密
harmonyos