电子说
设备类型分为default(默认设备)、tablet、tv、wearable、2in1等,有多种查询设备类型的方式。
# 方法一
hdc shell param get "const.product.devicetype"
# 方法二
hdc shell cat /etc/param/ohos.para | grep const.product.devicetype
import deviceInfo from'@ohos.deviceInfo'
@Entry
@Component
struct GetDeviceTypeSample {
@State deviceType:string='unknown'
aboutToAppear() {
this.deviceType= deviceInfo.deviceType
}
build() {
Column() {
Text(this.deviceType).fontSize(24)
}
.width('100%')
.height('100%')
}
}
应用由一个或多个Ability组成,Ability支持单实例、多实例和指定实例3种[启动模式],启动模式可以在[配置文件(module.json5)]中通过launchType字段配置。启动模式对应Ability被启动时的行为,对启动模式的详细说明如下:
启动模式 | 描述 | 说明 开发前请熟悉鸿蒙开发指导文档 :[gitee.com/li-shizhen-skin/harmony-os/blob/master/README.md ]点击或者复制转到。 |
---|---|---|
multiton | 多实例 | 每次startAbility都会启动一个新的实例。 |
singleton | 单实例 | 系统中最多只可以存在一个实例,startAbility时,如果系统中已存在相应的Ability实例,则复用该实例。 |
specified | 指定实例 | 运行时由Ability内部业务决定是否创建多实例。 |
默认设备屏幕尺寸较小,采用multiton启动模式不仅无法给用户提供便利,反而可能消耗更多系统资源,故通常采用singleton启动模式。平板屏幕尺寸较大且可能支持自由窗口,对于文档编辑、网页浏览等场景,使用multiton启动模式可以提升用户体验。
本文中将默认设备和平板等归为同一泛类,推荐同一泛类的设备共用HAP,同时本文也介绍了如何通过自适应布局能力和响应式布局能力开发出适配不同设备的页面。这里将补充介绍,如何实现Ability在不同设备上以不同的模式启动。
launchType字段配置为specified时,系统会根据AbilityStage的onAcceptWant的返回值确定是否创建新的实例。对于同一个应用,如果key已经存在,则复用该key对应的Ability,如果key不存在则新创建Ability。
可以将配置文件中的launchType字段配置为specified,同时在应用中加入如下代码以实现目标效果。
// MyAbilityStage.ts
import AbilityStage from "@ohos.app.ability.AbilityStage"
import deviceInfo from'@ohos.deviceInfo'
import Want from '@ohos.app.ability.Want'
export default class MyAbilityStage extends AbilityStage {
...
private generateKey(): string {
// 如果是平板,则将设备类型和毫秒级时间戳叠加作为key,保证每次启动的key都不同
if (deviceInfo.deviceType === 'tablet') {
return deviceInfo.deviceType + (new Date()).valueOf()
}
// 如果不是平板,直接以设备类型作为key,每次启动的key相同
return deviceInfo.deviceType
}
onAcceptWant(want: Want) : string{
return this.generateKey()
}
}
自由窗口功能默认是关闭的,可以通过如下方式开启自由窗口功能。
# 取出窗口配置文件,并将文件中的< decor enable="false" >< /decor >修改为< decor enable="true" >< /decor >
hdc file recv system/etc/window/resources/window_manager_config.xml ./
# 以可读写的模式重新挂载根目录,并更新配置文件
hdc shell mount -o rw,remount /
hdc file send window_manager_config.xml system/etc/window/resources/window_manager_config.xml
# 重启设备,配置生效
hdc shell reboot
屏幕较小,通过手指操作窗口较为不便时,建议外接鼠标进行操作。
自适应布局可以保证窗口尺寸在一定范围内变化时,页面的显示是正常的。当窗口尺寸变化较大时,就需要额外借助响应式布局能力(如断点等)调整页面结构以保证显示正常。通常每个断点都需要开发者精心适配以获得最佳的显示效果,考虑到设计及开发成本等实际因素的限制,应用不可能适配从零到正无穷的所有窗口宽度。
不同设备或不同设备状态,系统默认的自由窗口尺寸的调节范围可能不同。开发者可以在[应用配置文件]中限制应用中各个Ability的自由窗口尺寸调节范围,配置文件中影响自由窗口尺寸调节范围的字段如下表所示。
配置文件字段 | 数据类型 | 描述 |
---|---|---|
minWindowWidth | 数值 | 标识该ability支持的最小的窗口宽度, 宽度单位为vp。 |
minWindowHeight | 数值 | 标识该ability支持的最小的窗口高度, 高度单位为vp。 |
maxWindowWidth | 数值 | 标识该ability支持的最大的窗口宽度,宽度单位为vp。 |
maxWindowHeight | 数值 | 标识该ability支持的最大的窗口高度, 高度单位为vp。 |
minWindowRatio | 数值 | 标识该ability支持的最小的宽高比。 |
maxWindowRatio | 数值 | 标识该ability支持的最大的宽高比。 |
如下所示,通过配置文件分别限制自由窗口的最大和最小尺寸。
{
"module": {
...
"abilities": [
{
...
"minWindowWidth": 320,
"minWindowHeight": 240,
"maxWindowWidth": 1440,
"maxWindowHeight": 900,
"minWindowRatio": 0.5,
"maxWindowRatio": 2,
}
]
}
}
实际开发过程中,开发者可能有获取页面中某个组件或某块区域的尺寸的诉求,以便通过手动计算等进行更精确的布局计算及优化。
开发者可以通过[组件区域变化事件](即组件显示的尺寸、位置等发生变化时触发的事件)来获取指定组件的尺寸。
如下所示,通过onAreaChange事件获取Row组件(页面中白色区域)的尺寸。
@Entry
@Component
struct OnAreaChangeSample {
@State rate: number = 0.8
@State info: string = ''
// 底部滑块,可以通过拖拽滑块改变容器尺寸
@Builder slider() {
Slider({ value: this.rate * 100, min: 30, max: 80, style: SliderStyle.OutSet })
.blockColor(Color.White)
.width('60%')
.onChange((value: number) = > {
this.rate = value / 100;
})
.position({ x: '20%', y: '80%' })
}
build() {
Column() {
Column() {
Row() {
Text(this.info).fontSize(20).lineHeight(22)
}
.borderRadius(12)
.padding(24)
.backgroundColor('#FFFFFF')
.width(this.rate * 100 + '%')
.onAreaChange((oldValue: Area, newValue: Area) = > {
this.info = JSON.stringify(newValue)
})
}
this.slider()
}
.width('100%')
.height('100%')
.backgroundColor('#F1F3F5')
.justifyContent(FlexAlign.Center)
}
}
解决方案
顶部背景图被拉伸时,可以通过设置背景图片的[backgroundImageSize]属性,使得图片大小能够合理显示,达到适配效果。
布局效果
参考代码
@Entry
@Component
struct ImageClip {
build() {
// 设置背景图片的backgroundImageSize属性,使得图片大小能够合理显示
Column()
.width('100%')
.height(300)
.backgroundColor('#ccc')
.backgroundImage($r('app.media.ImageOne'))
.backgroundImageSize(ImageSize.Cover)
.backgroundImagePosition(Alignment.Center)
}
}
解决方案
在大屏上,Listitem内容会过大,页面整体浏览内容减少。可通过以下两种方法解决:
布局效果
参考代码
@Entry
@Component
struct ListLayout {
@State data: Resource[] = new Array(5).fill($r("app.media.image"))
@State breakPoint: string = 'sm'
build() {
GridRow() {
GridCol({ span: { sm: 12, md: 12, lg: 12 } }) {
List({ space: 24 }) {
ForEach(this.data, (item: Resource) = > {
ListItem() {
Image(item).margin({ left: 12, right: 12 })
}
})
}
// 设置列最小宽度和最大宽度
.lanes({ minLength: 300, maxLength: 360 }).padding(12)
}
}.onBreakpointChange((breakpoint: string) = > {
this.breakPoint = breakpoint
})
}
}
List() {
// ...
}
// 根据断点设置List列数
.lanes(this.breakPoint === 'sm' ? 1 : 2)
解决方案
在大屏上,Swiper图片显示内容过大,可以通过增加Swiper展示图片数来调整图片显示大小。外层可以使用栅格组件[GridRow],通过调用OnBreakpointChange事件,调整不同的断点下Swiper的前后边距,实现在不同屏幕尺寸上的显示不同Swiper图片数。
布局效果
参考代码
@Entry
@Component
struct SwiperLayout {
@State data: Resource[] = new Array(5).fill($r("app.media.sky"))
@State breakPoint: string = 'sm'
build() {
Row() {
GridRow() {
GridCol({ span: { sm: 12, md: 12, lg: 12 } }) {
Swiper() {
ForEach(this.data, (item: Resource) = > {
Image(item).width('100%').height(180)
})
}
.width('100%')
.itemSpace(24)
// 根据断点设置Swiper前后边距
.prevMargin(this.breakPoint === 'sm' ? 0 : 100)
.nextMargin(this.breakPoint === 'sm' ? 0 : 100)
}
}.onBreakpointChange((breakpoint: string) = > {
this.breakPoint = breakpoint
})
.height("60%")
.borderWidth(2)
}
}
}
解决方案
针对信息流单张图片过大的情况,设置[aspectRatio]和[constrainSize]属性,可以通过对图片的布局和尺寸进行约束,达到适配效果。
布局效果
参考代码
@Entry
@Component
struct ImageConstrainSize {
@State breakPoint: string = 'sm'
build() {
GridRow(){
GridCol({ span: { sm: 12, md: 12, lg: 12 } }){
Column(){
Text('一次开发,多端部署,让开发者可以基于一种设计,高效构建多端可运行的应用。一次开发,多端部署,让开发者可以基于一种设计,高效构建多端可运行的应用。')
// 设置aspectRatio和constrainSize属性,可以对图片的布局和尺寸进行约束
Image($r('app.media.ImageTwo'))
.width('30%')
.aspectRatio(0.5)
.constraintSize({ maxWidth: 240, minWidth: 180 })
Text('一次开发,多端部署,让开发者可以基于一种设计,高效构建多端可运行的应用。一次开发,多端部署,让开发者可以基于一种设计,高效构建多端可运行的应用。')
}.alignItems(HorizontalAlign.Start)
}
}.onBreakpointChange((breakpoint: string) = > {
this.breakPoint = breakpoint
})
}
}
解决方案
在大屏上,Grid组件里的4宫格图片大小过大,页面浏览区域变少。可以借助栅格行组件[GridRow]来调整不同的断点下Grid的宽度,解决大屏上Grid组件4宫格图片过大的问题。
布局效果
参考代码
@Entry
@Component
struct GridLayout {
@State data: Resource[] = new Array(4).fill($r("app.media.image"))
@State breakPoint: string = 'sm'
build() {
GridRow() {
GridCol({ span: { sm: 12, md: 12, lg: 12 } }) {
Column() {
Text('一次开发,多端部署,让开发者可以基于一种设计,高效构建多端可运行的应用。')
Grid() {
ForEach(this.data, (item: Resource) = > {
GridItem() {
Image(item).width('100%').aspectRatio(1)
}
})
}.columnsTemplate('1fr 1fr')
.columnsGap(24)
.rowsGap(24)
// 根据断点设置Grid宽度
.width(this.breakPoint === 'md' ? '60%' : '100%')
}.width('100%').alignItems(HorizontalAlign.Start)
}
}.onBreakpointChange((breakpoint: string) = > {
this.breakPoint = breakpoint
})
}
}
解决方案
在大屏上,Grid组件里的9宫格图片大小过大,页面整体浏览内容减少,可以设置Grid组件宽度和宽高比,使Grid组件保持固定大小,不会随着屏幕尺寸变化而变化。
布局效果
参考代码
`HarmonyOS与OpenHarmony鸿蒙文档籽料:mau123789是v直接拿`
@Entry
@Component
struct GridWidth {
@State data: Resource[] = new Array(9).fill($r("app.media.sky"))
build() {
Column() {
Text('一次开发,多端部署,让开发者可以基于一种设计,高效构建多端可运行的应用。')
Grid() {
ForEach(this.data, (item: Resource) = > {
GridItem() {
Image(item).width('100%').aspectRatio(1)
}
})
}
.columnsTemplate('1fr 1fr 1fr')
.columnsGap(12)
.rowsGap(12)
// 设置固定宽度和宽高比
.width(360)
.aspectRatio(1)
.padding(12)
}
.alignItems(HorizontalAlign.Start)
}
}
审核编辑 黄宇
全部0条评论
快来发表一下你的评论吧 !