【问题标题】:Creating an Accordion in React Native with Collapsible在 React Native 中使用 Collapsible 创建手风琴
【发布时间】:2021-11-30 19:08:23
【问题描述】:

我创建了一个手风琴,并为它创建了一些逻辑,但是当我查看我的代码时感觉不对。我不知道在哪里问所以我在这里问。

所以我创建了一个手风琴组件并在我的屏幕上实现了它。这款手风琴的特别之处在于,当一个手风琴打开时,另一个手风琴关闭。所以我使用useState() 作为手风琴的道具转发。 我也想把useState() 放在手风琴里面,但是当我点击另一个手风琴时我不知道如何关闭它。所以我创造了这个。

我需要有关如何改进它或如何使其更清洁的提示,因为现在当我查看代码时它可以工作但看起来不太好。

//AccordionCompontent.js
import React from 'react'
import { StyleSheet, View, Text, Dimensions } from 'react-native';
import Collapsible from 'react-native-collapsible';
import { TouchableWithoutFeedback } from 'react-native-gesture-handler';

const Accordion = props => {


    return (
        <View>
            <TouchableWithoutFeedback onPress={props.onPress}>
            <View style={styles.accordionContainer}>
            <Text style={styles.accordionContainerTitle} >{props.title}</Text>
            </View>
            </TouchableWithoutFeedback>
            <Collapsible style={styles.accordionCollapsedContainer} collapsed={props.isCollapsed}>
                {props.accordionRender}
            </Collapsible>
        </View>
    );
}

export default Accordion;

const styles = StyleSheet.create({
    accordionContainer: {
        justifyContent:'center',
        borderBottomWidth: 1,
        borderBottomColor: '#fff',
       minHeight: Dimensions.get('window').height / 15
    },
    accordionCollapsedContainer: {
        borderBottomWidth: 1,
        borderBottomColor: '#fff'
    },
    accordionContainerTitle: {
        color: '#fff',
        fontSize: 16,
        marginLeft:10
    },

})
//InformationScreen.js
import React, { useCallback, useLayoutEffect, useState } from 'react'
import { Text, View, StyleSheet, TouchableWithoutFeedback } from 'react-native';
import Icon from 'react-native-vector-icons/MaterialIcons'
import BodyText from '../components/Atomic/BodyText';
import Accordion from '../components/Accordion/Accordion';


