鸿蒙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展示 ... } } } |

相关推荐
RZer6 分钟前
Crypto Architecture Kit简介
harmonyos
东林知识库18 分钟前
鸿蒙NEXT小游戏开发:猜小球
harmonyos
东林知识库18 分钟前
鸿蒙NEXT小游戏开发:记忆翻牌
harmonyos
李游Leo1 小时前
HarmonyOS:ComposeTitleBar 组件自学指南
harmonyos
抓鱼猫L1 小时前
鸿蒙Next(四)文字识别
harmonyos
IT乐手2 小时前
3.7、HarmonyOS Next 自定义弹窗(CustomDialog)
harmonyos
李游Leo2 小时前
HarmonyOS:ArkTS 多态样式自学指南
harmonyos
zacksleo2 小时前
鸿蒙Flutter实战:20. Flutter集成高德地图,同层渲染
flutter·harmonyos
李游Leo2 小时前
HarmonyOS:ArkTS RowSplit 组件自学指南
harmonyos
NodeMedia2 小时前
如何快速集成NodeMediaClient-Harmony
harmonyos