1. 前言
断点,可以理解为划分不同屏幕尺寸的工具,也可以理解为将屏幕尺寸归为一个范围点。做断点的目的是,方便我们在不同屏幕尺寸的鸿蒙设备下实现响应式UI布局。何为响应式布局,我的理解是,屏幕尺寸变化,你的UI会发生变化,以实现最佳的视觉效果,这就是响应式布局。
2. 核心思路
- 用媒体查询接口做横竖屏切换功能。
- 根据官方文档推荐的vp尺寸,合理划分屏幕所处的断点,例如:'xs' | 'sm' | 'md' | 'lg' | 'xl' | 'xxl'。
- UI依据断点的变化,布局发生变化。
3. 核心代码
// 获取屏幕纵向断点str
getHeightBreakpointStr() {
// HEIGHT_SM 0 窗口高宽比小于0.8。
// HEIGHT_MD 1 窗口高宽比大于等于0.8,且小于1.2。
// HEIGHT_LG 2 窗口高宽比大于等于1.2。
const heightBreakpoint = this.getUIContext().getWindowHeightBreakpoint()
console.info(` heightBreakpoint: ${heightBreakpoint}`);
switch (heightBreakpoint) {
case 0:
this.heightBreakpoint = "sm"
break;
case 1:
this.heightBreakpoint = "md"
break;
case 2:
this.heightBreakpoint = "lg"
break;
default:
break;
}
this.heightBreakpoint
}
// 获取屏幕横向断点str
getWidthBreakpointStr() {
// 获取当前实例所在窗口的宽度断点枚举值
// WIDTH_XS 0 窗口宽度小于320vp。
// WIDTH_SM 1 窗口宽度大于等于320vp,且小于600vp。
// WIDTH_MD 2 窗口宽度大于等于600vp,且小于840vp。
// WIDTH_LG 3 窗口宽度大于等于840vp,且小于1440vp。
// WIDTH_XL 4 窗口宽度大于等于1440vp。
const widthBreakpoint = this.getUIContext().getWindowWidthBreakpoint()
console.info(` widthBreakpoint: ${widthBreakpoint}`);
switch (widthBreakpoint) {
case 0:
this.widthBreakpoint = "xs"
break;
case 1:
this.widthBreakpoint = "sm"
break;
case 2:
this.widthBreakpoint = "md"
break;
case 3:
this.widthBreakpoint = "lg"
break;
case 4:
this.widthBreakpoint = "xl"
break;
default:
break;
}
}
4. 运行效果