const InformationScreen = props => {

    const [isCollapsed, setIsCollapsed] = useState([true, true, true, true, true])

    const collapse = (id) => {
        let updatetIsCollapsed = [...isCollapsed]
        updatetIsCollapsed[id] = !updatetIsCollapsed[id]
        const filteredUpdateIsCollapse = updatetIsCollapsed.filter((value, index) => id !== index)
        filteredUpdateIsCollapse.forEach(element => {
            if (!element) {
                const index = filteredUpdateIsCollapse.indexOf(element)
                filteredUpdateIsCollapse[index] = true
            }
        });
        filteredUpdateIsCollapse.splice(id, 0, updatetIsCollapsed[id])
        setIsCollapsed(filteredUpdateIsCollapse)
    }


    useLayoutEffect(() => {
        props.navigation.setOptions({
            title: 'Information',
            headerStyle: {
                backgroundColor: '#000'
            },
            headerTitleStyle: {
                fontSize: 22,
                color: '#fff'
            },
            headerLeft: () => (
                <View></View>
            ),
            headerRight: () => (
                <TouchableWithoutFeedback onPress={() => {
                    props.navigation.popToTop()
                }}>
                    <View style={styles.iconContainer}>
                        <Icon name="home" size={30} color={'#fff'} />
                    </View>
                </TouchableWithoutFeedback>
            )
        })
    })
    return (
        <View style={styles.container}>

            <Accordion onPress={useCallback(() => {
                collapse(0)
            },
                [isCollapsed, setIsCollapsed],
            )} title={"Lorem"} isCollapsed={isCollapsed[0]} accordionRender={
                <View style={styles.accordionItemContainer}>
                    <View style={styles.accordionItemSpacing}>
                        <BodyText>Lorem Ipsum</BodyText>
                        <BodyText>Lorem Ipsum</BodyText>
                    </View>
                    <View>
                        <BodyText>Lorem ipsum</BodyText>
                        <BodyText>Lorem ipsum</BodyText>
                    </View>
                </View>
            } />
            <Accordion onPress={useCallback(() => {
                collapse(1)
            },
                [isCollapsed, setIsCollapsed],
            )} title={"Bla bla"} isCollapsed={isCollapsed[1]} accordionRender={
                <View>
                    <Text>Test</Text>
                    <Text>Test</Text>
                </View>
            } />
            <Accordion onPress={useCallback(() => {
                collapse(2)
            },
                [isCollapsed, setIsCollapsed],
            )} title={"Bla bla"} isCollapsed={isCollapsed[2]} accordionRender={
                <View>
                    <Text>Test</Text>
                    <Text>Test</Text>
                </View>
            } />
            <Accordion onPress={useCallback(() => {
                collapse(3)
            },
                [isCollapsed, setIsCollapsed],
            )} title={"Bla bla"} isCollapsed={isCollapsed[3]} accordionRender={
                <View>
                    <Text>Test</Text>
                    <Text>Test</Text>
                </View>
            } />
            <Accordion onPress={useCallback(() => {
                collapse(4)
            },
                [isCollapsed, setIsCollapsed],
            )} title={"Lorem Ipsum"} isCollapsed={isCollapsed[4]} accordionRender={
                <View style={styles.accordionItemContainer}>
                     <View style={styles.accordionItemSpacing}>
                        <BodyText>Lorem Ipsum</BodyText>
                        <BodyText>Lorem Ipsum</BodyText>
                    </View>
                    <View>
                        <BodyText>Lorem ipsum</BodyText>
                        <BodyText>Lorem ipsum</BodyText>
                    </View>
                </View>
            } />

        </View>
    );
}

const styles = StyleSheet.create({
    container: {
        backgroundColor: '#000',
        flex: 1,
        borderTopWidth: 2,
        borderTopColor: '#fff'
    }
    ,
    iconContainer: {
        height: 50,
        width: 50,
        borderLeftWidth: 2,
        borderLeftColor: '#fff',
        overflow: 'hidden',
        justifyContent: 'center',
        alignItems: 'flex-end'
    },
    accordionContainerTitle: {
        color: '#000',
        fontSize: 16,
    },
    accordionItemContainer: {
        paddingVertical: 10,
    },
    accordionItemText: {
        color: '#000',
        fontSize: 16,
        marginHorizontal: 10,
    },
    accordionItemSpacing: {
        marginBottom: 10
    }
})

export default InformationScreen;

