前言

在移动应用开发中,AI聊天功能已成为许多健康管理、医疗咨询类App的核心功能。为了提升用户体验,需要实现快捷输入和二级菜单功能,让用户能够快速选择常见问题,减少手动输入。本文将详细介绍如何在React Native中实现这些功能,包括技术选型、实现思路和完整代码解析。


一、功能概述与技术栈

1.1 功能需求

  • 快捷输入:用户可以通过点击预设问题快速输入内容
  • 二级菜单:通过"+"号按钮展开分类问题菜单
  • 角色选择:用户可选择不同身份与AI对话
  • 键盘适配:输入区域根据键盘状态自动调整位置

1.2 技术栈

  • React Native:跨平台移动应用框架
  • React Navigation:处理页面导航
  • React Native Keyboard:监听键盘事件
  • TypeScript:提供类型检查
  • styled-components(可选):用于样式管理

二、核心功能实现

2.1 快捷输入功能实现

2.1.1 数据结构设计

我们使用状态管理来存储快捷输入问题:

const [secondMenu, setSecondMenu] = useState(''); // 当前激活的二级菜单
const [userInput, setUserInput] = useState(''); // 用户输入内容
2.1.2 快捷问题分类

我们将问题分为三类,存储在组件中:

// 症状咨询类问题
const symptomQuestions = [
  { title: '头痛头晕原因', question: '我最近经常头痛和头晕,可能是什么原因?' },
  { title: '右下腹疼痛', question: '肚子右下方疼痛,是阑尾炎的症状吗?需要立即就医吗?' }
  // 更多问题...
];

// 健康管理类问题
const healthQuestions = [
  { title: '胆固醇饮食', question: '如何通过饮食改善胆固醇偏高的问题?' },
  // 更多问题...
];

// 医疗常识类问题
const medicalQuestions = [
  { title: '胃镜准备', question: '做胃镜检查前需要注意什么?' },
  // 更多问题...
];
2.1.3 渲染快捷输入菜单

根据当前激活的菜单类型渲染不同问题:

<TouchableWithoutFeedback onPress={() => setSecondMenu('')}>
  <View style={[styles.fastInputContainer, isKeyboardOn && styles.fastInputContainerOn]}>
    {/* 一级菜单 */}
    <View>
      <Button title={'症状咨询'} onPress={() => setSecondMenu('a')} />
      <Button title={'健康管理'} onPress={() => setSecondMenu('b')} />
      <Button title={'医疗常识咨询'} onPress={() => setSecondMenu('c')} />
    </View>
    
    {/* 二级菜单 - 症状咨询 */}
    <View style={{display: secondMenu === 'a' ? 'flex' : 'none'}}>
      {symptomQuestions.map((item, index) => (
        <Button
          key={index}
          title={item.title}
          onPress={() => {
            setUserInput(item.question);
            setSecondMenu('');
          }}
        />
      ))}
    </View>
    
    {/* 其他二级菜单... */}
  </View>
</TouchableWithoutFeedback>

2.2 二级菜单实现

2.2.1 状态管理

使用状态控制菜单显示:

const [firstMenu, setFirstMenu] = useState(false); // 控制一级菜单显示
const [secondMenu, setSecondMenu] = useState(''); // 控制二级菜单显示
2.2.2 菜单触发按钮

在输入框旁添加"+"按钮:

<View style={styles.inputContainer}>
  <Button
    title={'+'}
    onPress={() => setFirstMenu(!firstMenu)}
  />
  <TextInput
    style={styles.input}
    value={userInput}
    onChangeText={setUserInput}
    placeholder="请输入您的问题..."
  />
  <Button title="发送" onPress={handleSend} />
</View>
2.2.3 菜单样式控制

根据键盘状态调整菜单位置:

const styles = StyleSheet.create({
  fastInputContainer: {
    position: "absolute",
    top: 515,
    left: 3
  },
  fastInputContainerOn: {
    position: "absolute",
    top: 260, // 键盘弹出时调整位置
    left: 8
  }
});

2.3 键盘适配

2.3.1 键盘事件监听

使用React Native的Keyboard模块监听键盘状态:

useEffect(() => {
  const keyboardDidShowListener = Keyboard.addListener('keyboardDidShow', () => {
    setKeyboardOn(true);
  });
  const keyboardDidHideListener = Keyboard.addListener('keyboardDidHide', () => {
    setKeyboardOn(false);
  });

  return () => {
    keyboardDidHideListener.remove();
    keyboardDidShowListener.remove();
  };
}, []);
2.3.2 输入容器样式切换

根据键盘状态切换样式:

const inputContainer = isKeyboardOn ? styles.keyBoardOn : styles.keyBoardOff;

// 样式定义
const styles = StyleSheet.create({
  keyBoardOn: {
    position: "relative",
    top: -255
  },
  keyBoardOff: {
    position:"relative",
    top: 0
  }
});

