React native创建一个可扩展的列表组件,带有复选框并选择All选项

vmjh9lq9  于 2023-10-23  发布在  React
关注(0)|答案(1)|浏览(138)

我已经创建了一个组件后,教程,但在点击复选框无论是在父或子类别项目复选框,我不能改变复选框的状态。请检查我如何重新使用(或者如果其他方法更好,请分享)复选框项目上的islogic方法单击以更改图标状态,并在单击底部的按钮时获得所有选中的项目。先谢了。

// Import React
    import React, { useEffect, useState } from 'react';
    // Import required components
    import {
        SafeAreaView,
        LayoutAnimation,
        StyleSheet,
        View,
        Image,
        Text,
        ScrollView,
        UIManager,
        TouchableOpacity,
        Platform,
    } from 'react-native';
    import ImageName from '../../../assets/imageName/ImageName';
    
    const ExpandableComponent = ({ item, onClickFunction }) => {
        //Custom Component for the Expandable List
        const [layoutHeight, setLayoutHeight] = useState(0);
        const [checkedItems, setCheckedItems] = useState([]);
    
        const isChecked = (id) => {
            return checkedItems.includes(id);
        };
        useEffect(() => {
            if (item.isExpanded) {
                setLayoutHeight(null);
            } else {
                setLayoutHeight(0);
            }
        }, [item.isExpanded]);
    
        console.log('isChecked', isChecked(item.id))
        return (
            <View>
                {/*Header of the Expandable List Item*/}
                <TouchableOpacity
                    activeOpacity={0.8}
                    onPress={onClickFunction}
                    style={styles.header}>
                    <View style={{ flexDirection: 'row', alignItems: 'center' }}>
    
                        <Image style={{ height: 20, width: 20, margin: 10, tintColor: '#FEC432' }}
                            source={isChecked(item.id) ? ImageName.checked : ImageName.unchecked} />
    
                        <Text style={styles.headerText}>
                            {item.category_name}
                        </Text>
                    </View>
                </TouchableOpacity>
                <View
                    style={{
                        height: layoutHeight,
                        overflow: 'hidden',
                    }}>
                    {/*Content under the header of the Expandable List Item*/}
                    {item.subcategory.map((item, key) => (
                        <TouchableOpacity
                            key={key}
                            style={styles.content}
                            onPress={
                                () => {
                                    isChecked(item.id)
                                    console.log('Id: ' + item.id + ' val: ' + item.val)
                                }
                            }>
                            <View style={{ flexDirection: 'row', alignItems: 'center' }}>
    
                                <Image style={{ height: 20, width: 20, margin: 10, tintColor: '#FEC432' }}
                                    source={false ? ImageName.checked : ImageName.unchecked} />
                                <Text style={styles.headerText}>
                                    {key}. {item.val}
                                </Text>
                            </View>
                        </TouchableOpacity>
                    ))}
                </View>
            </View>
        );
    };
    
    const TestExpandible = () => {
        const [listDataSource, setListDataSource] = useState(CONTENT);
        const [checkedItems, setCheckedItems] = useState([]);
    
        const isChecked = (id) => {
            return checkedItems.includes(id);
        };
    
        const toggleItem = (id) => {
    
            if (isChecked(id)) {
                setCheckedItems(checkedItems.filter(item => item !== id));
            } else {
                setCheckedItems([...checkedItems, id]);
            }
        };
    
        if (Platform.OS === 'android') {
            UIManager.setLayoutAnimationEnabledExperimental(true);
        }
    
        const updateLayout = (index) => {
            LayoutAnimation.configureNext(LayoutAnimation.Presets.easeInEaseOut);
            const array = [...listDataSource];
    
            array.map((it) => {
                toggleItem(it.id)
            })
         
            array.map((value, placeindex) =>
                placeindex === index
                    ? (array[placeindex]['isExpanded'] =
                        !array[placeindex]['isExpanded'])
                    : (array[placeindex]['isExpanded'] = false),
            );
   
    
            setListDataSource(array);
        };
    
        return (
            <SafeAreaView style={{ flex: 1 }}>
                <View style={styles.container}>
                    
                    <ScrollView>
                        {listDataSource.map((item, key) => (
                            <ExpandableComponent
                                key={item.category_name}
                                onClickFunction={() => {
                                    updateLayout(key);
                                }}
                                item={item}
                            />
                        ))}

//here somewhere at bottom I'll add button to get all checked items
                    </ScrollView>
                </View>
            </SafeAreaView>
        );
    };
    
    export default TestExpandible;
    const styles = StyleSheet.create({
        container: {
            flex: 1,
        },
        titleText: {
            flex: 1,
            fontSize: 22,
            fontWeight: 'bold',
        },
        header: {
            backgroundColor: '#F5FCFF',
            padding: 20,
        },
        headerText: {
            fontSize: 16,
            fontWeight: '500',
        },
        separator: {
            height: 0.5,
            backgroundColor: '#808080',
            width: '95%',
            marginLeft: 16,
            marginRight: 16,
        },
        text: {
            fontSize: 16,
            color: '#606070',
            padding: 10,
        },
        content: {
            paddingLeft: 10,
            paddingRight: 10,
            backgroundColor: '#fff',
        },
    });
    
    //Dummy content
    const CONTENT = [
        {
            isExpanded: false,
            category_name: 'Item 1',
            id: 1,
            subcategory: [
                { id: 1, val: 'Sub Cat 1' },
                { id: 3, val: 'Sub Cat 3' },
            ],
        },
        {
            isExpanded: false,
            category_name: 'Item 2',
            id: 2,
            subcategory: [
                { id: 4, val: 'Sub Cat 4' },
                { id: 5, val: 'Sub Cat 5' },
            ],
        },
        {
            isExpanded: false,
            category_name: 'Item 3',
            id: 3,
            subcategory: [
                { id: 7, val: 'Sub Cat 7' },
                { id: 9, val: 'Sub Cat 9' },
            ],
        },
        {
            isExpanded: false,
            category_name: 'Item 4',
            id: 4,
            subcategory: [
                { id: 10, val: 'Sub Cat 10' },
                { id: 12, val: 'Sub Cat 2' },
            ],
        },
        {
            isExpanded: false,
            category_name: 'Item 5',
            id: 5,
            subcategory: [
                { id: 13, val: 'Sub Cat 13' },
                { id: 15, val: 'Sub Cat 5' },
            ],
        },
        {
            isExpanded: false,
            category_name: 'Item 6',
            id: 6,
            subcategory: [
                { id: 17, val: 'Sub Cat 17' },
                { id: 18, val: 'Sub Cat 8' },
            ],
        },
        {
            isExpanded: false,
            category_name: 'Item 7',
            id: 7,
            subcategory: [{ id: 20, val: 'Sub Cat 20' }],
        }
    ];
