Home > Mobile >  flutter expansion panel listView Builder
flutter expansion panel listView Builder

Time:01-06

a beginner in a field, I have this code that works, but there is an error in the case of clicking When I click on any card, all cards also open. I want to open a card that I just click on

import 'dart:io';
import 'package:english_club/data/im.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';


class Novals extends StatefulWidget {
  @override
  _NovalsState createState()
  {
    return _NovalsState();
  }
}

class _NovalsState extends State<Novals> {
  bool _expanded = false;
  var _test = "Full Screen";
  @override
  Widget build(BuildContext context) {
    return Scaffold(
       resizeToAvoidBottomInset: false,
      body: ListView.builder(
        itemCount: storys.length,

        itemBuilder: (context, index){
          return SingleChildScrollView(
            child: Column(
              children: [
                Center(
                  child: Container(
                    margin: EdgeInsets.all(10),
                    color: Colors.green,
                    child: ExpansionPanelList(
                    animationDuration: Duration(milliseconds: 2000),
                    children: [
                      ExpansionPanel(
                          headerBuilder: (context, isExpanded) {
                            return ListTile(
                              title: Text(storys[index]["name"], style: TextStyle(color: Colors.black),),
                            );
                          },
                          body:ListTile(
                            title: Text(storys[index]["lines"],style: TextStyle(color: Colors.black)),
                          ),
                        isExpanded: _expanded,
                        canTapOnHeader: true,
                      ),
                    ],
                    dividerColor: Colors.grey,
                    expansionCallback: (panelIndex, isExpanded) {
                      _expanded = !_expanded;
                      setState(() {

                      });
                    },

              ),
             ),
                ),
            ]
            ),
          );
        }
      ),
    );
  }
}

I tried to solve it, but I could not aim for the code to display the name of the story, and when the user clicks on it, the whole story appears

CodePudding user response:

The problem is that you're using the same _expanded variable for items in your ListView.

class _NovalsState extends State<Novals> {
  bool _expanded = false;

  ...

  @override
  Widget build(BuildContext context) {
    ...
  }
}

So when your itemBuilder is called in the ListView, it uses the same _expanded value for every item.

Solution:

Move the _expanded variable from the State to inside the body itemBuilder function.

class _NovalsState extends State<Novals> {

  var _test = "Full Screen";

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      resizeToAvoidBottomInset: false,
      body: ListView.builder(
          itemCount: storys.length,
          itemBuilder: (context, index) {
            bool _expanded = false;
            return SingleChildScrollView(
              child: Column(children: [
                Center(
                  child: Container(
                    margin: EdgeInsets.all(10),
                    color: Colors.green,
                    child: ExpansionPanelList(
                      animationDuration: Duration(milliseconds: 2000),
                      children: [
                        ExpansionPanel(
                          headerBuilder: (context, isExpanded) {
                            return ListTile(
                              title: Text(
                                storys[index]["name"],
                                style: TextStyle(color: Colors.black),
                              ),
                            );
                          },
                          body: ListTile(
                            title: Text(storys[index]["lines"],
                                style: TextStyle(color: Colors.black)),
                          ),
                          isExpanded: _expanded,
                          canTapOnHeader: true,
                        ),
                      ],
                      dividerColor: Colors.grey,
                      expansionCallback: (panelIndex, isExpanded) {
                        _expanded = !_expanded;
                        setState(() {});
                      },
                    ),
                  ),
                ),
              ]),
            );
          }),
    );
  }
}

Checkout Dart's Lexical Scope

CodePudding user response:

Firstly, you should remove the SingleChildScrollView as the ListView child. ListView.builder is enough to provide scrolling to your Scaffold.

For the main issue, you should split each item to a separate Widget with its own _expanded state. This will make your UI much faster, the widgets will expand separately and the whole screen won't have to reload after each item's setState().

Example code:

class Novals extends StatefulWidget {
  @override
  _NovalsState createState()
  {
    return _NovalsState();
  }
}

class _NovalsState extends State<Novals> {
  var _test = "Full Screen";
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      resizeToAvoidBottomInset: false,
      body: ListView.builder(
          itemCount: storys.length,
          itemBuilder: (context, index){
            return StoryWidget(story: storys[index]);
          }
      ),
    );
  }
}

class StoryWidget extends StatefulWidget {
  final Map<String, dynamic> story;
  const StoryWidget({Key? key, required this.story}) : super(key: key);

  @override
  _StoryWidgetState createState() => _StoryWidgetState();
}

class _StoryWidgetState extends State<StoryWidget> {  
bool _expanded = false;

@override
  Widget build(BuildContext context) {
    return Column(
        children: [
          Center(
            child: Container(
              margin: EdgeInsets.all(10),
              color: Colors.green,
              child: ExpansionPanelList(
                animationDuration: Duration(milliseconds: 2000),
                children: [
                  ExpansionPanel(
                    headerBuilder: (context, isExpanded) {
                      return ListTile(
                        title: Text(widget.story["name"], style: TextStyle(color: Colors.black),),
                      );
                    },
                    body:ListTile(
                      title: Text(widget.story["lines"],style: TextStyle(color: Colors.black)),
                    ),
                    isExpanded: _expanded,
                    canTapOnHeader: true,
                  ),
                ],
                dividerColor: Colors.grey,
                expansionCallback: (panelIndex, isExpanded) {
                  _expanded = !_expanded;
                  setState(() {});
                },
              ),
            ),
          ),
        ]
    );
  }
}

P/s: It's a good practice to put your story into a model class using jsonDecode() instead of using Map directly. It would help you avoid bugs and better maintenance in the long term

  •  Tags:  
  • Related