5. 完整代码
Index.ets
import { mediaquery, window } from '@kit.ArkUI';
type BreakpointType = 'xs' | 'sm' | 'md' | 'lg' | 'xl' | 'xxl';
@Entry
@ComponentV2
struct Index {
@Local currentState: string = ""
listener: mediaquery.MediaQueryListener =
this.getUIContext().getMediaQuery().matchMediaSync('(orientation: landscape)');
// 获取当前应用的UIAbility上下文
context = this.getUIContext().getHostContext()!;
@Local widthBreakpoint: BreakpointType = "xs"
@Local heightBreakpoint: BreakpointType = "xs"
aboutToAppear(): void {
// 监听屏幕方向改变
this.getCurrentOrientation()
}
// 获取屏幕纵向断点str
getHeightBreakpointStr() {
// HEIGHT_SM 0 窗口高宽比小于0.8。
// HEIGHT_MD 1 窗口高宽比大于等于0.8,且小于1.2。
// HEIGHT_LG 2 窗口高宽比大于等于1.2。
const heightBreakpoint = this.getUIContext().getWindowHeightBreakpoint()
console.info(` heightBreakpoint: ${heightBreakpoint}`);
switch (heightBreakpoint) {
case 0:
this.heightBreakpoint = "sm"
break;
case 1:
this.heightBreakpoint = "md"
break;
case 2:
this.heightBreakpoint = "lg"
break;
default:
break;
}
this.heightBreakpoint
}
// 获取屏幕横向断点str
getWidthBreakpointStr() {
// 获取当前实例所在窗口的宽度断点枚举值
// WIDTH_XS 0 窗口宽度小于320vp。
// WIDTH_SM 1 窗口宽度大于等于320vp,且小于600vp。
// WIDTH_MD 2 窗口宽度大于等于600vp,且小于840vp。
// WIDTH_LG 3 窗口宽度大于等于840vp,且小于1440vp。
// WIDTH_XL 4 窗口宽度大于等于1440vp。
const widthBreakpoint = this.getUIContext().getWindowWidthBreakpoint()
console.info(` widthBreakpoint: ${widthBreakpoint}`);
switch (widthBreakpoint) {
case 0:
this.widthBreakpoint = "xs"
break;
case 1:
this.widthBreakpoint = "sm"
break;
case 2:
this.widthBreakpoint = "md"
break;
case 3:
this.widthBreakpoint = "lg"
break;
case 4:
this.widthBreakpoint = "xl"
break;
default:
break;
}
}
/// 获取当前方向状态
getCurrentOrientation() {
this.listener.on('change', (mediaQueryResult: mediaquery.MediaQueryResult) => {
console.log("监听结果" + mediaQueryResult.media)
this.getWidthBreakpointStr()
this.getHeightBreakpointStr()
if (mediaQueryResult.matches) {
this.currentState = "横屏"
} else {
this.currentState = "竖屏"
}
});
}
/// 切换横屏
switchToLandscape() {
// 获取应用的最后一个窗口实例
window.getLastWindow(this.context).then((lastWindow) => {
// 根据参数设置窗口首选方向:横屏
lastWindow.setPreferredOrientation(window.Orientation.LANDSCAPE)
});
}
/// 切换竖屏
switchToPortrait() {
// 获取应用的最后一个窗口实例
window.getLastWindow(this.context).then((lastWindow) => {
// 根据参数设置窗口首选方向:竖屏
lastWindow.setPreferredOrientation(window.Orientation.PORTRAIT)
});
}
build() {
Column({ space: this.currentState == "横屏" ? 20 : 50 }) {
Text("响应式布局:断点+媒体查询")
.fontSize(this.currentState == "横屏" ? 16 : 24)
.fontWeight(FontWeight.Bold)
Column({ space: 30 }) {
Text("宽度断点" + this.widthBreakpoint)
.fontSize(30)
.fontWeight(FontWeight.Bold)
Text("纵向断点" + this.heightBreakpoint)
.fontSize(30)
.fontWeight(FontWeight.Bold)
Text("当前的状态:" + this.currentState)
.fontSize(30)
.fontWeight(FontWeight.Bold)
}
Column({ space: 20 }) {
Button("点击切换横屏")
.onClick(() => {
this.switchToLandscape()
})
.backgroundColor(this.currentState == "横屏" ? Color.Black : Color.Blue)
Button("点击切换竖屏")
.onClick(() => {
this.switchToPortrait()
})
.backgroundColor(this.currentState == "横屏" ? Color.Black : Color.Blue)
}
Row({ space: this.widthBreakpoint == "sm" ? 20 : 50 }) {
Image($r('app.media.startIcon'))
.width(this.widthBreakpoint == "sm" ? 20 : 50)
Image($r('app.media.startIcon'))
.width(this.widthBreakpoint == "sm" ? 20 : 50)
Image($r('app.media.startIcon'))
.width(this.widthBreakpoint == "sm" ? 20 : 50)
Image($r('app.media.startIcon'))
.width(this.widthBreakpoint == "sm" ? 20 : 50)
Image($r('app.media.startIcon'))
.width(this.widthBreakpoint == "sm" ? 20 : 50)
Image($r('app.media.startIcon'))
.width(this.widthBreakpoint == "sm" ? 20 : 50)
Image($r('app.media.startIcon'))
.width(this.widthBreakpoint == "sm" ? 20 : 50)
}
.justifyContent(FlexAlign.Center)
.width("100%")
}
.justifyContent(FlexAlign.Center)
.width("100%")
.height("100%")
}
}
觉得有帮助,可以点赞或收藏