鸿蒙多功能工具箱开发实战(三十二)-多设备适配与响应式布局
前言
HarmonyOS支持多种设备形态,多设备适配是开发的重要环节。本文将讲解响应式布局和多设备适配策略。
一、设备类型
1.1 设备分类
| 类型 | 宽度范围 | 典型设备 |
|---|---|---|
| 小屏 | < 600dp | 手机竖屏 |
| 中屏 | 600-840dp | 手机横屏、小平板 |
| 大屏 | > 840dp | 平板、折叠屏 |
1.2 设备信息获取
importdisplayfrom'@ohos.display'importdeviceInfofrom'@ohos.deviceInfo'exportclassDeviceUtil{/** * 获取设备类型 */staticgetDeviceType():'phone'|'tablet'|'tv'|'wearable'{consttype=deviceInfo.deviceTypeswitch(type){case'phone':return'phone'case'tablet':return'tablet'case'tv':return'tv'case'wearable':return'wearable'default:return'phone'}}/** * 获取屏幕宽度 */staticgetScreenWidth():number{constdisplayInfo=display.getDefaultDisplaySync()returndisplayInfo.width}/** * 获取屏幕高度 */staticgetScreenHeight():number{constdisplayInfo=display.getDefaultDisplaySync()returndisplayInfo.height}/** * 是否横屏 */staticisLandscape():boolean{returnthis.getScreenWidth()>this.getScreenHeight()}/** * 是否大屏设备 */staticisLargeScreen():boolean{constwidth=px2vp(this.getScreenWidth())returnwidth>=600}}1.3 网络请求流程图
二、响应式布局
2.1 媒体查询
importmediaQueryfrom'@ohos.mediaquery'exportclassMediaQueryUtil{privatestaticlistener:mediaQuery.MediaQueryListener/** * 监听屏幕变化 */staticlistenScreenChange(callback:(isLarge:boolean)=>void):void{constcondition=mediaQuery.matchConditionSync('screen and (min-width: 600vp)')this.listener=mediaQuery.matchCondition(condition,(result:mediaQuery.MediaQueryResult)=>{callback(result.matches)})}/** * 取消监听 */staticunlisten():void{if(this.listener){mediaQuery.unmatchCondition(this.listener)}}}2.2 响应式组件
@Componentexportstruct ResponsiveLayout{@StateisLargeScreen:boolean=falseaboutToAppear(){this.isLargeScreen=DeviceUtil.isLargeScreen()MediaQueryUtil.listenScreenChange((isLarge)=>{this.isLargeScreen=isLarge})}aboutToDisappear(){MediaQueryUtil.unlisten()}@BuilderParamsmallContent:()=>void@BuilderParamlargeContent:()=>voidbuild(){if(this.isLargeScreen){this.largeContent()}else{this.smallContent()}}}2.3 使用示例
@Entry@Componentstruct ResponsivePage{build(){ResponsiveLayout({smallContent:()=>{// 小屏布局:单列Column(){this.ContentArea()}},largeContent:()=>{// 大屏布局:双列Row(){this.SideBar()this.ContentArea()}}})}@BuilderSideBar(){Column(){Text('侧边栏')}.width(240).backgroundColor('#F5F5F5')}@BuilderContentArea(){Column(){Text('内容区域')}.layoutWeight(1)}}三、栅格布局
3.1 栅格系统
@Componentexportstruct GridContainer{@Propcolumns:number=12@Propgutter:number=16@BuilderParamcontent:()=>voidbuild(){Row(){this.content()}.width('100%')}}@Componentexportstruct GridColumn{@Propspan:number=12// 占用列数@Propoffset:number=0// 偏移列数@BuilderParamcontent:()=>voidbuild(){Column(){this.content()}.width(`${(this.span/12)*100}%`).margin({left:`${(this.offset/12)*100}%`})}}3.2 响应式栅格
@Componentexportstruct ResponsiveGrid{@Statecolumns:number=12@StateisLargeScreen:boolean=falseaboutToAppear(){this.updateColumns()MediaQueryUtil.listenScreenChange((isLarge)=>{this.isLargeScreen=isLargethis.updateColumns()})}privateupdateColumns(){this.columns=this.isLargeScreen?12:4}build(){Grid(){// 栅格内容}.columnsTemplate(`repeat(${this.columns}, 1fr)`)}}四、多设备资源
4.1 资源目录结构
resources/ ├── base/ # 默认资源 │ ├── element/ │ │ └── string.json │ └── media/ │ └── icon.png ├── phone/ # 手机资源 │ └── media/ │ └── icon.png # 手机尺寸图标 └── tablet/ # 平板资源 └── media/ └── icon.png # 平板尺寸图标4.2 设备特定配置
exportclassResourceUtil{/** * 获取设备特定资源 */staticgetDeviceResource(baseName:string):Resource{constdeviceType=DeviceUtil.getDeviceType()// 根据设备类型返回不同资源switch(deviceType){case'tablet':return$r(`app.media.${baseName}_tablet`)default:return$r(`app.media.${baseName}`)}}/** * 获取尺寸相关值 */staticgetDimensionValue(config:{small:numbermedium:numberlarge:number}):number{constwidth=px2vp(DeviceUtil.getScreenWidth())if(width<600)returnconfig.smallif(width<840)returnconfig.mediumreturnconfig.large}}五、适配最佳实践
5.1 弹性尺寸
@Entry@Componentstruct AdaptivePage{build(){Column(){// 使用百分比宽度Row(){Column().width('30%').backgroundColor('#F5F5F5')Column().width('70%').backgroundColor('#FFFFFF')}.width('100%')// 使用layoutWeightRow(){Column().layoutWeight(1).backgroundColor('#F5F5F5')Column().layoutWeight(2).backgroundColor('#FFFFFF')}.width('100%')}}}5.2 字体适配
exportclassFontSizeUtil{/** * 获取适配字体大小 */staticgetFontSize(baseSize:number):number{constdeviceType=DeviceUtil.getDeviceType()switch(deviceType){case'tablet':returnbaseSize*1.25case'tv':returnbaseSize*1.5default:returnbaseSize}}}// 使用Text('标题').fontSize(FontSizeUtil.getFontSize(18))六、高级适配技巧
6.1 设备适配流程图
6.2 自适应组件
@Componentstruct AdaptiveLayout{@StatedeviceType:string='phone'aboutToAppear(){this.deviceType=DeviceUtil.getDeviceType()}build(){if(this.deviceType==='tablet'){this.TabletLayout()}else{this.PhoneLayout()}}@BuilderTabletLayout(){Row(){this.SidePanel()this.MainContent()}}@BuilderPhoneLayout(){Column(){this.MainContent()}}}6.3 资源限定符
resources/ base/ # 默认资源 phone/ # 手机资源 tablet/ # 平板资源 tv/ # TV资源 wearable/ # 可穿戴设备资源七、小结
本文详细讲解了多设备适配:
- ✅ 设备类型判断
- ✅ 媒体查询
- ✅ 响应式布局
- ✅ 栅格系统
- ✅ 多设备资源
- ✅ 自适应组件
- ✅ 资源限定符
系列文章导航:
下期预告:鸿蒙多功能工具箱开发实战(三十三)-折叠屏适配