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

React Native聊天页面键盘适配:如何固定头部且消息随键盘上滑

Expo React Native 聊天页面键盘适配解决方案

核心配置调整

先在app.json中固定键盘布局模式为resize,因为pan模式会触发整个页面上滑,无法实现头部固定需求:

{
  "expo": {
    "android": {
      "softwareKeyboardLayoutMode": "resize",
      "windowSoftInputMode": "adjustResize"
    },
    "ios": {
      "softwareKeyboardLayoutMode": "resize"
    }
  }
}

方案一:原生组件组合实现(无第三方库)

通过KeyboardAvoidingView + FlatList配合固定头部的布局,解决消息随键盘上滑、头部固定的需求:

import { View, FlatList, TextInput, KeyboardAvoidingView, Platform, Text, TouchableOpacity } from 'react-native';

export default function ChatScreen() {
  // 模拟消息数据
  const messages = [
    { id: '1', content: '你好', isMine: false },
    { id: '2', content: '请问有什么可以帮你?', isMine: true },
    // ...更多消息
  ];

  return (
    <View style={{ flex: 1, backgroundColor: '#f0f0f0' }}>
      {/* 固定头部 - 不参与滚动 */}
      <View style={{ height: 60, backgroundColor: '#fff', justifyContent: 'center', alignItems: 'center', borderBottomWidth: 1, borderBottomColor: '#eee' }}>
        <Text style={{ fontSize: 18, fontWeight: '500' }}>聊天标题</Text>
      </View>

      {/* 消息列表 + 输入框区域 */}
      <KeyboardAvoidingView
        style={{ flex: 1, marginTop: 60 }} // marginTop与头部高度一致,避免遮挡
        behavior={Platform.OS === 'ios' ? 'padding' : 'height'}
        keyboardVerticalOffset={Platform.OS === 'ios' ? 0 : 20} // 适配安卓键盘偏移
      >
        {/* 消息列表 - 使用FlatList优化性能 */}
        <FlatList
          style={{ flex: 1 }}
          data={messages}
          keyExtractor={(item) => item.id}
          inverted // 最新消息显示在底部时启用
          contentContainerStyle={{ padding: 10, paddingBottom: 30 }} // 底部留空间避免输入框遮挡消息
          renderItem={({ item }) => (
            <View
              style={{
                alignSelf: item.isMine ? 'flex-end' : 'flex-start',
                backgroundColor: item.isMine ? '#dcf8c6' : '#fff',
                padding: 12,
                borderRadius: 12,
                maxWidth: '80%',
                marginVertical: 4
              }}
            >
              <Text>{item.content}</Text>
            </View>
          )}
        />

        {/* 底部输入框 */}
        <View style={{ flexDirection: 'row', padding: 10, borderTopWidth: 1, borderTopColor: '#eee', backgroundColor: '#f0f0f0' }}>
          <TextInput
            style={{ flex: 1, borderWidth: 1, borderColor: '#ddd', borderRadius: 24, paddingHorizontal: 16, paddingVertical: 8, backgroundColor: '#fff' }}
            placeholder="输入消息..."
          />
          <TouchableOpacity style={{ marginLeft: 10, justifyContent: 'center', alignItems: 'center', paddingHorizontal: 16 }}>
            <Text style={{ color: '#0084ff' }}>发送</Text>
          </TouchableOpacity>
        </View>
      </KeyboardAvoidingView>
    </View>
  );
}

关键细节说明

  • 头部采用固定高度+外层布局隔离,确保键盘弹出时不会被上推
  • KeyboardAvoidingView的behavior属性分平台设置:iOS用padding,安卓用height,减少页面跳动
  • FlatList添加contentContainerStyle的paddingBottom,避免最后一条消息被输入框遮挡
  • 统一页面背景色,解决resize模式下键盘开合的闪白问题

方案二:使用第三方库增强适配

如果原生组件效果不佳,可采用react-native-keyboard-aware-scroll-view库,它对键盘适配的细节处理更完善:

import { View, Text, TextInput, TouchableOpacity } from 'react-native';
import { KeyboardAwareScrollView } from 'react-native-keyboard-aware-scroll-view';

export default function ChatScreen() {
  const messages = [
    { id: '1', content: '你好', isMine: false },
    { id: '2', content: '请问有什么可以帮你?', isMine: true },
    // ...更多消息
  ];

  return (
    <View style={{ flex: 1, backgroundColor: '#f0f0f0' }}>
      {/* 固定头部 */}
      <View style={{ height: 60, backgroundColor: '#fff', justifyContent: 'center', alignItems: 'center', borderBottomWidth: 1, borderBottomColor: '#eee' }}>
        <Text style={{ fontSize: 18, fontWeight: '500' }}>聊天窗口</Text>
      </View>

      <KeyboardAwareScrollView
        style={{ flex: 1, marginTop: 60 }}
        extraScrollHeight={30} // 额外滚动高度,避免输入框遮挡消息
        enableOnAndroid={true} // 安卓端启用适配
        enableAutomaticScroll={true} // 键盘弹出时自动滚动到输入框位置
        keyboardShouldPersistTaps="handled" // 点击消息区域关闭键盘
      >
        {/* 消息列表 */}
        <View style={{ padding: 10, gap: 8 }}>
          {messages.map(msg => (
            <View key={msg.id} style={{
              alignSelf: msg.isMine ? 'flex-end' : 'flex-start',
              backgroundColor: msg.isMine ? '#dcf8c6' : '#fff',
              padding: 12,
              borderRadius: 12,
              maxWidth: '80%'
            }}>
              <Text>{msg.content}</Text>
            </View>
          ))}
        </View>

        {/* 输入框区域 */}
        <View style={{ flexDirection: 'row', padding: 10, borderTopWidth: 1, borderTopColor: '#eee', marginTop: 10 }}>
          <TextInput
            style={{ flex: 1, borderWidth: 1, borderColor: '#ddd', borderRadius: 24, paddingHorizontal: 16, paddingVertical: 8, backgroundColor: '#fff' }}
            placeholder="输入消息..."
          />
          <TouchableOpacity style={{ marginLeft: 10, justifyContent: 'center', alignItems: 'center', paddingHorizontal: 16 }}>
            <Text style={{ color: '#0084ff' }}>发送</Text>
          </TouchableOpacity>
        </View>
      </KeyboardAwareScrollView>
    </View>
  );
}

额外优化建议

  • 避免在键盘弹出/收起的回调中执行复杂逻辑或状态更新,减少不必要的重渲染
  • 用React.memo包裹消息项组件,优化列表滚动性能
  • 安卓端可调整keyboardVerticalOffset参数,适配不同机型的键盘高度差异

内容的提问来源于stack exchange,提问作者Pedro Luan Polignano Motta Dia

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.10 22:55:18