剛換工作拴竹,接手新公司的一個RN項目悟衩,同事向我反映了一個問題,說我們的App的首頁栓拜,滾動后頂部就出現了一個白條座泳,僅在iOS端出現,Android上運行良好幕与。我一聽就猜想是ScrollView兼容出問題了挑势,嘗試用iOS 9和iOS 11手機分別運行了一下,在iOS 11的手機上重現了這個問題啦鸣。于是檢查代碼潮饱,發(fā)現是iOS 11上UIScrollView增加了contentInsetAdjustmentBehavior屬性。
/* Configure the behavior of adjustedContentInset.
Default is UIScrollViewContentInsetAdjustmentAutomatic.
*/
@property(nonatomic) UIScrollViewContentInsetAdjustmentBehavior contentInsetAdjustmentBehavior API_AVAILABLE(ios(11.0),tvos(11.0));
typedef NS_ENUM(NSInteger, UIScrollViewContentInsetAdjustmentBehavior) {
UIScrollViewContentInsetAdjustmentAutomatic, // Similar to .scrollableAxes, but for backward compatibility will also adjust the top & bottom contentInset when the scroll view is owned by a view controller with automaticallyAdjustsScrollViewInsets = YES inside a navigation controller, regardless of whether the scroll view is scrollable
UIScrollViewContentInsetAdjustmentScrollableAxes, // Edges for scrollable axes are adjusted (i.e., contentSize.width/height > frame.size.width/height or alwaysBounceHorizontal/Vertical = YES)
UIScrollViewContentInsetAdjustmentNever, // contentInset is not adjusted
UIScrollViewContentInsetAdjustmentAlways, // contentInset is always adjusted by the scroll view's safeAreaInsets
} API_AVAILABLE(ios(11.0),tvos(11.0));
contentInsetAdjustmentBehavior
默認為automatic
時诫给,它會根據屏幕上是否有UINavigationBar香拉,UITabBar,可見狀態(tài)欄等自動調整ContentInset(并覆蓋任何手動設置的ContentInset)
剛好我們的主頁上有UITabBar中狂,于是就被自動調整了ContentInset凫碌,就出現了頂部的白條。
怎么解決
在新版本的React Native中已經修復了此問題胃榕,在ScrollView上新增了contentInsetAdjustmentBehavior
屬性盛险,且默認為never
,所以使用新版本React Native的童鞋一般是不會遇到這個問題的。但是我司App的React Native版本是0.38苦掘,因為歷史原因也不能直接去升級React Native版本换帜,所以就自己動手修改源碼吧。
以下是修改位置和源碼:(參考了React Native新版本的代碼)
文件RCTScrollView.m
initWithEventDispatcher方法中增加:
#if defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 110000 /* __IPHONE_11_0 */
// `contentInsetAdjustmentBehavior` is only available since iOS 11.
// We set the default behavior to "never" so that iOS
// doesn't do weird things to UIScrollView insets automatically
// and keeps it as an opt-in behavior.
if ([_scrollView respondsToSelector:@selector(setContentInsetAdjustmentBehavior:)]) {
_scrollView.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever;
}
#endif
以下代碼可在@implementation RCTScrollView任意位置加入鹤啡,我是加在sendScrollEventWithName方法前的惯驼。
#if defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 110000 /* __IPHONE_11_0 */
- (void)setContentInsetAdjustmentBehavior:(UIScrollViewContentInsetAdjustmentBehavior)behavior
{
// `contentInsetAdjustmentBehavior` is available since iOS 11.
if ([_scrollView respondsToSelector:@selector(setContentInsetAdjustmentBehavior:)]) {
CGPoint contentOffset = _scrollView.contentOffset;
_scrollView.contentInsetAdjustmentBehavior = behavior;
_scrollView.contentOffset = contentOffset;
}
}
#endif
文件RCTScrollViewManager.m
可在@implementation RCTScrollViewManager中任意位置加入以下代碼,不過為了和其他代碼統一揉忘,我們在RCT_EXPORT_VIEW_PROPERTY那堆代碼后進行增加跳座。
#if defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 110000 /* __IPHONE_11_0 */
RCT_EXPORT_VIEW_PROPERTY(contentInsetAdjustmentBehavior, UIScrollViewContentInsetAdjustmentBehavior)
#endif
@implementation RCTConvert (UIScrollView)中增加
#if defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 110000 /* __IPHONE_11_0 */
RCT_ENUM_CONVERTER(UIScrollViewContentInsetAdjustmentBehavior, (@{
@"automatic": @(UIScrollViewContentInsetAdjustmentAutomatic),
@"scrollableAxes": @(UIScrollViewContentInsetAdjustmentScrollableAxes),
@"never": @(UIScrollViewContentInsetAdjustmentNever),
@"always": @(UIScrollViewContentInsetAdjustmentAlways),
}), UIScrollViewContentInsetAdjustmentNever, integerValue)
#endif
文件ScrollView.js
在ScrollView的propTypes中增加contentInsetAdjustmentBehavior屬性。
contentInsetAdjustmentBehavior: PropTypes.oneOf([
'automatic',
'scrollableAxes',
'never', // default
'always',
]),
修改完畢泣矛,運行后白條消失疲眷,不過這只是臨時解決方案,接下來還是要想辦法把React Native的版本升級一下您朽,以免遇到更多的坑狂丝。