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

如何实现React Native手风琴式模态框?(命名存疑)

React Native 手风琴式切换组件实现方案

核心思路

通过React状态管理控制组件展开/收起状态,搭配Animated API实现平滑过渡动画,还原你需要的手风琴效果。

代码实现

1. 基础无动画版本

import React, { useState } from 'react';
import { View, Text, TouchableOpacity, StyleSheet } from 'react-native';

const AccordionModal = () => {
  const [isExpanded, setIsExpanded] = useState(false);

  return (
    <View style={styles.container}>
      {/* 头部点击区域 */}
      <TouchableOpacity 
        style={styles.header}
        onPress={() => setIsExpanded(!isExpanded)}
      >
        <Text style={styles.headerText}>选择选项</Text>
        <Text style={styles.arrow}>{isExpanded ? '▲' : '▼'}</Text>
      </TouchableOpacity>

      {/* 展开内容区域 */}
      {isExpanded && (
        <View style={styles.content}>
          <TouchableOpacity style={styles.option}>
            <Text>选项1</Text>
          </TouchableOpacity>
          <TouchableOpacity style={styles.option}>
            <Text>选项2</Text>
          </TouchableOpacity>
          <TouchableOpacity style={styles.option}>
            <Text>选项3</Text>
          </TouchableOpacity>
        </View>
      )}
    </View>
  );
};

const styles = StyleSheet.create({
  container: {
    width: '90%',
    borderWidth: 1,
    borderColor: '#ccc',
    borderRadius: 8,
    overflow: 'hidden',
  },
  header: {
    flexDirection: 'row',
    justifyContent: 'space-between',
    alignItems: 'center',
    padding: 16,
    backgroundColor: '#f5f5f5',
  },
  headerText: {
    fontSize: 16,
    fontWeight: '500',
  },
  arrow: {
    fontSize: 18,
  },
  content: {
    backgroundColor: '#fff',
  },
  option: {
    padding: 16,
    borderTopWidth: 1,
    borderTopColor: '#eee',
  },
});

export default AccordionModal;

2. 带平滑过渡动画版本

import React, { useState, useRef, useEffect } from 'react';
import { View, Text, TouchableOpacity, StyleSheet, Animated } from 'react-native';

const AccordionModal = () => {
  const [isExpanded, setIsExpanded] = useState(false);
  const heightAnim = useRef(new Animated.Value(0)).current;

  useEffect(() => {
    Animated.timing(heightAnim, {
      toValue: isExpanded ? 1 : 0,
      duration: 300,
      useNativeDriver: false,
    }).start();
  }, [isExpanded]);

  // 插值计算内容高度,可根据实际选项数量调整输出值
  const contentHeight = heightAnim.interpolate({
    inputRange: [0, 1],
    outputRange: [0, 144],
  });

  return (
    <View style={styles.container}>
      <TouchableOpacity 
        style={styles.header}
        onPress={() => setIsExpanded(!isExpanded)}
      >
        <Text style={styles.headerText}>选择选项</Text>
        <Text style={styles.arrow}>{isExpanded ? '▲' : '▼'}</Text>
      </TouchableOpacity>

      <Animated.View style={[styles.content, { height: contentHeight }]}>
        <TouchableOpacity style={styles.option}>
          <Text>选项1</Text>
        </TouchableOpacity>
        <TouchableOpacity style={styles.option}>
          <Text>选项2</Text>
        </TouchableOpacity>
        <TouchableOpacity style={styles.option}>
          <Text>选项3</Text>
        </TouchableOpacity>
      </Animated.View>
    </View>
  );
};

const styles = StyleSheet.create({
  container: {
    width: '90%',
    borderWidth: 1,
    borderColor: '#ccc',
    borderRadius: 8,
    overflow: 'hidden',
  },
  header: {
    flexDirection: 'row',
    justifyContent: 'space-between',
    alignItems: 'center',
    padding: 16,
    backgroundColor: '#f5f5f5',
  },
  headerText: {
    fontSize: 16,
    fontWeight: '500',
  },
  arrow: {
    fontSize: 18,
  },
  content: {
    backgroundColor: '#fff',
    overflow: 'hidden',
  },
  option: {
    padding: 16,
    borderTopWidth: 1,
    borderTopColor: '#eee',
  },
});

export default AccordionModal;

细节调整说明

  • 状态切换:通过useState维护isExpanded变量,点击头部区域触发状态反转
  • 动画优化:利用Animated API实现高度过渡,避免展开/收起时的生硬跳转
  • 样式适配:代码中样式已贴合截图效果,可根据需求修改边框颜色、内边距、选项数量等细节

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.06 20:01:21