【问题讨论】:

    标签: javascript reactjs react-native react-hooks use-state


    【解决方案1】:
    1. 取下挂钩。 JSX/TSX
    2. 按函数生成手风琴
    3. 使用地图索引道具来切换手风琴
    import React, { useCallback, useLayoutEffect, useState } from 'react'
    import { Text, View, StyleSheet, TouchableWithoutFeedback } from 'react-native';
    import Icon from 'react-native-vector-icons/MaterialIcons'
    import BodyText from '../components/Atomic/BodyText';
    import Accordion from '../components/Accordion/Accordion';
    
    
    const getaccordianItems = () => ([
    
                            <View style={styles.accordionItemSpacing}>
                                <BodyText>Lorem Ipsum</BodyText>
                                <BodyText>Lorem Ipsum</BodyText>
                            </View>
                            <View>
                                <BodyText>Lorem ipsum</BodyText>
                                <BodyText>Lorem ipsum</BodyText>
                            </View>,
    
    <View>
                        <Text>Test</Text>
                        <Text>Test</Text>
                    </View>,
    
    <View>
                        <Text>Test</Text>
                        <Text>Test</Text>
                    </View>,
    
    <View>
                        <Text>Test</Text>
                        <Text>Test</Text>
                    </View>,
    
    <View>
                        <Text>Test</Text>
                        <Text>Test</Text>
                    </View>
    
    ])
    
    const InformationScreen = props => {
    
        
            const [isExpandedIndex, setIsExpanded] = useState();
        
            useLayoutEffect(() => {
                props.navigation.setOptions({
                    title: 'Information',
                    headerStyle: {
                        backgroundColor: '#000'
                    },
                    headerTitleStyle: {
                        fontSize: 22,
                        color: '#fff'
                    },
                    headerLeft: () => (
                        <View></View>
                    ),
                    headerRight: () => (
                        <TouchableWithoutFeedback onPress={() => {
                            props.navigation.popToTop()
                        }}>
                            <View style={styles.iconContainer}>
                                <Icon name="home" size={30} color={'#fff'} />
                            </View>
                        </TouchableWithoutFeedback>
                    )
                })
            })
            return (
                <View style={styles.container}>
                    {accordionList.map((item,index)=>(
                    <Accordion onPress={()=> { setIsExpanded(index) }} title={"Lorem"} isCollapsed={isExpanded !== index} accordionRender={
                        <View style={styles.accordionItemContainer}>
                            {item}
                        </View>
                      } />
                    )}
        
                </View>
            );
        }
        
        const styles = StyleSheet.create({
            container: {
                backgroundColor: '#000',
                flex: 1,
                borderTopWidth: 2,
                borderTopColor: '#fff'
            }
            ,
            iconContainer: {
                height: 50,
                width: 50,
                borderLeftWidth: 2,
                borderLeftColor: '#fff',
                overflow: 'hidden',
                justifyContent: 'center',
                alignItems: 'flex-end'
            },
            accordionContainerTitle: {
                color: '#000',
                fontSize: 16,
            },
            accordionItemContainer: {
                paddingVertical: 10,
            },
            accordionItemText: {
                color: '#000',
                fontSize: 16,
                marginHorizontal: 10,
            },
            accordionItemSpacing: {
                marginBottom: 10
            }
        })
        
        export default InformationScreen;
    
    

    【讨论】:

    • 这是一个不错的方法,它给了我一些想法,但它不是解决方案。它总是生成一个同名的手风琴,当我关闭另一个时,它会打开。但是如何编写它的想法看起来不错。
    • 其实我发现了问题,你的想法很好。问题是,当属性为真时手风琴折叠起来,当属性为假时关闭,所以我只是放了!在 iScollapsed 道具上。但仍然需要弄清楚如何获得自定义名称
    • 为什么需要自定义名称?
    • 我需要它,所以我可以把它作为手风琴的标题。但是我修复了这个问题,我也找到了一些方法,如果有人在手风琴打开时按下手风琴来关闭它,我也需要它,但我也这样做了,我现在将发布我的代码作为答案,你可以评论它也许有更好的方法.
    【解决方案2】:

    好的,在Michael Bahl 的帮助下,我能够编写一些更好的代码。他的代码很好,但我做了一些调整。现在一切正常,我可以把我需要的所有东西都放在我的手风琴里。

    我在手风琴Compontent.js 中做了一个小改动,在屏幕上,我应用了 Michael 展示的代码并进行了一些小调整,以使其对我来说更灵活。

    //AccordionCompontent.js
    import React from 'react'
    import { StyleSheet, View, Text, Dimensions } from 'react-native';
    import Collapsible from 'react-native-collapsible';
    import { TouchableWithoutFeedback } from 'react-native-gesture-handler';
    
    const Accordion = props => {
    
    
        return (
            <View>
                <TouchableWithoutFeedback onPress={props.onPress}>
                <View style={styles.accordionContainer}>
                <Text style={styles.accordionContainerTitle} >{props.title}</Text>
                </View>
                </TouchableWithoutFeedback>
                <Collapsible style={styles.accordionCollapsedContainer} 
                 //The small change is at collapsed
                 collapsed={!props.isCollapsed}>
                    {props.accordionRender}
                </Collapsible>
            </View>
        );
    }
    
    export default Accordion;
    
    const styles = StyleSheet.create({
        accordionContainer: {
            justifyContent:'center',
            borderBottomWidth: 1,
            borderBottomColor: '#fff',
           minHeight: Dimensions.get('window').height / 15
        },
        accordionCollapsedContainer: {
            borderBottomWidth: 1,
            borderBottomColor: '#fff'
        },
        accordionContainerTitle: {
            color: '#fff',
            fontSize: 16,
            marginLeft:10
        },
    
    })
    
    import React, { useCallback, useLayoutEffect, useState } from 'react'
    import { Text, View, StyleSheet, TouchableWithoutFeedback } from 'react-native';
    import Icon from 'react-native-vector-icons/MaterialIcons'
    import BodyText from '../components/Atomic/BodyText';
    import Accordion from '../components/Accordion/Accordion';
    
    const getAccordionItems = (version, expiresDate, scriptSize, packageSize) => ([
        ['General Information',
            <View>
                <View style={styles.accordionItemSpacing}>
                    <BodyText>Version {version}</BodyText>
                    <BodyText>License expires on {expiresDate}</BodyText>
                </View>
                <View>
                    <BodyText>Size of scripts folder: {scriptSize} MB</BodyText>
                    <BodyText>Size of packages folder: {packageSize} MB</BodyText>
                </View>
            </View>],
    
        ['lorem',
            <View>
                <View style={styles.accordionItemSpacing}>
                    <BodyText>Lorem Ipsum</BodyText>
                    <BodyText>Lorem Ipsum</BodyText>
                </View>
                <View>
                    <BodyText>Lorem ipsum</BodyText>
                    <BodyText>Lorem ipsum</BodyText>
                </View>
            </View>],
        ['lorem',
            <View>
                <View style={styles.accordionItemSpacing}>
                    <BodyText>Lorem Ipsum</BodyText>
                    <BodyText>Lorem Ipsum</BodyText>
                </View>
                <View>
                    <BodyText>Lorem ipsum</BodyText>
                    <BodyText>Lorem ipsum</BodyText>
                </View>
            </View>],
    ])
    
    const InformationScreen = props => {
        const accordionList = getAccordionItems('1.0', '2021/10/20', 1.00, 0.00)
    
        const [isExpanded, setIsExpanded] = useState();
    
        useLayoutEffect(() => {
            props.navigation.setOptions({
                title: 'Information',
                headerStyle: {
                    backgroundColor: '#000'
                },
                headerTitleStyle: {
                    fontSize: 22,
                    color: '#fff'
                },
                headerLeft: () => (
                    <View></View>
                ),
                headerRight: () => (
                    <TouchableWithoutFeedback onPress={() => {
                        props.navigation.popToTop()
                    }}>
                        <View style={styles.iconContainer}>
                            <Icon name="home" size={30} color={'#fff'} />
                        </View>
                    </TouchableWithoutFeedback>
                )
            })
        })
    
        accordionList.map((item, index) => {
            console.log(item)
            console.log(index)
        })
        return (
            <View style={styles.container}>
                {accordionList.map((item, index) => (
                    <Accordion onPress={() => { 
                        if (isExpanded === index){
                            setIsExpanded(accordionList.size)
                        } else{
                        setIsExpanded(index) 
                        }
                }} title={item[0]} isCollapsed={isExpanded === index} accordionRender={
                        <View style={styles.accordionItemContainer}>
                            {item[1]}
                        </View>
                    } />
                ))}
            </View>
        );
    }
    
    const styles = StyleSheet.create({
        container: {
            backgroundColor: '#000',
            flex: 1,
            borderTopWidth: 2,
            borderTopColor: '#fff'
        }
        ,
        iconContainer: {
            height: 50,
            width: 50,
            borderLeftWidth: 2,
            borderLeftColor: '#fff',
            overflow: 'hidden',
            justifyContent: 'center',
            alignItems: 'flex-end'
        },
        accordionContainerTitle: {
            color: '#fff',
            fontSize: 16,
        },
        accordionItemContainer: {
            paddingVertical: 10,
        },
        accordionItemText: {
            color:'#fff',
            fontSize: 16,
            marginHorizontal: 10,
        },
        accordionItemSpacing: {
            marginBottom: 10
        }
    })
    
    export default InformationScreen;
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2022-12-18
      • 1970-01-01
      • 1970-01-01
      • 2016-03-28
      • 2014-07-31
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多