六、一次开发多端部署——多设备响应式布局
开发应用时不能仅仅考虑手机,还应考虑其他应用设备的布局。
(一)实现原理
在去渲染页面时,应动态判断当前设备屏幕的大小,根据屏幕大小不同去渲染不同效果。
利用媒体查询技术可以知道当前设备的具体大小情况。
(二)代码实现
目录:
1.定义一些需要的静态常量
/*BreakpointConstants*/
import BreakpointType from '../bean/BreanpointType';
export default class BreakpointConstants {
/**
* 小屏幕设备的 Breakpoints 标记.
*/
static readonly BREAKPOINT_SM: string = 'sm';
/**
* 中等屏幕设备的 Breakpoints 标记.
*/
static readonly BREAKPOINT_MD: string = 'md';
/**
* 大屏幕设备的 Breakpoints 标记.
*/
static readonly BREAKPOINT_LG: string = 'lg';
/**
* 当前设备的 breakpoints 存储key
*/
static readonly CURRENT_BREAKPOINT: string = 'currentBreakpoint';
/**
* 小屏幕设备宽度范围.
*/
static readonly RANGE_SM: string = '(320vp<=width<600vp)';
/**
* 中屏幕设备宽度范围.
*/
static readonly RANGE_MD: string = '(600vp<=width<840vp)';
/**
* 大屏幕设备宽度范围.
*/
static readonly RANGE_LG: string = '(840vp<=width)';
static readonly BAR_POSITION: BreakpointType<BarPosition> = new BreakpointType({
sm: BarPosition.End,
md: BarPosition.Start,
lg: BarPosition.Start,
})
}
2.媒体查询
/*BreakpointSystem*/
import mediaQuery from '@ohos.mediaquery'
import BreakpointConstants from '../constants/BreakpointConstants'
export default class BreakpointSystem{
//监听
private smListener: mediaQuery.MediaQueryListener = mediaQuery.matchMediaSync(BreakpointConstants.RANGE_SM)
private mdListener: mediaQuery.MediaQueryListener = mediaQuery.matchMediaSync(BreakpointConstants.RANGE_MD)
private lgListener: mediaQuery.MediaQueryListener = mediaQuery.matchMediaSync(BreakpointConstants.RANGE_LG)
//回调函数
smListenerCallback(result: mediaQuery.MediaQueryResult){
if(result.matches){
this.updateCurrentBreakpoint(BreakpointConstants.BREAKPOINT_SM)
}
}
mdListenerCallback(result: mediaQuery.MediaQueryResult){
if(result.matches){
this.updateCurrentBreakpoint(BreakpointConstants.BREAKPOINT_MD)
}
}
lgListenerCallback(result: mediaQuery.MediaQueryResult){
if(result.matches){
this.updateCurrentBreakpoint(BreakpointConstants.BREAKPOINT_LG)
}
}
updateCurrentBreakpoint(breakpoint: string){
AppStorage.SetOrCreate(BreakpointConstants.CURRENT_BREAKPOINT, breakpoint)
}
//注册回调
register(){
this.smListener.on('change', this.smListenerCallback.bind(this))
this.mdListener.on('change', this.mdListenerCallback.bind(this))
this.lgListener.on('change', this.lgListenerCallback.bind(this))
}
//取消回调
unregister(){
this.smListener.off('change', this.smListenerCallback.bind(this))
this.mdListener.off('change', this.mdListenerCallback.bind(this))
this.lgListener.off('change', this.lgListenerCallback.bind(this))
}
}
3.横向——纵向布局
/*BreakpointTypeOptions*/
/**
* 断点类型(动态)
*/
declare interface BreakpointTypeOptions<T>{
sm?:T,
md?:T,
lg?:T
}
export default class BreakpointType<T>{
options: BreakpointTypeOptions<T>
constructor(options: BreakpointTypeOptions<T>) {
this.options = options
}
getValue(breakpoint: string): T{
return this.options[breakpoint]
}
}
/*Index*/
private breakpointSystem: BreakpointSystem = new BreakpointSystem()
@StorageProp('currentBreakpoint') currentBreakpoint: string = BreakpointConstants.BREAKPOINT_SM
aboutToAppear(){
this.breakpointSystem.register()
}
aboutToDisappear(){
this.breakpointSystem.unregister()
}
previewer:
4.卡片滑动——平铺
Swiper的.displayCount()属性可改变滑动(括号内为1时)或平铺(括号内为2时)。
/*StatsCard*/
import DatePickDialog from './DatePickDialog'
@Component
export default struct StatsCard {
@StorageProp('selectedDate') selectedDate: number = DateUtil.beginTimeOfDay(new Date())
@StorageProp('currentBreakpoint') currentBreakpoint: string = BreakpointConstants.BREAKPOINT_SM
controller: CustomDialogController = new CustomDialogController({
builder: DatePickDialog({selectedDate: new Date(this.selectedDate)})//把获取的日期值传回,使下次打开时依旧保存(注意将number类型转回日期类型)
})
build() {
Column(){
// 1.日期信息
Row(){
Text(DateUtil.formatDate(this.selectedDate))//格式化为日期字符串
.fontColor($r('app.color.secondary_color'))
Image($r('app.media.ic_public_spinner'))
.width(20)
.fillColor($r('app.color.secondary_color'))
}
.padding(CommonConstants.SPACE_8)
.onClick(() => this.controller.open())
// 2.统计信息
Swiper(){
// 2.1.热量统计
CalorieStats({intake: this.info.intake, expend: this.info.expend})
// 2.2.营养素统计
NutrientStats({carbon: this.info.carbon, protein: this.info.protein, fat: this.info.fat})
}
.width('100%')
.backgroundColor(Color.White)
.borderRadius(CommonConstants.DEFAULT_18)
.indicatorStyle({selectedColor: $r('app.color.primary_color')})//穿梭框样式属性
.displayCount(new BreakpointType({
sm: 1,
md: 1,
lg: 2
}).getValue(this.currentBreakpoint))
}
.width(CommonConstants.THOUSANDTH_940)//占总宽度的94%
.backgroundColor($r('app.color.stats_title_bgc'))
.borderRadius(CommonConstants.DEFAULT_18)//使卡片有圆弧
}
}
previewer: