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

React Native自定义动画折叠组件开发问题求助

Fixing Your React Native Custom Collapsible Component Issues

Hey there! Let's work through the two problems you're hitting with your collapsible component. I've broken down the solutions below:

1. Clicking One Component Triggers All to Expand/Collapse

The root issue here is that all your collapsible items are sharing the same state (like expanded, animation) in the parent component. Each item needs its own independent state to control only itself.

Fix: Extract a Reusable CollapsibleItem Component

Move the state and toggle logic into a separate child component so each instance manages its own expansion state:

import React, { Component } from 'react';
import { View, Text, Animated, TouchableHighlight, Image, ScrollView } from 'react-native';
import { Card, CardSection } from './your-components-path'; // Adjust path to your Card components

class CollapsibleItem extends Component {
  constructor(props) {
    super(props);
    this.icons = {
      'up': require('../Images/Arrowhead.png'),
      'down': require('../Images/Arrowhead-Down.png')
    };
    this.state = {
      expanded: false,
      animation: new Animated.Value(0),
      maxHeight: 0,
      minHeight: 0
    };
  }

  toggle = () => {
    const { expanded, animation, maxHeight, minHeight } = this.state;
    const initialValue = expanded ? maxHeight + minHeight : minHeight;
    const finalValue = expanded ? minHeight : maxHeight + minHeight;

    this.setState({ expanded: !expanded });
    animation.setValue(initialValue);
    Animated.spring(animation, {
      toValue: finalValue,
      useNativeDriver: false // Required for height animations in React Native
    }).start();
  };

  _setMaxHeight = (event) => {
    this.setState({ maxHeight: event.nativeEvent.layout.height });
  };

  _setMinHeight = (event) => {
    this.setState({ minHeight: event.nativeEvent.layout.height });
  };

  render() {
    const { curr } = this.props;
    const { expanded } = this.state;
    const icon = expanded ? this.icons['up'] : this.icons['down'];

    return (
      <Animated.View style={[styles.container, { height: this.state.animation }]}>
        {curr.type === 'section' && (
          <View onLayout={this._setMinHeight}>
            <Card>
              <CardSection>
                <TouchableHighlight onPress={this.toggle} underlayColor="#f1f1f1">
                  <Image style={styles.buttonImage} source={icon} />
                </TouchableHighlight>
                <View style={styles.thumbnailContainerStyle}>
                  <Text style={styles.userStyle1}>{curr.title}</Text>
                </View>
              </CardSection>
            </Card>
          </View>
        )}
        <View style={styles.body} onLayout={this._setMaxHeight}>
          {this.props.children}
          <Text>hiii</Text>
        </View>
      </Animated.View>
    );
  }
}

// Parent component where you fetch and render data
class CollapsibleContainer extends Component {
  constructor(props) {
    super(props);
    this.state = {
      details: []
    };
  }

  componentWillMount() {
    fetch('https://www.mywebsite.com')
      .then(response => response.json())
      .then(responseData => this.setState({ details: responseData }));
  }

  render() {
    return (
      <ScrollView>
        {this.state.details.map((detail, index) =>
          detail.data.curriculum.map((curr, currIndex) => (
            <CollapsibleItem key={`${index}-${currIndex}`} curr={curr}>
              {/* Insert your child content here */}
            </CollapsibleItem>
          ))
        )}
      </ScrollView>
    );
  }
}

// Style definitions
const styles = {
  container: {
    overflow: 'hidden', // Critical to clip content when collapsed
    marginVertical: 8,
  },
  buttonImage: {
    width: 20,
    height: 20,
    resizeMode: 'contain'
  },
  thumbnailContainerStyle: {
    marginLeft: 12,
    flex: 1
  },
  userStyle1: {
    fontSize: 16,
    fontWeight: '500'
  },
  body: {
    padding: 12,
    backgroundColor: '#f8f8f8'
  }
};

export default CollapsibleContainer;

2. Card Height Increases But Content Doesn't Show

This issue is tied to how your animated container handles overflow and animation targeting. Here are the key fixes:

  • Add overflow: 'hidden' to the animated container style (see styles.container above) — this ensures content outside the animated height is hidden when collapsed, and visible when expanded.
  • The Animated.View now wraps both the header card and body content, so the height animation applies to the entire item's expandable area.
  • We added useNativeDriver: false to the Animated.spring call — height animations can't use React Native's native driver, so this is required for the animation to work correctly.

Quick Additional Tips

  • Always use unique key props when mapping over arrays (like ${index}-${currIndex}) to help React track component instances accurately.
  • Using arrow functions for event handlers avoids unnecessary re-renders caused by function binding in the render method.

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 04:40:40