Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

RN-SafeAreaView #289

Open
yaofly2012 opened this issue Nov 5, 2023 · 0 comments
Open

RN-SafeAreaView #289

yaofly2012 opened this issue Nov 5, 2023 · 0 comments

Comments

@yaofly2012
Copy link
Owner

yaofly2012 commented Nov 5, 2023

SafeAreaView组件

功能

设备安全区域内容展示页面内容:

原理

本质是个View组件,但会自动添加padding
SafeAreaView不是无脑的添加padding,而是在适当的时候添加padding

  1. 上边缘触摸了设备顶部,即坐标Y === 0;
  2. 左边缘触摸了设备左部,即坐标X === 0;
  3. 下边缘超过设备底部,即坐标Y + View高度 >= 设备高度;
  4. 右边缘超过设备右部,即坐标X + View宽度 >= 设备宽度;

SafeAreaView四边处于以上4中情况时,则会给边缘添加合适的padding

具体实现可以参考react-native-safe-area-view_getSafeAreaStyle方法的实现。

// 检查`SafeAreaView`边缘是否触碰到设备边缘
 _updateMeasurements = () => {
    if (!this._isMounted) return;
    if (!this._view.current) return;

    const { width: WIDTH, height: HEIGHT } = getResolvedDimensions();

    // calling getNode on the ref is no longer necessary in the future
    const view = this._view.current.measureInWindow
      ? this._view.current
      : this._view.current.getNode();
    view.measureInWindow((realX, realY, winWidth, winHeight) => {
      if (!this._view.current) {
        return;
      }

      if (realY >= HEIGHT) {
        realY = realY % HEIGHT;
      } else if (realY < 0) {
        realY = (realY % HEIGHT) + HEIGHT;
      }

      if (realX >= WIDTH) {
        realX = realX % WIDTH;
      } else if (realX < 0) {
        realX = (realX % WIDTH) + WIDTH;
      }

      let nextState = {
        touchesTop: realY === 0,
        touchesBottom: realY + winHeight >= HEIGHT,
        touchesLeft: realX === 0,
        touchesRight: realX + winWidth >= WIDTH,
        viewWidth: winWidth,
        viewHeight: winHeight,
      };

      if (!shallowEquals(nextState, this.state)) {
        this.setState(nextState);
      }
    });
  };

使用

包裹整个页面组件

如果只是简单的把页面内容展示安全区域内,可以用SafeAreaView+flex: 1包裹页面组件即可。正如RN官方的[DEMO]:(https://reactnative.dev/docs/safeareaview#example):

import React from 'react';
import {StyleSheet, Text, SafeAreaView} from 'react-native';

const App = () => {
  return (
    <SafeAreaView style={styles.container}>
      <Text style={styles.text}>Page content</Text>
    </SafeAreaView>
  );
};

const styles = StyleSheet.create({
  container: {
    flex: 1,
  },
  text: {
    fontSize: 25,
    fontWeight: '500',
  },
});

export default App;

头部组件

为了实现更好的沉浸式头部组件(Header, Tab等)可以在这些组件内部使用SafeAreaView

底部组件

跟头部组件类似,还有些页面底部的组件中可以直接使用SafeAreaView

Issues/Concern

  1. 不能给SafeAreaView显示的指定padding相关属性。
  2. ScrollView内部使用SafeAreaView时会发生页面抖动。解决方案:contentInsetAdjustmentBehavior="automatic"

参考

  1. ReactNative SafeAreaView
  2. iOS Safe Area
  3. SafeAreaView doesn't respect padding property in style #22211
  4. Having a SafeAreaView inside ScrollView breaks scrolling #19658
  5. react-native-safe-area-context
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant