KeyboardAvoidingView为什么需要keyboardVerticalOffset?

431 阅读1分钟

有键盘的页面很多时候要考虑用KeyboardAvoidingView来避免输入框别键盘遮挡,但是使用的时候经常发现键盘弹出后发现键盘还是可能遮挡一些东西,和预期的不一样。

主要的原因还是和KeyboardAvoidingView内部实现有关系,它是通过一个ViewA来包含KeyboardAvoidingView的children,然后再监听键盘,调整ViewA的高度,或者bottom,或者paddingBottom来达到让里面的children也一起上升,从而不会被键盘遮挡,所以关键问题就是上升高度的计算

这是源码计算要上升的高度

async _relativeKeyboardHeight(
  keyboardFrame: KeyboardMetrics,
): Promise<number> {
  const frame = this._frame;
  if (!frame || !keyboardFrame) {
    return 0;
  }

  // On iOS when Prefer Cross-Fade Transitions is enabled, the keyboard position
  // & height is reported differently (0 instead of Y position value matching height of frame)
  if (
    Platform.OS === 'ios' &&
    keyboardFrame.screenY === 0 &&
    (await AccessibilityInfo.prefersCrossFadeTransitions())
  ) {
    return 0;
  }

  const keyboardY =
    keyboardFrame.screenY - (this.props.keyboardVerticalOffset ?? 0);

  if (this.props.behavior === 'height') {
    return Math.max(
      this.state.bottom + frame.y + frame.height - keyboardY,
      0,
    );
  }

  // Calculate the displacement needed for the view such that it
  // no longer overlaps with the keyboard
  return Math.max(frame.y + frame.height - keyboardY, 0);
}

其中frame是ViewA的坐标,keyboardFrame是键盘相对整个屏幕的坐标

从这里可以看出ViewA和keyboardFrame的坐标系是关键,如果两个坐标系一样,那么就不需要keyboardVerticalOffset了,如果不一样就会产生误差,需要通过keyboardVerticalOffset来调整

所以通常将KeyboardAvoidingView放在最外层来避免更多的keyboardVerticalOffset值计算;但是有时放在最外层还是会需要计算误差,比如导航和状态栏的高度