cnjp1d6j

cnjp1d6j1#

你好首先你需要创建组件

import React from 'react';
import { TouchableOpacity, Image } from 'react-native';

const Checkbox = ({ checked, onChange }) => {
  return (
    <TouchableOpacity onPress={onChange}>
      <Image
        style={{ height: 20, width: 20, margin: 10, tintColor: '#FEC432' }}
        source={checked ? require('../assets/images/checked.png') : require('../assets/images/unchecked.png')}
      />
    </TouchableOpacity>
  );
};

export default Checkbox;

在此之后,实现我在下面添加的代码

import React, { useEffect, useState } from 'react';
import {
  SafeAreaView,
  LayoutAnimation,
  StyleSheet,
  View,
  Image,
  Text,
  ScrollView,
  UIManager,
  TouchableOpacity,
  Platform,
} from 'react-native';

import Checkbox from '../../components/Checkbox'; // Import the Checkbox component

const ExpandableComponent = ({ item, onClickFunction, onCheckboxChange }) => {
  const [layoutHeight, setLayoutHeight] = useState(0);

  useEffect(() => {
    if (item.isExpanded) {
      setLayoutHeight(null);
    } else {
      setLayoutHeight(0);
    }
  }, [item.isExpanded]);

  return (
    <View>
      {/* Header of the Expandable List Item */}
      <TouchableOpacity activeOpacity={0.8} onPress={onClickFunction} style={styles.header}>
        <View style={{ flexDirection: 'row', alignItems: 'center' }}>
          {/* Use the Checkbox component for the category */}
          <Checkbox checked={item.isChecked} onChange={() => onCheckboxChange(item.id)} />

          <Text style={styles.headerText}>{item.category_name}</Text>
        </View>
      </TouchableOpacity>
      <View style={{ height: layoutHeight, overflow: 'hidden' }}>
        {/* Content under the header of the Expandable List Item */}
        {item.subcategory.map((subItem, key) => (
          <TouchableOpacity
            key={key}
            style={styles.content}
            onPress={() => {
              // Use the Checkbox component for subcategories
              onCheckboxChange(subItem.id);
            }}>
            <View style={{ flexDirection: 'row', alignItems: 'center' }}>
              {/* Use the Checkbox component for subcategories */}
              <Checkbox checked={subItem.isChecked} onChange={() => onCheckboxChange(subItem.id)} />
              <Text style={styles.headerText}>{key}. {subItem.val}</Text>
            </View>
          </TouchableOpacity>
        ))}
      </View>
    </View>
  );
};
const CONTENT = [
  {
      isExpanded: false,
      category_name: 'Item 1',
      id: 1,
      subcategory: [
          { id: 1, val: 'Sub Cat 1' },
          { id: 3, val: 'Sub Cat 3' },
      ],
  },
  {
      isExpanded: false,
      category_name: 'Item 2',
      id: 2,
      subcategory: [
          { id: 4, val: 'Sub Cat 4' },
          { id: 5, val: 'Sub Cat 5' },
      ],
  },
  {
      isExpanded: false,
      category_name: 'Item 3',
      id: 3,
      subcategory: [
          { id: 7, val: 'Sub Cat 7' },
          { id: 9, val: 'Sub Cat 9' },
      ],
  },
  {
      isExpanded: false,
      category_name: 'Item 4',
      id: 4,
      subcategory: [
          { id: 10, val: 'Sub Cat 10' },
          { id: 12, val: 'Sub Cat 2' },
      ],
  },
  {
      isExpanded: false,
      category_name: 'Item 5',
      id: 5,
      subcategory: [
          { id: 13, val: 'Sub Cat 13' },
          { id: 15, val: 'Sub Cat 5' },
      ],
  },
  {
      isExpanded: false,
      category_name: 'Item 6',
      id: 6,
      subcategory: [
          { id: 17, val: 'Sub Cat 17' },
          { id: 18, val: 'Sub Cat 8' },
      ],
  },
  {
      isExpanded: false,
      category_name: 'Item 7',
      id: 7,
      subcategory: [{ id: 20, val: 'Sub Cat 20' }],
  }
];

