You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React Native中KeyboardAwareScrollView实现长表单出现抖动问题如何解决?

React Native 长表单使用KeyboardAwareScrollView出现抖动问题

问题背景

有Swift开发iOS应用的经验,刚接触React Native不久,开发基础表单页面时遇到异常:使用KeyboardAwareScrollView处理键盘弹出逻辑,表单仅含2个输入框时功能正常,表单较长时出现滚动抖动、交互异常问题。

问题表现

滚动到页面最底部时,整个屏幕会出现抖动、晃动,之后无法正常滚动;滚动回顶部时顶部也会出现同样的抖动问题。

相关代码

import React from 'react';
import { useState } from 'react';
import { Alert, TouchableWithoutFeedback, StatusBar, Dimensions, Pressable, Image, SafeAreaView, Keyboard, StyleSheet, Text, View, Button as RNButton } from 'react-native';
import { KeyboardAwareScrollView } from 'react-native-keyboard-aware-scroll-view';

import { Button, InputField, ErrorMessage } from '../components';

export default function SignupScreen({ navigation }) {
  const [email, setEmail] = useState('');
  const [phoneNumber, setPhoneNumber] = useState('');
  const [password, setPassword] = useState('');
  const [repeatPassword, setRepeatPassword] = useState('');
  const [firstName, setFirstName] = useState('');
  const [lastName, setLastName] = useState('');
  const [passwordVisibility, setPasswordVisibility] = useState(true);
  const [repeatPasswordVisibility, setRepeatPasswordVisibility] = useState(true);
  const [rightIcon, setRightIcon] = useState('eye');
  const [repeatRightIcon, setRepeatRightIcon] = useState('eye');
  const [signupError, setSignupError] = useState('');

  return (
    <View style={styles.container}>
    <TouchableWithoutFeedback
          onPress={Keyboard.dismiss}
          accessible={false}>
    <View style={{ flex: 1, backgroundColor: "white" }}>
    <KeyboardAwareScrollView
          keyboardShouldPersistTaps="handled"
          keyboardOpeningTime={0}
          alwaysBounceHorizontal={false}
          alwaysBounceVertical={false}
          showsHorizontalScrollIndicator={false}
          showsVerticalScrollIndicator={false}
          enableOnAndroid>
      <SafeAreaView>
      <StatusBar
            backgroundColor="transparent"
            barStyle="dark-content"
            hidden={false}
            translucent
          />
          
          <View style={styles.registerContainer}>
            <View style={styles.registerContent}>

                <InputField
                    labelText="Field 1"
                    inputStyle={{
                    fontSize: 14
                    }}
                    containerStyle={{
                    backgroundColor: '#fff',
                    }}
                    // leftIcon='email'
                    autoCapitalize='words'
                    keyboardType='default'
                    textContentType='givenName'
                    // autoFocus={true}
                    value={firstName}
                    onChangeText={text => setFirstName(text)}
                />

                <InputField
                    labelText="Field 2"
                    inputStyle={{
                    fontSize: 14
                    }}
                    containerStyle={{
                    backgroundColor: '#fff',
                    }}
                    // leftIcon='email'
                    autoCapitalize='words'
                    keyboardType='default'
                    textContentType='familyName'
                    // autoFocus={true}
                    value={lastName}
                    onChangeText={text => setLastName(text)}
                />

                <InputField
                    labelText="Field 3"
                    inputStyle={{
                    fontSize: 14
                    }}
                    containerStyle={{
                    backgroundColor: '#fff',
                    }}
                    // leftIcon='email'
                    autoCapitalize='none'
                    keyboardType='email-address'
                    textContentType='emailAddress'
                    // autoFocus={true}
                    value={email}
                    onChangeText={text => setEmail(text)}
                />

                <InputField
                    labelText="Field 4"
                    inputStyle={{
                    fontSize: 14
                    }}
                    containerStyle={{
                    backgroundColor: '#fff',
                    }}
                    // leftIcon='email'
                    autoCapitalize='none'
                    keyboardType='phone-pad'
                    textContentType='telephoneNumber'
                    // autoFocus={true}
                    value={phoneNumber}
                    onChangeText={text => setPhoneNumber(text)}
                />

                <InputField
                    labelText="Field 5"
                    inputStyle={{
                    fontSize: 14
                    }}
                    containerStyle={{
                    backgroundColor: '#fff',
                    }}
                    // leftIcon='lock'
                    autoCapitalize='none'
                    autoCorrect={false}
                    secureTextEntry={passwordVisibility}
                    textContentType='password'
                    rightIcon={rightIcon}
                    value={password}
                    onChangeText={text => setPassword(text)}
                    handlePasswordVisibility={handlePasswordVisibility}
                />

                <InputField
                    labelText="Field 6"
                    inputStyle={{
                    fontSize: 14
                    }}
                    containerStyle={{
                    backgroundColor: '#fff',
                    }}
                    // leftIcon='lock'
                    autoCapitalize='none'
                    autoCorrect={false}
                    secureTextEntry={passwordVisibility}
                    textContentType='password'
                    rightIcon={rightIcon}
                    value={password}
                    onChangeText={text => setPassword(text)}
                    handlePasswordVisibility={handlePasswordVisibility}
                />

                <InputField
                    labelText="Field 7"
                    inputStyle={{
                    fontSize: 14
                    }}
                    containerStyle={{
                    backgroundColor: '#fff',
                    }}
                    // leftIcon='lock'
                    autoCapitalize='none'
                    autoCorrect={false}
                    secureTextEntry={passwordVisibility}
                    textContentType='password'
                    rightIcon={rightIcon}
                    value={password}
                    onChangeText={text => setPassword(text)}
                    handlePasswordVisibility={handlePasswordVisibility}
                />

                <InputField
                    labelText="Field 8"
                    inputStyle={{
                    fontSize: 14
                    }}
                    containerStyle={{
                    backgroundColor: '#fff',
                    }}
                    // leftIcon='lock'
                    autoCapitalize='none'
                    autoCorrect={false}
                    secureTextEntry={passwordVisibility}
                    textContentType='password'
                    rightIcon={rightIcon}
                    value={password}
                    onChangeText={text => setPassword(text)}
                    handlePasswordVisibility={handlePasswordVisibility}
                />

                <InputField
                    labelText="Field 9"
                    inputStyle={{
                    fontSize: 14
                    }}
                    containerStyle={{
                    backgroundColor: '#fff',
                    }}
                    // leftIcon='lock'
                    autoCapitalize='none'
                    autoCorrect={false}
                    secureTextEntry={passwordVisibility}
                    textContentType='password'
                    rightIcon={rightIcon}
                    value={password}
                    onChangeText={text => setPassword(text)}
                    handlePasswordVisibility={handlePasswordVisibility}
                />

                <InputField
                    labelText="Field 10"
                    inputStyle={{
                    fontSize: 14
                    }}
                    containerStyle={{
                    backgroundColor: '#fff',
                    }}
                    // leftIcon='lock'
                    autoCapitalize='none'
                    autoCorrect={false}
                    secureTextEntry={passwordVisibility}
                    textContentType='password'
                    rightIcon={rightIcon}
                    value={password}
                    onChangeText={text => setPassword(text)}
                    handlePasswordVisibility={handlePasswordVisibility}
                />

                <InputField
                    labelText="Field 11"
                    inputStyle={{
                    fontSize: 14
                    }}
                    containerStyle={{
                    backgroundColor: '#fff',
                    }}
                    // leftIcon='lock'
                    autoCapitalize='none'
                    autoCorrect={false}
                    secureTextEntry={passwordVisibility}
                    textContentType='password'
                    rightIcon={rightIcon}
                    value={password}
                    onChangeText={text => setPassword(text)}
                    handlePasswordVisibility={handlePasswordVisibility}
                />

                <InputField
                    labelText="Field 12"
                    inputStyle={{
                    fontSize: 14
                    }}
                    containerStyle={{
                    backgroundColor: '#fff',
                    }}
                    // leftIcon='lock'
                    autoCapitalize='none'
                    autoCorrect={false}
                    secureTextEntry={passwordVisibility}
                    textContentType='password'
                    rightIcon={rightIcon}
                    value={password}
                    onChangeText={text => setPassword(text)}
                    handlePasswordVisibility={handlePasswordVisibility}
                />

                <InputField
                    labelText="Field 13"
                    inputStyle={{
                    fontSize: 14
                    }}
                    containerStyle={{
                    backgroundColor: '#fff',
                    }}
                    // leftIcon='lock'
                    autoCapitalize='none'
                    autoCorrect={false}
                    secureTextEntry={passwordVisibility}
                    textContentType='password'
                    rightIcon={rightIcon}
                    value={password}
                    onChangeText={text => setPassword(text)}
                    handlePasswordVisibility={handlePasswordVisibility}
                />

                <InputField
                    labelText="Field 14"
                    inputStyle={{
                    fontSize: 14
                    }}
                    containerStyle={{
                    backgroundColor: '#fff',
                    }}
                    // leftIcon='lock'
                    autoCapitalize='none'
                    autoCorrect={false}
                    secureTextEntry={passwordVisibility}
                    textContentType='password'
                    rightIcon={rightIcon}
                    value={password}
                    onChangeText={text => setPassword(text)}
                    handlePasswordVisibility={handlePasswordVisibility}
                />

                <InputField
                    labelText="Field 15"
                    inputStyle={{
                    fontSize: 14
                    }}
                    containerStyle={{
                    backgroundColor: '#fff',
                    }}
                    // leftIcon='lock'
                    autoCapitalize='none'
                    autoCorrect={false}
                    secureTextEntry={repeatPasswordVisibility}
                    textContentType='password'
                    repeatRightIcon={repeatRightIcon}
                    value={repeatPassword}
                    onChangeText={text => setRepeatPassword(text)}
                    handleRepeatPasswordVisibility={handleRepeatPasswordVisibility}
                />

                {/* {signupError ? <ErrorMessage error={signupError} visible={true} /> : null} */}

                <Button
                    onPress={onHandleSignup}
                    backgroundColor='#f57c00'
                    title='Button'
                    tileColor='#fff'
                    titleSize={20}
                    containerStyle={{
                    marginBottom: 20
                    }}
                />
                {/* <RNButton
                    onPress={() => navigation.navigate('Login')}
                    title='Go to Login'
                    color='red'
                /> */}
            </View>
        </View>
      </SafeAreaView>
    </KeyboardAwareScrollView>
    </View>
    </TouchableWithoutFeedback>
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: '#fff',
    // paddingTop: 50,
    // paddingHorizontal: 12
  },
  title: {
    fontSize: 24,
    fontWeight: '600',
    color: '#fff',
    alignSelf: 'center',
    // paddingBottom: 24
  },
  registerContainer: {
    width: '100%',
    backgroundColor: '#fff',
    alignItems: 'center',
    paddingTop: Dimensions.get('window').width * 0.1,
  },
  registerContent: {
    width: '80%',
    backgroundColor: 'white',
  },
  labelText: {
    fontSize: 16,
    color: '#808080',
    marginBottom: 10,
  },
});

