Flutter Conversion – UICollectionViewDiffableDataSource

Issue

Im trying to convert my existing iOS Application into Flutter.

In iOS I’m using UICollectionViewDiffableDataSource to view a structure like that:

struct ClassItem: Hashable{
 let year: String
 let students: [StudentItem]
}

let BiologyClass = [
 ClassItem(year: "2021", students: [
  StudentItem(name: "Michael Pearson", favColor: "blue"),
  StudentItem(name: "Pearson Michael", favColor: "green")
 ]),
 ClassItem(year: "2020", students: [
  StudentItem(name: "Steve Pearson", favColor: "blue"),
  StudentItem(name: "Steve Michael", favColor: "green"),
  StudentItem(name: "Pearson Steve", favColor: "red")
 ]),

That looks like this:

iosView

In Flutter I try to work with an ExpansionPanel:

  Widget build(BuildContext context) {
    return ExpansionPanelList(
            children: [
              ExpansionPanel(
                headerBuilder: (context, isExpanded) {
                  return ListTile(
                    title: Text(
                      '2021',
                      style: TextStyle(color: Colors.black),
                    ),
                  );
                },
                body: Column(
                  children: [
                    ListTile(
                      title: Text('Description text',
                          style: TextStyle(color: Colors.black)),
                    ),
                    ListTile(
                      title: Text('Description text2',
                          style: TextStyle(color: Colors.black)),
                    ),
                  ],
                ),
                isExpanded: _expanded,
                canTapOnHeader: true,
              ),
            ],
            dividerColor: Colors.grey,
            expansionCallback: (panelIndex, isExpanded) {
              _expanded = !_expanded;
              setState(() {});
            },
      
    ); 

So the question is, how is it possible to create a variable number of Tiles within the ExpansionPanel. Or better, how is it possible to build something like shown with using UICollectionViewDiffableDataSource in iOS env. Currently I would have to create all tiles by hand and that is just not feasible in the final version.
Flutter looks like this currently:

FlutterView

Thanks.

EDIT:
There is an error "Duplicate Keys Found".
The following image is showing the debugging window.
I don’t know why the entry is doubled.
Debug

EDIT2: Got It, there was a line commented out in the CustomExpansionTile!

Solution

Output:

enter image description here

Create Data Models similar to Swift structs and datasource as BiologyClass:

class ClassItem {
  ClassItem({this.isExpanded: false, this.year, this.students});

  bool isExpanded;
  final String year;
  final List<StudentItem> students;
}

class StudentItem {
  StudentItem({this.name, this.favColor});

  final String name;
  final String favColor;
}

Now you can iterate through the items and populate the ExpansionPanelList with dynamic data:

class _MyHomePageState extends State<MyHomePage> {
  List<ClassItem> _items = <ClassItem>[
    ClassItem(year: "2021", students: [
      StudentItem(favColor: "blue", name: "Michael Pearson"),
      StudentItem(favColor: "green", name: "Pearson Michael")
    ]),
    ClassItem(year: "2020", students: [
      StudentItem(favColor: "blue", name: "Steve Pearson"),
      StudentItem(favColor: "green", name: "Steve Michael"),
      StudentItem(favColor: "red", name: "Pearson Steve")
    ]),
  ];

  @override
  Widget build(BuildContext context) {
    return ListView(
      children: <Widget>[
        ExpansionPanelList(
          expansionCallback: (int index, bool isExpanded) {
            setState(() {
              _items[index].isExpanded = !_items[index].isExpanded;
            });
          },
          children: _items.map((ClassItem item) {
            return ExpansionPanel(
              headerBuilder: (BuildContext context, bool isExpanded) {
                return Text(item.year);
              },
              isExpanded: item.isExpanded,
              body: Column(children: [
                ...item.students.map((StudentItem student) {
                  return GestureDetector(
                    onTap: () {
                      print(student.name);
                    },
                    child: Container(child: Padding(padding: const EdgeInsets.all(8.0), child: Text(student.name))),
                  );
                }).toList(),
              ]),
            );
          }).toList(),
        )
      ],
    );
  }
}

Answered By – RTXGamer

Answer Checked By – Timothy Miller (FlutterFixes Admin)

Leave a Reply

Your email address will not be published.