React Native踩坑指南

WebView高度自适应

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

添加高度state

state = {
    height: 0
}
复制代码

自适应

<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上开发的库无法解决问题。所以就只能自行封装一个来解决键盘遮挡输入框的问题。

源码链接KeyboardAvoidingView.tsx

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后事件还在监听,所以需要移除,然后等路由重新回来到当前页面再重新监听。

将组件包裹在视图最上层即可

<KeyboardAvoidingView navigation={this.props.navigation}>
  <View>
    <TextInput />
    ...
  </View>
</KeyboardAvoidingView>
复制代码
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值