大家好,我是 V 哥,
在鴻蒙6開發中,屏幕方向適配是提升用户體驗的重要環節。下面我將通過一個完整的視頻播放器示例,詳細講解ArkTS中橫豎屏切換的實現方案。
聯繫V哥獲取 鴻蒙學習資料
一、基礎概念理解
1.1 屏幕方向類型
鴻蒙系統支持四種屏幕方向:
- PORTRAIT(豎屏):屏幕高度大於寬度
- LANDSCAPE(橫屏):屏幕寬度大於高度
- PORTRAIT_INVERTED(反向豎屏)
- LANDSCAPE_INVERTED(反向橫屏)
1.2 適配策略
- 靜態配置:通過配置文件鎖定基礎方向
- 動態調整:運行時感知設備旋轉並智能適配
二、靜態配置實現
2.1 修改module.json5配置
在src/main/module.json5文件中配置UIAbility的方向屬性:
{
"module": {
"abilities": [
{
"name": "EntryAbility",
"orientation": "landscape", // 可選:portrait|landscape|unspecified
"metadata": [
{
"name": "ohos.ability.orientation",
"value": "$profile:orientation"
}
]
}
]
}
}
參數説明:
portrait:鎖定豎屏landscape:鎖定橫屏unspecified:跟隨系統(默認)
三、動態橫豎屏切換實現
3.1 創建方向工具類
新建utils/OrientationUtil.ets文件:
// OrientationUtil.ets
import window from '@ohos.window';
import display from '@ohos.display';
export class OrientationUtil {
// 設置窗口方向
static async setPreferredOrientation(windowClass: window.Window, orientation: window.Orientation) {
try {
await windowClass.setPreferredOrientation(orientation);
console.info('屏幕方向設置成功:', orientation);
} catch (error) {
console.error('設置屏幕方向失敗:', error);
}
}
// 獲取當前設備方向
static getCurrentOrientation(): string {
const displayInfo = display.getDefaultDisplaySync();
return displayInfo.width > displayInfo.height ? 'landscape' : 'portrait';
}
// 橫屏模式配置
static readonly LANDSCAPE: window.Orientation = window.Orientation.LANDSCAPE;
// 豎屏模式配置
static readonly PORTRAIT: window.Orientation = window.Orientation.PORTRAIT;
// 跟隨傳感器自動旋轉(受旋轉鎖控制)
static readonly FOLLOW_SENSOR: window.Orientation = window.Orientation.FOLLOW_SENSOR;
}
3.2 視頻播放頁面實現
創建pages/VideoPlayback.ets主頁面:
// VideoPlayback.ets
import { OrientationUtil } from '../utils/OrientationUtil';
import window from '@ohos.window';
import common from '@ohos.app.ability.common';
import mediaquery from '@ohos.mediaquery';
@Entry
@Component
struct VideoPlayback {
@State currentOrientation: string = 'portrait';
@State isFullScreen: boolean = false;
private context: common.UIContext = getContext(this) as common.UIContext;
private windowClass: window.Window | null = null;
private mediaQueryListener: mediaquery.MediaQueryListener | null = null;
// 頁面初始化
aboutToAppear() {
this.initWindow();
this.setupOrientationListener();
}
// 初始化窗口
async initWindow() {
try {
this.windowClass = await window.getLastWindow(this.context);
AppStorage.setOrCreate('windowClass', this.windowClass);
this.currentOrientation = OrientationUtil.getCurrentOrientation();
} catch (error) {
console.error('窗口初始化失敗:', error);
}
}
// 設置方向監聽器
setupOrientationListener() {
// 監聽窗口尺寸變化
this.windowClass?.on('windowSizeChange', () => {
this.currentOrientation = OrientationUtil.getCurrentOrientation();
console.info('屏幕方向變化:', this.currentOrientation);
});
// 媒體查詢監聽橫屏事件
const mediaQuery = mediaquery.matchMediaSync('(orientation: landscape)');
this.mediaQueryListener = mediaQuery;
mediaQuery.on('change', (result: mediaquery.MediaQueryResult) => {
if (result.matches) {
console.info('當前為橫屏模式');
} else {
console.info('當前為豎屏模式');
}
});
}
// 切換全屏/豎屏模式
async toggleFullScreen() {
if (!this.windowClass) return;
if (this.isFullScreen) {
// 退出全屏,切換回豎屏
await OrientationUtil.setPreferredOrientation(this.windowClass, OrientationUtil.PORTRAIT);
this.isFullScreen = false;
} else {
// 進入全屏,切換為橫屏並跟隨傳感器
await OrientationUtil.setPreferredOrientation(this.windowClass, OrientationUtil.FOLLOW_SENSOR);
this.isFullScreen = true;
}
}
// 鎖定橫屏(不受傳感器影響)
async lockLandscape() {
if (this.windowClass) {
await OrientationUtil.setPreferredOrientation(this.windowClass, OrientationUtil.LANDSCAPE);
}
}
// 頁面佈局
build() {
Column() {
// 標題欄
Row() {
Text('視頻播放器')
.fontSize(20)
.fontColor(Color.White)
}
.width('100%')
.height(60)
.backgroundColor('#007DFF')
.justifyContent(FlexAlign.Start)
.padding({ left: 20 })
// 視頻播放區域
Column() {
if (this.currentOrientation === 'landscape') {
this.LandscapeVideoContent()
} else {
this.PortraitVideoContent()
}
}
.layoutWeight(1)
// 控制按鈕區域(豎屏時顯示)
if (this.currentOrientation === 'portrait') {
Column() {
Button(this.isFullScreen ? '退出全屏' : '進入全屏')
.width('90%')
.height(40)
.backgroundColor('#007DFF')
.fontColor(Color.White)
.onClick(() => this.toggleFullScreen())
Button('鎖定橫屏')
.width('90%')
.height(40)
.margin({ top: 10 })
.backgroundColor('#FF6A00')
.fontColor(Color.White)
.onClick(() => this.lockLandscape())
}
.width('100%')
.padding(10)
}
}
.width('100%')
.height('100%')
.backgroundColor('#F5F5F5')
}
// 橫屏內容佈局
@Builder LandscapeVideoContent() {
Column() {
// 模擬視頻播放器
Stack() {
Image($r('app.media.video_poster'))
.width('100%')
.height(300)
.objectFit(ImageFit.Contain)
// 橫屏控制條
Row() {
Button('退出全屏')
.width(100)
.height(30)
.backgroundColor(Color.Orange)
.fontColor(Color.White)
.onClick(() => this.toggleFullScreen())
}
.width('100%')
.justifyContent(FlexAlign.End)
.padding(10)
}
// 視頻信息
Text('當前模式:橫屏全屏播放')
.fontSize(16)
.margin({ top: 20 })
}
}
// 豎屏內容佈局
@Builder PortraitVideoContent() {
Column() {
// 模擬視頻播放器
Image($r('app.media.video_poster'))
.width('100%')
.height(200)
.objectFit(ImageFit.Cover)
// 視頻信息
Text('視頻標題:鴻蒙開發教程')
.fontSize(18)
.margin({ top: 10 })
Text('視頻描述:學習ArkTS橫豎屏適配')
.fontSize(14)
.margin({ top: 5 })
.fontColor(Color.Gray)
}
.padding(10)
}
// 頁面銷燬
aboutToDisappear() {
this.mediaQueryListener?.off('change');
this.windowClass?.off('windowSizeChange');
}
}
3.3 EntryAbility配置
更新entryability/EntryAbility.ets:
// EntryAbility.ets
import UIAbility from '@ohos.app.ability.UIAbility';
import window from '@ohos.window';
import hilog from '@ohos.hilog';
export default class EntryAbility extends UIAbility {
onCreate(want: Want, launchParam: AbilityConstant.LaunchParam) {
hilog.info(0x0000, 'EntryAbility', 'Ability onCreate');
}
onWindowStageCreate(windowStage: window.WindowStage) {
hilog.info(0x0000, 'EntryAbility', 'Ability onWindowStageCreate');
// 設置窗口方向為跟隨傳感器
windowStage.getMainWindow((err, windowClass) => {
if (err) {
hilog.error(0x0000, 'EntryAbility', 'Failed to get main window');
return;
}
// 初始設置為豎屏,但允許跟隨傳感器旋轉
windowClass.setPreferredOrientation(window.Orientation.FOLLOW_SENSOR);
});
windowStage.loadContent('pages/VideoPlayback', (err, data) => {
if (err) {
hilog.error(0x0000, 'EntryAbility', 'Failed to load the content.');
}
});
}
}
四、關鍵技術與原理分析
4.1 方向控制原理
- setPreferredOrientation:核心方法,控制窗口顯示方向
- FOLLOW_SENSOR:跟隨傳感器自動旋轉,受系統旋轉鎖控制
- 媒體查詢:監聽屏幕方向變化事件
4.2 佈局適配技巧
使用條件渲染和Flex佈局實現響應式設計:
// 響應式佈局示例
build() {
Column() {
if (this.currentOrientation === 'landscape') {
// 橫屏佈局
Row() {
// 左右分欄
}
} else {
// 豎屏佈局
Column() {
// 上下分欄
}
}
}
}
五、完整項目結構
entry/src/main/ets/
├── entryability/EntryAbility.ets
├── pages/VideoPlayback.ets
├── utils/OrientationUtil.ets
└── resources/ // 資源文件
六、測試與調試要點
- 真機測試:在鴻蒙設備上測試旋轉效果
- 旋轉鎖定:測試系統旋轉開關的影響
- 摺疊屏適配:考慮摺疊態和展開態的不同場景
七、常見問題解決
問題1:旋轉後佈局錯亂
解決:使用媒體查詢監聽方向變化,動態調整佈局
問題2:旋轉動畫卡頓
解決:優化佈局計算,避免複雜操作在旋轉時執行
這個完整示例涵蓋了鴻蒙6中ArkTS橫豎屏適配的核心技術點,適合初學者逐步學習和實踐。