最近遇到一個奇怪的問題,在 iPhone 7P 上韭脊,用戶在打開某些活動頁面時童谒,截圖會讓 h5 向上竄,導(dǎo)致頂部被遮擋沪羔。如果是截圖導(dǎo)致的饥伊,后續(xù)滑動 h5 還可以恢復(fù)。如圖
分析
首先 iOS 沒有監(jiān)聽截圖事件蔫饰,不會主動執(zhí)行自己邏輯琅豆; WebView 位置是用約束實現(xiàn)的。頂部約束等于 vc.view 的安全區(qū)頂部對齊篓吁,布局是沒有問題的茫因。
拿到真機(jī)后,查看了 View 視圖發(fā)現(xiàn)是安全區(qū)的 y 坐標(biāo)變化了杖剪。正確的時候是
<UIView: 0x102708ef0; frame = (0 64; 375 812); autoresize = W+H; layer = <CALayer: 0x281087920>>
而截圖后的表現(xiàn)是:
<UIView: 0x104f0c0d0; frame = (0 20; 390 844); autoresize = W+H; layer = <CALayer: 0x281d20b00>>
這是為何冻押?截圖是怎么影響安全區(qū)布局的。一頭霧水盛嘿,然后通過偉大的二分法洛巢,最后確認(rèn)是我們 WebView 頁面里有個自定義導(dǎo)航欄的操作導(dǎo)致的。
[self.navigationController.navigationBar setBackgroundImage:newImage forBarMetrics:UIBarMetricsDefault];
注釋掉就不會有問題次兆。而且在劉海屏上也沒有問題稿茉,我只能把此問題定義為 iOS 的 bug(iOS 14 也存在的)。
回到頂部
過了幾天有開發(fā)反饋說芥炭,點擊 statusbar (觸發(fā)返回頂部)狈邑,后續(xù)滾動操作都無法恢復(fù)。最后的 bug 表現(xiàn)是一樣的蚤认。但相對于截圖客戶端沒有做任何監(jiān)聽邏輯,scrollToTop
似乎還有些發(fā)掘的空間糕伐。
我大概找了下影響 view 安全邊界的一些 VC 參數(shù)砰琢,edgesForExtendedLayout
, extendedLayoutIncludesOpaqueBars
,進(jìn)而了解的他們對 self.navigationController.navigationBar.translucent
參數(shù)的影響,其中有一條:
When the navigation bar is translucent, configure the edgesForExtendedLayout and extendedLayoutIncludesOpaqueBarsproperties of your view controller to display your content underneath the navigation bar.
If the navigation bar doesn't have a custom background image, or if any pixel of the background image has an alpha value of less than1.0
, the default value of this property is YES. If the background image is completely opaque, the default value of this property is NO. If you set this property to YES and the custom background image is completely opaque, UIKit applies a system-defined opacity of less than1.0
to the image. If you set this property to NO and the background image is not opaque, UIKit adds an opaque backdrop.
所以陪汽,是否translucent
會導(dǎo)致導(dǎo)航欄行為變化训唱,進(jìn)而影響安全距離是嗎?我在 setBackgroundImage
前后追加了 log:
NSLog(@"1. translecent = %d", self.navigationController.navigationBar.translucent);
[self.navigationController.navigationBar setBackgroundImage:newImage forBarMetrics:UIBarMetricsDefault];
NSLog(@"2. translecent = %d", self.navigationController.navigationBar.translucent);
果然挚冤,執(zhí)行 setBackgroundImage
之后况增,translucent
從 1,變?yōu)?0 训挡。也就是說澳骤,初始時 SafeArea 的 y 邊界 = 64 ,當(dāng)設(shè)置了背景后, UIKit 發(fā)現(xiàn)此時不需要額外的 44 高度的導(dǎo)航欄偏差澜薄,translucentChanged=1
为肮,并且設(shè)置 SafeArea 的 y 邊界 = 20 但是沒有觸發(fā)渲染,記住這個標(biāo)記位肤京。當(dāng)用戶截圖颊艳、回到頂部時,UIKIt 會更新渲染忘分,所以會導(dǎo)致 bug棋枕。(以上是我對 UIKit 的黑盒運行機(jī)制猜測)
修改方法
在設(shè)置 setBackgroundImage
之前,主動設(shè)置 translucent = 0
妒峦,避免觸發(fā)setBackgroundImage
內(nèi)部的檢測是否透明的邏輯重斑。
self.navigationController.navigationBar.translucent = NO;
[self.navigationController.navigationBar setBackgroundImage:newImage forBarMetrics:UIBarMetricsDefault];
總結(jié)
屬于 iOS 自身對非劉海屏的 bug,現(xiàn)在還存在舟山。[self.navigationController.navigationBar setBackgroundImage:newImage forBarMetrics:UIBarMetricsDefault];
不一定會導(dǎo)致 translucent = 0
,即使你使用了 JPG 或者下面示例中的代碼绸狐。在嚴(yán)選 WebView 有問題,自己全新創(chuàng)建的工程里不會有問題累盗,內(nèi)部機(jī)制待查寒矿。
NSLog(@"1. translecent = %d", self.navigationController.navigationBar.translucent);
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
NSData *imageData = [NSData dataWithContentsOfURL:[NSURL URLWithString:@"https://yanxuan.nosdn.127.net/0ae2f591d48e4b29b064fa3f4f71e190.jpg?imageView&thumbnail=750y128&quality=75&axis=5_10"]];
UIImage *img = [UIImage imageWithData:imageData];
CGFloat scale = [UIScreen mainScreen].scale;
UIImage *newImage = [UIImage imageWithData:UIImagePNGRepresentation(img) scale:scale];
[self.navigationController.navigationBar setBackgroundImage:newImage forBarMetrics:UIBarMetricsDefault];
NSLog(@"2. translecent = %d", self.navigationController.navigationBar.translucent);
});