如何实现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变量,点击头部区域触发状态反转 - 动画优化:利用
AnimatedAPI实现高度过渡,避免展开/收起时的生硬跳转 - 样式适配:代码中样式已贴合截图效果,可根据需求修改边框颜色、内边距、选项数量等细节
内容的提问来源于stack exchange,提问作者FaysalB
相关产品推荐
相关产品推荐