三、功能优化与扩展

3.1 性能优化

  1. 避免不必要的渲染:使用React.memo包装菜单组件
  2. 懒加载问题数据:对于大量问题,可以考虑分页加载
  3. 使用FlatList:当问题数量多时,替换ScrollView为FlatList

3.2 用户体验优化

  1. 添加动画效果:使用React Native Animated为菜单添加展开/收起动画
  2. 增加搜索功能:在快捷问题较多时提供搜索框
  3. 收藏常用问题:允许用户收藏常用问题

3.3 扩展功能

  1. 问题分类管理:从后端获取问题分类,实现动态配置
  2. 用户历史记录:保存用户常用问题,智能推荐
  3. 语音输入:集成语音识别,支持语音提问

四、完整代码解析

以下是核心功能的完整实现代码:

// 快捷输入菜单组件
const QuickInputMenu = () => {
  const [firstMenu, setFirstMenu] = useState(false);
  const [secondMenu, setSecondMenu] = useState('');
  const [isKeyboardOn, setKeyboardOn] = useState(false);
  
  // 键盘监听
  useEffect(() => {
    const keyboardDidShowListener = Keyboard.addListener('keyboardDidShow', () => {
      setKeyboardOn(true);
    });
    const keyboardDidHideListener = Keyboard.addListener('keyboardDidHide', () => {
      setKeyboardOn(false);
    });

    return () => {
      keyboardDidHideListener.remove();
      keyboardDidShowListener.remove();
    };
  }, []);

  return (
    <>
      {/* 输入框 */}
      <View style={isKeyboardOn ? styles.keyBoardOn : styles.keyBoardOff}>
        <View style={styles.inputContainer}>
          <Button
            title={'+'}
            onPress={() => setFirstMenu(!firstMenu)}
          />
          <TextInput
            style={styles.input}
            placeholder="请输入您的问题..."
          />
          <Button title="发送" onPress={handleSend} />
        </View>
      </View>

      {/* 快捷输入菜单 */}
      {firstMenu && (
        <TouchableWithoutFeedback onPress={() => setSecondMenu('')}>
          <View style={[
            styles.fastInputContainer, 
            isKeyboardOn && styles.fastInputContainerOn
          ]}>
            {/* 一级菜单 */}
            <View>
              <Button title={'症状咨询'} onPress={() => setSecondMenu('a')} />
              <Button title={'健康管理'} onPress={() => setSecondMenu('b')} />
              <Button title={'医疗常识'} onPress={() => setSecondMenu('c')} />
            </View>
            
            {/* 二级菜单渲染 */}
            {renderSecondMenu(secondMenu)}
          </View>
        </TouchableWithoutFeedback>
      )}
    </>
  );
};

// 渲染二级菜单
const renderSecondMenu = (menuType: string) => {
  const questions = {
    a: symptomQuestions,
    b: healthQuestions,
    c: medicalQuestions
  }[menuType] || [];

  return (
    <View style={{display: menuType ? 'flex' : 'none'}}>
      {questions.map((item, index) => (
        <Button
          key={index}
          title={item.title}
          onPress={() => {
            setUserInput(item.question);
            setFirstMenu(false);
            setSecondMenu('');
          }}
        />
      ))}
    </View>
  );
};

五、常见问题与解决方案

5.1 菜单定位不准

问题:键盘弹出时菜单位置计算错误
解决:使用Keyboard模块的keyboardHeight属性精确计算位置

const [keyboardHeight, setKeyboardHeight] = useState(0);

Keyboard.addListener('keyboardDidShow', (e) => {
  setKeyboardHeight(e.endCoordinates.height);
});

5.2 菜单点击穿透

问题:点击菜单外部无法关闭菜单
解决:使用TouchableWithoutFeedback包裹菜单,并设置点击事件

<TouchableWithoutFeedback onPress={() => setFirstMenu(false)}>
  <View style={styles.menuOverlay}>
    <View style={styles.menuContainer}>
      {/* 菜单内容 */}
    </View>
  </View>
</TouchableWithoutFeedback>

5.3 性能问题

问题:菜单展开时有卡顿
解决

  1. 减少菜单项的复杂度
  2. 使用PureComponent或React.memo优化组件
  3. 避免在渲染函数中进行复杂计算

最终效果:
在这里插入图片描述
在这里插入图片描述

结语

通过本文的介绍,我们详细讲解了React Native中实现AI聊天页面快捷输入和二级菜单功能的全过程。这些功能不仅提升了用户体验,也减少了用户的输入负担。开发者可以根据实际需求进行扩展和优化,如添加更多问题分类、实现问题搜索等。

希望本文对您有所帮助,如果有任何问题或建议,欢迎在评论区留言讨论!

Logo

开源鸿蒙跨平台开发社区汇聚开发者与厂商,共建“一次开发,多端部署”的开源生态,致力于降低跨端开发门槛,推动万物智联创新。

更多推荐