React Native踩坑指南

WebView高度自适应

webview使用100%高度等没办法自动填满父容器,反而会由于一开始没有渲染高度只有0,因此后面都看不到webview。webview必须指定一个高度,没办法自适应高度。经过注入js,监听渲染后高度,而后回调设置真正的100%高度回来,作到自适应。html

添加高度statereact

state = {
    height: 0
}
复制代码

自适应ios

<WebView
  source={{html: `
    <!DOCTYPE html>
    <html>
        <body>
          ${html}
        </body>
        <script>
          window.onload = function() {
            // 回调高度
            document.title = document.body.clientHeight;
          }
        </script>
      </body>
  `}}
  onNavigationStateChange={(event)=>{
    if(event.title != undefined) {
      console.log('event title', event.title);
      // 设置高度
      this.setState({
        height: parseInt(event.title)
      });
    }}}
/>
复制代码

ios键盘遮挡输入框

在react native开发中第一个最容易遇到的坑就是点击输入框,ios的键盘遮挡住了输入框,看不到输入的内容。而直接使用第三方的库解决这个问题的过程当中又遇到了新的问题,github上开发的库没法解决问题。因此就只能自行封装一个来解决键盘遮挡输入框的问题。git

源码连接KeyboardAvoidingView.tsxgithub

import React from 'react';
import {Animated, Dimensions, EmitterSubscription, Keyboard, Platform, TextInput, UIManager} from 'react-native';
import {NavigationEventSubscription, NavigationScreenProp} from 'react-navigation';

interface IState {
  height: Animated.Value;
}

export interface KeyboardAvoidingViewProps {
  navigation: NavigationScreenProp<any, any>;
  onInputChange?: (onInput: boolean) => void;
  // 固定键盘高度
  fixedKeyboardHeight?: boolean;
  // 固定上浮高度
  fixedHeight?: number;
  // 键盘加上高度
  addHeight?: number;
}

export default class KeyboardAvoidingView extends React.Component<KeyboardAvoidingViewProps, IState> {
  state = {
    height: new Animated.Value(0),
    onInput: false
  }
  private didFocus?: NavigationEventSubscription;
  private willBlur?: NavigationEventSubscription;
  private keyboardDidShowSub?: EmitterSubscription;
  private keyboardDidHideSub?: EmitterSubscription;
  componentDidMount() {
    this.didFocus = this.props.navigation.addListener('didFocus', () => {
      this.keyboardDidShowSub = Keyboard.addListener('keyboardDidShow', this.handleKeyboardDidShow);
      this.keyboardDidHideSub = Keyboard.addListener('keyboardDidHide', this.handleKeyboardDidHide);
    });
    this.willBlur = this.props.navigation.addListener('willBlur', () => {
        this.keyboardDidShowSub && this.keyboardDidShowSub.remove();
        this.keyboardDidHideSub && this.keyboardDidHideSub.remove();
    });
  }
  handleKeyboardDidShow = (event: any) => {
    this.props.onInputChange && this.props.onInputChange(true);
    if (Platform.OS != 'ios') return;
    console.log('handleKeyboardDidShow');
    const { height: windowHeight } = Dimensions.get('window');
    const addHeight = this.props.addHeight || 0;
    const keyboardHeight = event.endCoordinates.height + addHeight;
    const currentlyFocusedField = TextInput.State.currentlyFocusedField();
    console.log('currentlyFocusedField', currentlyFocusedField);
    if (currentlyFocusedField == null) return;
    if (this.props.fixedHeight != undefined) {
      Animated.timing(
        this.state.height,
        {
          toValue: -this.props.fixedHeight,
          duration: 200,
          useNativeDriver: true,
        }
      ).start();
      return;
    }
    if (this.props.fixedKeyboardHeight) {
      console.log('keyboardHeight', keyboardHeight);
      Animated.timing(
        this.state.height,
        {
          toValue: -keyboardHeight,
          duration: 200,
          useNativeDriver: true,
        }
      ).start();
      return;
    }
    UIManager.measure(currentlyFocusedField, (originX, originY, width, height, pageX, pageY) => {
      const fieldHeight = height;
      const fieldTop = pageY;
      const gap = (windowHeight - keyboardHeight) - (fieldTop + fieldHeight);
      console.log('windowHeight', windowHeight, 'keyboardHeight', keyboardHeight, 'gap', gap, 'fieldTop', fieldTop, 'fieldHeight', fieldHeight);
      if (gap >= 0) {
        return;
      }
      Animated.timing(
        this.state.height,
        {
          toValue: gap,
          duration: 200,
          useNativeDriver: true,
        }
      ).start();
    });
  }
  handleKeyboardDidHide = () => {
    this.props.onInputChange && this.props.onInputChange(false);
    if (Platform.OS != 'ios') return;
    console.log('handleKeyboardDidHide');
    Animated.timing(
      this.state.height,
      {
        toValue: 0,
        duration: 200,
        useNativeDriver: true,
      }
    ).start();
  }
  render() {
    if (Platform.OS == 'ios') {
      return (
        <Animated.View style={{flex: 1, transform: [{translateY: this.state.height}]}}>
          {this.props.children}
        </Animated.View>
      );
    }
    return this.props.children;
  }
}
复制代码

须要注意的是KeyboardAvoidingView与react-navigation配合使用,在路由push后事件还在监听,因此须要移除,而后等路由从新回来到当前页面再从新监听。web

将组件包裹在视图最上层便可react-native

<KeyboardAvoidingView navigation={this.props.navigation}>
  <View>
    <TextInput />
    ...
  </View>
</KeyboardAvoidingView>
复制代码
相关文章
相关标签/搜索