博客 / 詳情

返回

【鴻蒙開發實戰篇】鴻蒙6開發視頻播放器的屏幕方向適配問題

大家好,我是 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. 旋轉鎖定:測試系統旋轉開關的影響
  3. 摺疊屏適配:考慮摺疊態和展開態的不同場景

七、常見問題解決

問題1:旋轉後佈局錯亂
解決:使用媒體查詢監聽方向變化,動態調整佈局

問題2:旋轉動畫卡頓
解決:優化佈局計算,避免複雜操作在旋轉時執行

這個完整示例涵蓋了鴻蒙6中ArkTS橫豎屏適配的核心技術點,適合初學者逐步學習和實踐。

user avatar
0 位用戶收藏了這個故事!

發佈 評論

Some HTML is okay.