我在Cordova应用中使用CSS变量safe-area-inset-top
处理iPhone X安全区域:
body {
padding-top: env(safe-area-inset-top);
}
在应用启动时按预期工作。但是,当我通过自定义插件进入和退出全屏(强制横向)AVPlayer并返回到肖像应用程序时,填充区消失了,我的应用程序被部分切断了。
我目前正在iOS上的插件中的AVPlayerViewController类中使用此功能。
LandscapeVideo.m
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation {
return UIInterfaceOrientationLandscapeRight; // or LandscapeLeft
}
- (UIInterfaceOrientationMask)supportedInterfaceOrientations {
return UIInterfaceOrientationMaskLandscape;
}
在此先感谢您的帮助/想法!
答案 0 :(得分:2)
如关于此答案的设备方向的注释所示: https://stackoverflow.com/a/46232813/1085272
使用uiWebView(默认设置)后,某些方向发生更改后,出现安全区域插入xxx问题。
切换到WKWebView(例如,使用cordova-plugin-wkwebview-engine
)为我解决了该问题。
答案 1 :(得分:2)
修复了iPhone X / XS屏幕旋转问题
在iPhone X / XS上,屏幕旋转将导致标题栏高度使用不正确的值,因为safe-area-inset- *的计算未及时反映UI刷新的新值。即使在最新的iOS 12中,UIWebView中也存在此错误。一种解决方法是插入一个1px的上边距,然后快速将其反转,这将触发安全区域插入*立即被重新计算。修复起来有些丑陋,但是如果您出于某种原因而不得不使用UIWebView,它就可以工作。
window.addEventListener("orientationchange", function() {
var originalMarginTop = document.body.style.marginTop;
document.body.style.marginTop = "1px";
setTimeout(function () {
document.body.style.marginTop = originalMarginTop;
}, 100);
}, false);
代码的目的是使document.body.style.marginTop稍作更改,然后将其反转。不一定必须是“ 1px”。您可以选择一个不会导致UI闪烁但可以达到其目的的值。
答案 2 :(得分:0)
感谢@pascalzon和@YYL提供有用的信息。我尝试为我的Cordova应用程序切换到WKWebView,但它只是中断了它,所以暂时我一直被uiWebview所困扰,因此也遇到了这个问题。
我希望我的应用程序在类似iPhone X的缺口设备上看起来不错,因此我在应用程序的视口声明中添加了viewport-fit=cover
,并开始使用安全区域插入功能。我的布局需求非常简单。如果上边距的值大于1rem,则必须为1rem或安全区域插入顶部。
不幸的是,CSS max()函数还不是标准功能。如果我可以使用的话,事情会更简单(假设它将所有内容转换为像素)。
:root {
--app-margin-top-default: 1rem;
--app-margin-top: max(env(safe-area-inset-top), var(--app-margin-top-default));
}
因此,我不得不在javascript中执行最大比较,然后每次屏幕方向更改时都从此处设置--app-margin-top
。
由于到目前为止,似乎还没有办法从javascript中读取CSS env vars,因此我开始在CSS中记录CSS变量中的安全区域插图,以便以后从javascript中进行访问。默认值为:
:root {
--safe-area-inset-top: 0px;
--safe-area-inset-right: 0px;
--safe-area-inset-bottom: 0px;
--safe-area-inset-left: 0px;
}
然后我将这些变量设置如下:
/* iOS 11.0: supports constant() css function. (Assume all other inset vars are supported.) */
@supports (padding-top: constant(safe-area-inset-top)) {
:root {
--safe-area-inset-top: constant(safe-area-inset-top, 0);
--safe-area-inset-right: constant(safe-area-inset-right, 0);
--safe-area-inset-bottom: constant(safe-area-inset-bottom, 0);
--safe-area-inset-left: constant(safe-area-inset-left, 0);
}
}
/* iOS 11.2 and latest Chrome webviews support the env() css function. (Assume all other inset vars are supported.) */
@supports (padding-top: env(safe-area-inset-top)) {
:root {
--safe-area-inset-top: env(safe-area-inset-top, 0);
--safe-area-inset-right: env(safe-area-inset-right, 0);
--safe-area-inset-bottom: env(safe-area-inset-bottom, 0);
--safe-area-inset-left: env(safe-area-inset-left, 0);
}
}
每次屏幕方向改变时,我都会将--safe-area-inset-top
与--app-margin-top-default
进行比较,并将--app-margin-top
设置为这些值的最大值。那时我遇到了这个问题。屏幕方向更改和我的CSS安全区域插入变量被更新之间似乎存在滞后。因此我的边距设置代码无效。
我尝试了YYL的技巧来强制重新计算安全区域插图,但是似乎没有用。插图最终进行了更新,但是在我的屏幕方向更改事件侦听器完成执行:(
我的解决方案
此解决方案依赖于cordova屏幕方向插件:
https://cordova.apache.org/docs/en/latest/reference/cordova-plugin-screen-orientation/
唯一可以依靠正确的安全区域插入值的时间是在应用程序启动时,因此我将它们记录在app
对象内部的一组javascript变量中:
safeAreaInsetNorth: undefined,
safeAreaInsetEast: undefined,
safeAreaInsetSouth: undefined,
safeAreaInsetWest: undefined,
在启动时设置这些变量的方法会考虑屏幕方向。
console.log("Screen orientation at startup is: " +screen.orientation.type);
let $root = $(":root");
// Notch/North at the top.
if (screen.orientation.type.match("portrait-primary")) {
app.safeAreaInsetNorth = $root.css("--safe-area-inset-top");
app.safeAreaInsetEast = $root.css("--safe-area-inset-right");
app.safeAreaInsetSouth = $root.css("--safe-area-inset-bottom");
app.safeAreaInsetWest = $root.css("--safe-area-inset-left");
}
// Upside down... Notch/North at the bottom.
else if (screen.orientation.type.match("portrait-secondary")) {
app.safeAreaInsetNorth = $root.css("--safe-area-inset-bottom");
app.safeAreaInsetEast = $root.css("--safe-area-inset-left");
app.safeAreaInsetSouth = $root.css("--safe-area-inset-top");
app.safeAreaInsetWest = $root.css("--safe-area-inset-right");
}
// Notch/North to the left.
else if (screen.orientation.type.match("landscape-primary")) {
app.safeAreaInsetNorth = $root.css("--safe-area-inset-left");
app.safeAreaInsetEast = $root.css("--safe-area-inset-top");
app.safeAreaInsetSouth = $root.css("--safe-area-inset-right");
app.safeAreaInsetWest = $root.css("--safe-area-inset-bottom");
}
// Notch/North to the right.
else if (screen.orientation.type.match("landscape-secondary")) {
app.safeAreaInsetNorth = $root.css("--safe-area-inset-right");
app.safeAreaInsetEast = $root.css("--safe-area-inset-bottom");
app.safeAreaInsetSouth = $root.css("--safe-area-inset-left");
app.safeAreaInsetWest = $root.css("--safe-area-inset-top");
} else {
throw "I have no idea which way up I am!";
}
在启动时,然后每次屏幕方向改变时,我都会再次检查是否需要像这样更新--app-margin-top
:
let marginTopDefault = app.getGlobalCssVariableInPx("--app-margin-top-default");
let newMarginTop = undefined;
switch(screen.orientation.type) {
case "portrait-primary": // Notch/North at the top.
newMarginTop = app.safeAreaInsetNorth;
break;
case "portrait-secondary": // Upside down... Notch/North at the bottom.
newMarginTop = app.safeAreaInsetSouth;
break;
case "landscape-primary": // Notch/North to the left.
newMarginTop = app.safeAreaInsetEast;
break;
case "landscape-secondary": // Notch/North to the right.
newMarginTop = app.safeAreaInsetWest;
break;
default:
throw "No idea which way up I am!";
}
app.getGlobalCssVariableInPx
是一个辅助函数,通过将rems乘以基本字体大小将rems转换为像素。
然后我将marginTopDefault
和newMarginTop
转换为整数,找到最大值并将--app-margin-top
设置为此。
$(":root").css("--app-margin-top", Math.max(marginTopDefault, newMarginTop) + "px");
结论
我想我已经描述得足够好了。要使一些本来可以工作的工作变得很混乱,但是嘿。有时候就是这样。而且我不是HTML5专家,所以可能有一些方法可以使之更简单。