将介绍 Weex 适配不同尺寸屏幕的方法以及横竖屏动态切换时如何自适应。
以 iOS 为例,在应用启动时,Weex 获取当前屏幕宽度作为全局默认值。在 iOS 系统上该宽度为实际像素/屏幕比例后的 UIKit 宽度。比如 iPhone6 为 375。
@implementation WXCoreBridge
+ (void)install
{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
WeexCore::WXCoreEnvironment* env = WeexCore::WXCoreEnvironment::getInstance();
env->SetPlatform(OS_iOS);
env->AddOption("scale", "1");
CGSize screenSize = [UIScreen mainScreen].bounds.size;
env->SetDeviceWidth(std::to_string(screenSize.width));
env->SetDeviceHeight(std::to_string(screenSize.height));
...
...
}
创建的每个 WXSDKInstance,其默认的 viewPortWidth 为 750px。
// The default screen width which helps us to calculate the real size or scale in different devices.
static const CGFloat WXDefaultScreenWidth = 750.0;
当指定 CSS 样式值为 “375px” 时,Weex 在接收到该样式后,自动根据当前屏幕宽度和当前 Instance 的 viewPortWidth 计算出在 iOS 系统上,对应的 UIKit 坐标值为:
dimension(UIKit) = dimensionPx(CSS) / viewPortWidth(instance) * globalScreenWidth
代入后: dimension(UIKit) = 375 / 750 * 375 = 187.5
之后 Weex 排版引擎使用 187.5 来排版,并最终将排版后的结果设置给 iOS UIView。之后没有坐标转换过程了。
setViewport(options)
0.20.0+ & Android Only
,表示layout引擎在布局时会忽略小数点导致的误差;若发现组件拼接处有缝隙,可以将 roundOffDeviation 设置为false,此时layout引擎将自动填补小数点误差,默认值为 true。0.25.0+
)Weex 容器默认的宽度 (viewport) 是 750px,通过 setViewport 方法可以改变页面的显示宽度,仅对当前页面生效。
在weex工程实例化之前设置该API内参数deviceWidth
meta.setViewport({
width: 750,//UI设计图的渲染标准默认750px
deviceWidth: [number],//设置数字类型参数
roundOffDeviation: false,
reserveCssStyles: true
});
(1)需要注意的是:只有在页面渲染开始之前设置 viewport 才会生效。 也就是说,setViewport 方法只能在入口文件中使用,而且要在 new Vue(…) 之前调用;如果是在组件中使用,就只有在渲染到该组件的时候才会执行相应的代码,此时页面已经处于渲染过程中,设置 viewport 将不会再生效。
(2)宽度和高度的单位默认是 px,暂不支持其他单位。
/**
* entry.js(入口文件)
*/
const meta = weex.requireModule("meta");
const storage = weex.requireModule("storage");
const screenMstrice = weex.requireModule("screen-metrics");
let eWidth
if(screenMstrice){
eWidth = screenMstrice.getScreenRealWidth();
}else{
eWidth = weex.config.env.deviceWidth
}
meta.setViewport({
width: 750,
deviceWidth: eWidth,
roundOffDeviation: false,
reserveCssStyles: true
});
//由于是回调函数形式,且new Vue()需要在设置生效后执行,因此,将该文件的其余处理都放置在此回调内执行
...
new Vue(Vue.util.extend({ el: "#root", router, store }, App));
...
/*示例tabbar.vue*/
const context = weex.requireModule("context")
const storage = weex.requireModule("storage")
const screenMstrice = weex.requireModule('screen-metrics')
/*下边为两个相关处理函数*/
/*处理选中状态的函数*/
initState () {
var baseURL = weex.config.bundleUrl.replace(/\/weex\/index.weex.js\/?.*/, '')
this.tabLength = this.tabItems.length;
for (let i = 0; i < this.tabLength; i++) {
this.tabItems[i].src = baseURL + this.tabItems[i].src
if (this.tabItems[i].visibility == "visible") {
this.selectedIndex = i;
}
}
/*在将新的选中tab页的index送去下一函数处理前,判断是否折叠操作,取值成功且为yes便使用缓存内的最后一次页面index*/
storage.getItem("IsTabPage", (event) => {
if (event.result == 'success' && event.data == 'yes') {
this.selectedIndex = context.sessionGetString('tabSelIndex')
this.select(this.selectedIndex);
} else {
this.select(this.selectedIndex);
}
})
}
/*tabbar底部按钮点击事件*/
tabItemOnClick(e){
/*切换tab页同时主动存储当前屏幕渲染页面宽度*/
storage.getItem("CurrentScreenWidth", (event) => {
// vue实例化前设置viewport,判断该值是否存在就说明是否发生了折叠屏事件
if (event.result != "success") {
storage.setItem('CurrentScreenWidth', screenMstrice.getScreenRealWidth(), event => {})
}
});
/*存储每次点击后的选中index*/
context.sessionSetString('tabSelIndex', e.index)
}
1、上述提到weex自身模块storage使用字段CurrentScreenWidth、IsTabPage是安卓sdk设定好的。
2、模块screen-metrics是安卓原生自定义模块。
3、该方案仅供安卓使用。
4、若ios报错没有screen-metrics模块,可自行注册。或者对应的方法可判断ios环境不执行。