简体   繁体   中英

flutter expansion panel listView Builder

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

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

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM