简体   繁体   中英

Flutter ExpansionTile with ListView.builder has weird vertical scrolling issues

I have an example of my issue below. When using ListView.builder() to lazy build the items in a list using ExpansionTile(), I have a weird behavior where I am unable to scroll the OVERALL list by grabbing an item from the open expansion tile. If I grab the overall list on a base item in the top level of the list then I can still scroll the whole list.

I wrote a demo app to show this.

If you set the bool flag swapFailureTrigger to true, it's NOT using ListView.builder() for the open expansion tile contents, but just putting it all in memory. Then things work smoothly to scroll vertically no matter where you grab the list.

If you set the bool flag swapFailureTrigger to false then it uses ListView.builder() and you can experience the failure by opening an expansion tile and trying to scroll vertically by grabbing an item in the expanded list.

I'm not sure if it's maybe related to the key I'm using?

import 'package:flutter/material.dart';

// If TRUE, scrolling works well when grabbing an open expansion tile list
// If FALSE, scrolling only works if you grab a parent list OUTSIDE the items of the open expansion tile
bool swapFailureTrigger = false;

class EntryItem extends StatelessWidget {
  const EntryItem(this.entry);

  final Entry entry;

  Widget _buildTiles(Entry root) {
    if (root.children.isEmpty) return ListTile(title: Text(root.title));
    var kids = root.children.map((child) => _buildTiles(child)).toList();

    return ExpansionTile(
      key: PageStorageKey<Entry>(root),
      title: Text(root.title),

      // <<---------- PROBLEM IS HERE if you test with the ListView.builder() version ---------->>
      children: swapFailureTrigger ?
      root.children.map(_buildTiles).toList():
      <Widget>[
        ListView.builder(
          key: PageStorageKey<Entry>(root),
          itemCount: kids.length,
          itemBuilder: (context, index) {
            return kids[index];
          },
          shrinkWrap: true,
        )
      ],
      //  <<--------------------------------------------------------------------------------->>


    );
  }

  @override
  Widget build(BuildContext context) {
    return _buildTiles(entry);
  }
}

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(title: 'Flutter Expansion Issue'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);
  final String title;
  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  int _counter = 0;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: ExpansionTileExample(),
    );
  }
}

class ExpansionTileExample extends StatelessWidget {
  const ExpansionTileExample({Key key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return ListView.builder(
      itemBuilder: (BuildContext context, int index) => EntryItem(data[index]),
      itemCount: data.length,
    );
  }
}

// One entry in the multilevel list displayed by this app.
class Entry {
  const Entry(this.title, [this.children = const <Entry>[]]);
  final String title;
  final List<Entry> children;
}

// Data to display.
const List<Entry> data = <Entry>[
  Entry(
    'Chapter A',
    <Entry>[
      Entry(
        'Section A0',
        <Entry>[
          Entry('Item A0.1'),
          Entry('Item A0.2'),
        ],
      ),
      Entry('Section A1'),
      Entry('Section A2'),
      Entry('Section A3'),
      Entry('Section A4'),
      Entry('Section A5'),
      Entry('Section A6'),
      Entry('Section A7'),
      Entry('Section A8'),
      Entry('Section A9'),
      Entry('Section A10'),
      Entry('Section A11'),
      Entry('Section A12'),
      Entry('Section A13'),
      Entry('Section A14'),
      Entry('Section A15'),
      Entry('Section A16'),
      Entry('Section A17'),
      Entry('Section A18'),
      Entry('Section A19'),
    ],
  ),
  Entry(
    'Chapter B',
    <Entry>[
      Entry('Section B1'),
      Entry('Section B2'),
      Entry('Section B3'),
      Entry('Section B4'),
      Entry('Section B5'),
      Entry('Section B6'),
      Entry('Section B7'),
      Entry('Section B8'),
      Entry('Section B9'),
      Entry('Section B10'),
      Entry('Section B11'),
      Entry('Section B12'),
      Entry('Section B13'),
      Entry('Section B14'),
      Entry('Section B15'),
      Entry('Section B16'),
      Entry('Section B17'),
      Entry('Section B18'),
      Entry('Section B19'),
    ],
  ),
  Entry(
    'Chapter C',
    <Entry>[
      Entry('Section C1'),
      Entry('Section C2'),
      Entry('Section C3'),
      Entry('Section C4'),
      Entry('Section C5'),
      Entry('Section C6'),
      Entry('Section C7'),
      Entry('Section C8'),
      Entry('Section C9'),
      Entry('Section C10'),
      Entry('Section C11'),
      Entry('Section C12'),
      Entry('Section C13'),
      Entry('Section C14'),
      Entry('Section C15'),
      Entry('Section C16'),
      Entry('Section C17'),
      Entry('Section C18'),
      Entry('Section C19'),
    ],
  ),
  Entry(
    'Chapter D',
    <Entry>[
      Entry('Section D1'),
      Entry('Section D2'),
      Entry('Section D3'),
      Entry('Section D4'),
      Entry('Section D5'),
      Entry('Section D6'),
      Entry('Section D7'),
      Entry('Section D8'),
      Entry('Section D9'),
      Entry('Section D10'),
      Entry('Section D11'),
      Entry('Section D12'),
      Entry('Section D13'),
      Entry('Section D14'),
      Entry('Section D15'),
      Entry('Section D16'),
      Entry('Section D17'),
      Entry('Section D18'),
      Entry('Section D19'),
    ],
  ),
  Entry(
    'Chapter E',
    <Entry>[
      Entry('Section E1'),
      Entry('Section E2'),
      Entry('Section E3'),
      Entry('Section E4'),
      Entry('Section E5'),
      Entry('Section E6'),
      Entry('Section E7'),
      Entry('Section E8'),
      Entry('Section E9'),
      Entry('Section E10'),
      Entry('Section E11'),
      Entry('Section E12'),
      Entry('Section E13'),
      Entry('Section E14'),
      Entry('Section E15'),
      Entry('Section E16'),
      Entry('Section E17'),
      Entry('Section E18'),
      Entry('Section E19'),
    ],
  ),
];

Flutter github pointed me to the answer, just FYI:

How to implement Nested ListView in Flutter?

The one line fixed it:

 physics: ClampingScrollPhysics(),

inside the ListView.builder()

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