React Native的ScrollView頂部出現(xiàn)白條

剛換工作,接手新公司的一個RN項目,同事向我反映了一個問題,說我們的App的首頁,滾動后頂部就出現(xiàn)了一個白條,僅在iOS端出現(xiàn),Android上運行良好。我一聽就猜想是ScrollView兼容出問題了,嘗試用iOS 9和iOS 11手機分別運行了一下,在iOS 11的手機上重現(xiàn)了這個問題。于是檢查代碼,發(fā)現(xiàn)是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時,它會根據(jù)屏幕上是否有UINavigationBar,UITabBar,可見狀態(tài)欄等自動調整ContentInset(并覆蓋任何手動設置的ContentInset)

剛好我們的主頁上有UITabBar,于是就被自動調整了ContentInset,就出現(xiàn)了頂部的白條。

怎么解決

在新版本的React Native中已經(jīng)修復了此問題,在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中任意位置加入以下代碼,不過為了和其他代碼統(tǒng)一,我們在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的版本升級一下,以免遇到更多的坑。

參考GitHub: 1954438 #diff-973dcd0e3fbfcc5e35485bb6404a2fd2

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容