设备适配
记录下开发中使用的适配,保证一套代码在手机、折叠屏、平板上有不同的样式、布局。
断点
在应用启动时获取宽度,根据不同大小进行判断。区分不同设备使用的组件属性
实现方式
//EntryAbility.ets
export default class EntryAbility extends UIAbility {
onWindowStageCreate(windowStage: window.WindowStage) {
windowStage.getMainWindow((err, data) => {
if (err.code) {
return
}
// 启动应用和窗口大小变化时计算断点
this.updateBreakpoint(data.getWindowProperties().windowRect.width)
windowClass.on('windowSizeChange', (windowSize: window.Size) => {
this.updateBreakpoint(windowSize.width)
})
})
}
// 根据宽度划分断点
private updateBreakpoint(windowWidth: number): void {
let windowWidthVp = px2vp(windowWidth)
let curBp: string = ''
const breakPoints = [320, 600, 840, 1440]
if (windowWidthVp < breakPoints[0]) {
curBp = 'xs'
} else if (windowWidthVp >= breakPoints[0] && windowWidthVp < breakPoints[1]) {
curBp = 'sm'
} else if (windowWidthVp >= breakPoints[1] && windowWidthVp < breakPoints[2]) {
curBp = 'md'
} else if (windowWidthVp >= breakPoints[2] && windowWidthVp < breakPoints[3]) {
curBp = 'lg'
} else {
curBp = 'xl'
}
AppStorage.setOrCreate('breakPoint', curBp)
}
}
断点对应设备:
- xs:穿戴式设备
- sm:手机、折叠屏手机折叠态竖屏
- md:手机、折叠屏手机横屏,折叠屏手机展开横竖屏
- lg:pad横竖屏
- xl:2in1设备
断点使用
1、tabs
平板和其它设备区分tabbar样式,平板中tabs在右侧
@StorageProp('breakPoint') currentPoint: string = 'sm'
Tabs({
index: /*tabbar索引*/,
barPosition: BarPosition.End
})
.vertical(this.breakPoint === 'lg')
2、swiper
竖屏一个item横向占满,其它设备展示第一item的右侧+完整的第二个item+第三个item的左侧
@StorageProp('breakPoint') currentPoint: string = 'sm'
// bannerElementData:swiper数据内容项
Swiper() {
}
.width(this.currentPoint === 'sm' ? '100%' : (this.bannerElementData.length > 2 ? '150%' : '100%'))
.displayCount(this.currentPoint == 'sm' ? 1 :
(this.bannerElementData.length > 2 ? 3 : 2)) // 显示几页
3、分栏
平板设备在最左侧一部分屏展示负一屏内容
SideBarContainer(SideBarContainerType.Embed) {
MinusScreenComponent()
Navigation(this.navPathStack) {
}
.mode(NavigationMode.Stack)
.hideTitleBar(true)
.navDestination(/*配置的navDestination组件*/)
}.showSideBar(this.breakPoint === 'lg')
.showControlButton(false)
1、SideBarContainer组件只能有两个子组件,第一个子组件是侧栏第二个是内容区。
2、分栏效果也可以用Navigation实现,设置mode的值为NavigationMode.Split。
栅格布局
ArkUI提供的响应式组件,根据配置的断点自适应布局。和前端的响应式布局设计相同
栅格组件GridRow和其子组件GridCol
GridRow({breakpoints: {value: ['320vp', '600vp','840vp','1440vp'],reference: BreakpointsReference.WindowSize}}){
GridCol({span: {xs: 12, sm: 6, md: 4, lg:12, xl: 12}}){
Row().height(60).backgroundColor(Color.Red).width('100%')
}
GridCol({span: {xs: 12, sm: 6, md: 4, lg:12, xl: 12}}){
Row().height(60).backgroundColor(Color.Black).width('100%')
}
GridCol({span: {xs: 12, sm: 6, md: 4, lg:12, xl: 12}}){
Row().height(60).backgroundColor(Color.Blue).width('100%')
}
}
GridRow:
- breakpoints:
- value:配置断点。例如['600vp','800vp']表示xs(0,600), sm[600,800), md[800,∞)
- reference:断点生效根据窗口尺寸或当前GirdRow的父组件尺寸
- columns:设置屏幕分多少份,默认任何大小的屏都是分12份,大屏每份更宽小屏每份更窄,也可单独为不同尺寸划分屏幕。栅格布局span的分配占用份数超出总份数(默认12)会自动换行。
GridCol:
根据GridRow划分的尺寸设置其子组件的占比。例如设备尺寸在(840,1440)区间内,对应的span设置为6,GridCol子组件宽度设置为100%也只能占6份,屏幕的一半。
value设置的断点和span对应的值并不是固定的,例如['840vp','1440vp']对应span是xs(0,840), sm[840,1440), md[1440,∞)
1、应用首页分区展示部分,手机和折叠屏手机折叠态每行展示一项,横向或双折叠展开每行展示两项,平板每行展示三项
@Builder
itemContent(param: string) {
Row() {
// 展示项内容...
}.width('100%')
}
build() {
GridRow({ breakpoints: { value: ['320vp', '600vp', '840vp'], reference: BreakpointsReference.WindowSize } }) {
ForEach(this.dataList, (item: string) => {
GridCol({
span: {
xs: 12,
sm: 12,
md: 6,
lg: 4
}
}) {
this.itemContent(item)
}
}, (item: string, index: number) => `${item}_${index}`)
}
}
2、弹窗宽度适应设备,在平板上不能和其它设备相差太大,通过控制屏幕划分份数和偏移份数保证弹窗大小和位置居中。BreakPoints的value默认是["320vp", "600vp", "840vp"]
build() {
// 默认的value有3项对应xs、sm、md、lg,这里没写的xs份数对应1
GridRow({columns: {sm: 4, md: 8, lg: 12}}) {
GridCol({span: 4, offset: {sm: 0, md: 2, lg: 4}}) {
// 弹窗内容...
}
}
}