已排查情况

  • 该页面是在Stack.Navigator中通过CardStyleInterpolators.forVerticalIOS方式弹出的,但移除模态弹窗样式后问题依旧存在。
  • 尝试给KeyboardAwareScrollView设置automaticallyAdjustContentInsets={false}和contentInsetAdjustmentBehavior="automatic"属性,没有效果。
  • 所有表单输入框的键盘交互都存在异常:点击输入框无响应,键盘几乎无法唤起,即便唤起也会卡住,无法正常填写表单。

解决方案

1. 修正KeyboardAwareScrollView属性

删除keyboardOpeningTime={0}配置,该参数会打断iOS原生键盘动画和滚动偏移计算逻辑,长表单下会触发循环计算导致抖动。最终属性配置参考:

<KeyboardAwareScrollView
  keyboardShouldPersistTaps="handled"
  enableOnAndroid
  extraScrollHeight={20}
  bounces={false}
  showsVerticalScrollIndicator={false}
  showsHorizontalScrollIndicator={false}
>

2. 调整组件层级

将SafeAreaView移到KeyboardAwareScrollView外层,避免滚动区域反复计算安全区域偏移:

<View style={styles.container}>
  <SafeAreaView style={{flex: 1}}>
    <StatusBar
      backgroundColor="transparent"
      barStyle="dark-content"
      hidden={false}
      translucent
    />
    <TouchableWithoutFeedback onPress={Keyboard.dismiss} accessible={false}>
      <View style={{ flex: 1, backgroundColor: "white" }}>
        <KeyboardAwareScrollView {/* 修正后的属性 */}>
          {/* 表单内容 */}
        </KeyboardAwareScrollView>
      </View>
    </TouchableWithoutFeedback>
  </SafeAreaView>
</View>

3. 替换动态padding计算

registerContainer的动态paddingTop会触发视图频繁重绘,改为固定值:

registerContainer: {
  width: '100%',
  backgroundColor: '#fff',
  alignItems: 'center',
  paddingTop: 40, // 按设计需求调整数值
},

4. 补充缺失的方法定义

代码中调用的handlePasswordVisibility、handleRepeatPasswordVisibility、onHandleSignup未定义,会导致点击交互异常,补充对应方法:

const handlePasswordVisibility = () => {
  setPasswordVisibility(!passwordVisibility);
  setRightIcon(passwordVisibility ? 'eye-off' : 'eye');
};

const handleRepeatPasswordVisibility = () => {
  setRepeatPasswordVisibility(!repeatPasswordVisibility);
  setRepeatRightIcon(repeatPasswordVisibility ? 'eye-off' : 'eye');
};

const onHandleSignup = () => {
  // 表单提交逻辑
};

修改完成后清理项目缓存重新运行即可解决所有异常问题。


内容的提问来源于stack exchange,提问作者PennyWise

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.30 14:54:06