const LoginScreen = () => {
  const [listDataSource, setListDataSource] = useState(CONTENT);

  const toggleItem = (id) => {
    setListDataSource((prevState) =>
      prevState.map((item) => {
        if (item.id === id) {
          return { ...item, isChecked: !item.isChecked };
        } else if (item.subcategory.some((subItem) => subItem.id === id)) {
          const subcategory = item.subcategory.map((subItem) =>
            subItem.id === id ? { ...subItem, isChecked: !subItem.isChecked } : subItem
          );
          return { ...item, subcategory };
        }
        return item;
      })
    );
  };

  const getCheckedItems = () => {
    const checkedItems = listDataSource.reduce((result, item) => {
      if (item.isChecked) {
        result.push({ id: item.id, name: item.category_name });
      }
      item.subcategory.forEach((subItem) => {
        if (subItem.isChecked) {
          result.push({ id: subItem.id, name: subItem.val });
        }
      });
      return result;
    }, []);
    console.log('Checked Items:', checkedItems);
  };

  if (Platform.OS === 'android') {
    UIManager.setLayoutAnimationEnabledExperimental(true);
  }

  const updateLayout = (index) => {
    LayoutAnimation.configureNext(LayoutAnimation.Presets.easeInEaseOut);
    setListDataSource((prevState) =>
      prevState.map((item, i) => ({
        ...item,
        isExpanded: i === index ? !item.isExpanded : false,
      }))
    );
  };

  return (
    <SafeAreaView style={{ flex: 1 }}>
      <View style={styles.container}>
        <ScrollView>
          {listDataSource.map((item, key) => (
            <ExpandableComponent
              key={item.category_name}
              onClickFunction={() => updateLayout(key)}
              item={item}
              onCheckboxChange={toggleItem}
            />
          ))}
          <TouchableOpacity onPress={getCheckedItems}>
            <Text>Get Checked Items</Text>
          </TouchableOpacity>
        </ScrollView>
      </View>
    </SafeAreaView>
  );
};
export default LoginScreen;
const styles = StyleSheet.create({
  container: {
      flex: 1,
  },
  titleText: {
      flex: 1,
      fontSize: 22,
      fontWeight: 'bold',
  },
  header: {
      backgroundColor: '#F5FCFF',
      padding: 20,
  },
  headerText: {
      fontSize: 16,
      fontWeight: '500',
  },
  separator: {
      height: 0.5,
      backgroundColor: '#808080',
      width: '95%',
      marginLeft: 16,
      marginRight: 16,
  },
  text: {
      fontSize: 16,
      color: '#606070',
      padding: 10,
  },
  content: {
      paddingLeft: 10,
      paddingRight: 10,
      backgroundColor: '#fff',
  },
});

只是复制和过去的代码
happy coding:)

相关问题