非全屏 Weex 頁面開發中的 Android 適配
weex代碼中的高度和寬度的單位均為px,然而,在手機屏幕上顯示的高寬卻不一定與代碼指定的相同。原因是weex框架在底層做了針對不同屏幕的適配工作,具體計算公式為 實際高寬 = 代碼高寬 * (屏幕寬度 / 750)。
舉個例子,假設代碼中是這么寫的:
<style>
.button {
height: 100;
width: 200;
}
</style>
那么,在一款屏幕分辨率為1920*1280的Android手機上,此時的計算過程為:
height: 100 * (1080 / 750) = 144;
width: 200 * (1080 / 750) = 288。
如果我們開發的weex頁面是全屏幕的,那么這個高寬的轉換過程對我們而言是透明的,無需做額外的工作。然而一旦有一個業務場景,weex容器并非是全屏幕的,而是需要從外部傳入weex容器的高度,那么,就不得不考慮這個轉換的過程。
舉一個我在開發weex彈窗時的例子。該weex彈窗的樣式如下:
可以看到,如果不考慮多屏幕適配,頂欄和底欄都是一個固定值,那么只需要用總容器高度 - 兩個定高組件就可以了。那么需要解決的第一個問題,就是如何獲取外部容器的高度。由于weex可以通過 $getConfig().env.deviceHeight 和 $getConfig().env.deviceWidth 的形式來獲取手機屏幕的高度,因而,很自然地就想到,是否能在安卓中以屏幕的3/5的比例,約定容器高度,然后在weex代碼中,同樣通過3/5來計算容器高度。這樣就避免了去寫 Native Module 和 Method。
然而,這樣的思路是不可行的。因為Android Native的總高度,事實上是可供顯示的全屏高度,而不一定是物理屏幕的高度,因為有狀態欄,虛擬按鍵欄,Smartbar等等安卓碎片化引入的額外顯示元素,實際全屏高度很有可能小于物理屏幕高度。所以,仍然需要開發和注冊Native Module,以獲取外部容器高度。
再來看上文的計算公式:總容器高度 - 兩個定高 = scroller高度。因為多屏幕適配的原因,上面的公式是不可行的,需要改為:
外部傳入的總容器高度 - 兩個定高組件的高度字面量 * 轉換比例 = scroller實際高度
也就是說:外部傳入的總容器高度 / 轉換比例 - 兩個定高組件的高度字面量 = scroller實際高度 / 轉換比例 = scroller的字面量高度。
所以,最終的業務代碼如下所示:
ready:function() {
...
// 引入外部注冊的 Native Module;Android 和 iOS 各有其實現
var AppInfo = require('@weex-module/MSOAFoundation');
if (this.$getConfig().env.platform != "iOS") {
// 適配 Android
this.mainExtra = "mainExtraAndroid";
AppInfo.getContainerHeight(function(params) {
ratio = this.$getConfig().env.deviceWidth / 750;
this.scrollerHeight = params.height / ratio - 200;
}.bind(this));
} else {
// 適配 iPhone 4S
if (this.$getConfig().env.deviceHeight < 1000) {
this.scrollerHeight = 700;
}
}
...
}
這個坑非常的隱蔽,本質是因為:weex 默默做了A參考系轉換到B參考系的過程,然而一旦我們自力更生,試圖從B參考系獲得一個測量得到的高度,用在A參考系,而沒意識到這個隱蔽的轉換過程的時候,就會陷入到一臺機子上調好了,另一臺又跪了的尷尬局面。而且,這種情況在Android上遠較iOS要來的嚴重。因為iOS上,除了4S以外,5,5s,6,6p,6s,6sp,屏幕尺寸均為同一長寬比。因此,在一臺上調整好后,可無縫等比例放大到其他機型上。然而在Android上,毋論碎片化的屏幕尺寸,光status bar,navigation bar,smartbar等等虛擬的占用實際顯示區域的各類bar,就足夠讓weex的默認適配喝一壺的。因此,weex這種隱蔽適配的處理方式,在Android生態上是否真的合理方便,尚待商榷。
來自:https://segmentfault.com/a/1190000007073531