【HarmonyOS Next】鴻蒙應用折疊屏設備適配方案
一、前言
目前應用上架華為AGC平臺,都會被要求適配折疊屏設備。目前華為系列的折疊屏手機,有華為 Mate系列(左右折疊,華為 Mate XT三折疊),華為Pocket 系列(上下折疊)。
二、適配方案思路探討
目前鴻蒙應用適配折疊屏的思路分為兩種:分欄和全屏適配。
分欄
在左右折疊手機上,相當于首頁一級頁面在左邊,二級子頁面點開后在右邊。三折疊上形態未知,有知道的小伙伴可以同步下。
上下折疊手機上,不以分欄的方式呈現,和直板機相似。
單欄(全屏)
全屏適配并且拉伸界面,不進行界面處理。而是處理成平板的UI布局形式,和直板機界面排版不一樣。這種適配方案效果最好,但是工作量較大。
不過目前華為官方反饋說以后不演進分欄方案了。三折疊和25年三月新形態手機的適配都是風險。
三、適配方案實現
傳統的router路由在折疊屏適配上,無法提供良好支撐。所以建議切換到Navigation。
因為不管是路由回退棧的處理,還是頁面數的限制問題。Navigation都優于router,并且華為官方已經明確表示,推薦Navgation的方案。
當然如果有了解HMRouter的同學,也可以使用,因為HMRouter就是在Navgation上進行封裝和優化的三方庫。
分欄
設置主頁面容器Navigation,mode屬性為NavigationMode.Stack:
MainPage { message: string = 'Hello World';// 創建一個頁面棧對象并傳入NavigationpageStack: NavPathStack = new NavPathStack()build() {Navigation(this.pageStack) {// 頁面布局Row() {Column() {Text(this.message).fontSize(50).fontWeight(FontWeight.Bold).onClick(()=>{// 跳轉到子頁面this.pageStack.pushDestination({name: "OnePage",}, false); //該false表示不需要轉場動畫,默認是有的})}.width('100%')}.height('100%')}.mode(NavigationMode.Split)}
}
struct
細節可參考該文章,點擊跳轉=》(【HarmonyOS】關于官方推薦的組件級路由Navigation的心得體會)
單欄(全屏)
設置主頁面容器Navigation,mode屬性為NavigationMode.Stack:
MainPage { message: string = 'Hello World';// 創建一個頁面棧對象并傳入NavigationpageStack: NavPathStack = new NavPathStack()// 使用 @State 裝飾器定義響應式變量,用于存儲組件的寬高 width: number = 0 height: number = 0build() {Navigation(this.pageStack) {// 頁面布局Row() {Column() {Text(this.message).fontSize(50).fontWeight(FontWeight.Bold).onClick(()=>{// 跳轉到子頁面this.pageStack.pushDestination({name: "OnePage",}, false); //該false表示不需要轉場動畫,默認是有的})}.width('100%')}.height('100%')}// 分為三種模式,(默認)自動NavigationMode.Auto,單頁面NavigationMode.Stack和分欄NavigationMode.Split.mode(NavigationMode.Stack).backgroundColor(Color.Gray).onSizeChange((width: number, height: number) => {// 當組件大小變化時,更新寬高信息this.width = widththis.height = height}).onAreaChange( (oldValue: Area, newValue: Area)=>{// newValue.width})}
}
struct
界面需要監聽最外層寬高,onSizeChange和onAreaChange都可以,建議使用onAreaChange,用于判定界面是否需要切換為平板適配模式。【目前官方推薦使用600vp 作為當頁面寬度大于等于一定閾值點】
子頁面添加跳轉入口函數,添加NavDestination生命周期的處理:
// 跳轉頁面入口函數
export function OnePageBuilder() {OnePage()
}
struct OnePage {private TAG: string = "OnePage"; message: string = 'Hello World';pathStack: NavPathStack = new NavPathStack();build() {NavDestination() {Row() {Column() {Text(this.message).fontSize(50).fontWeight(FontWeight.Bold)}.width('100%')}.height('100%')}.onShown(()=>{console.log(this.TAG, "OnePage onShown");}).onReady((context: NavDestinationContext) => {this.pathStack = context.pathStack;})}
}
在首頁獲取到的寬高,可以使用多種方式緩存起來,例如放到AppStorage,單例中。二級等子頁面進入后就可以判定。
當然頁面中的動態監聽也需要保存。場景需要覆蓋,因為在首頁時用戶可能是折疊狀態,進入子頁面后展開的情況也有。
當然判定手機折疊屏狀態,除了通過寬高,也可通過官方提供的折疊屏狀態進行判斷,不過在上下折疊屏手機上也會被激活,這里需要額外在判定一下。
import { display } from '@kit.ArkUI';let ret: boolean = false;
// 當前是否是折疊屏
ret = display.isFoldable();if(ret){
let callback: Callback<display.FoldStatus> = (data: display.FoldStatus) => {console.info('Listening enabled. Data: ' + JSON.stringify(data));
};
display.on('foldStatusChange', callback);
}// 頁面銷毀時,記得取消監聽
display.off('foldStatusChange', callback);