Липкие вкладки в NestedScrollView с ListViews

#flutter

#flutter

Вопрос:

Макет работает так, как хотелось, за исключением этого:

Когда я прокручиваю одну страницу, вторая страница тоже прокручивается. Не так много, но достаточно, чтобы скрыть первый элемент.

Я мог бы предположить, что это как-то связано с NestedScrollView, но я не знаю, как поступить дальше.

введите описание изображения здесь

 import 'package:flutter/material.dart';

main(){
  runApp(new MaterialApp(
    home: new MyHomePage(),
  ));
}

class MyHomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new DefaultTabController(
      length: 2,
      child: new Scaffold(
        body: NestedScrollView(
          headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) {
            return <Widget>[
              new SliverAppBar(
                title: const Text('Tabs and scrolling'),
                forceElevated: innerBoxIsScrolled,
                pinned: true,
                floating: true,
                bottom: new TabBar(
                  tabs: <Tab>[
                    new Tab(text: 'Page 1'),
                    new Tab(text: 'Page 2'),
                  ],
                ),
              ),
            ];
          },
          body: new TabBarView(
            children: <Widget>[
              _list(),
              _list(),
            ],
          ),
        ),
      ),
    );
  }

  Widget _list(){
    return ListView.builder(
      padding: EdgeInsets.zero,
      itemCount: 250,
      itemBuilder: (context, index){
        return Container(
          color: Colors.grey[200].withOpacity((index % 2).toDouble()),
          child: ListTile(
            title: Text(index.toString()),
          ),
        );
      }
    );
  }
}
  

Ответ №1:

Чтобы иметь возможность прокручивать два ListViews, не влияя друг на друга, они должны иметь определенные контроллеры.

Чтобы ListViews сохраняли свое положение прокрутки при переключении вкладок, вам необходимо разместить их в виджете с AutomaticKeepAliveClientMixin.

Вот пример того, что вы можете сделать вместо вашего метода _list . Определен виджет с отслеживанием состояния, который возвращает ваши списки, используя оба контроллера и AutomaticKeepAliveClientMixin:

 class ItemList extends StatefulWidget {
  @override
  _ItemListState createState() => _ItemListState();
}

class _ItemListState extends State<ItemList> with AutomaticKeepAliveClientMixin{
  ScrollController _scrollController = ScrollController();
  @override
  Widget build(BuildContext context) {
    super.build(context);
    return ListView.builder(
      controller: _scrollController,
      padding: EdgeInsets.zero,
      itemCount: 250,
      itemBuilder: (context, index){
        return Container(
          color: Colors.grey[200].withOpacity((index % 2).toDouble()),
          child: ListTile(
            title: Text(index.toString()),
          ),
        );
      }
    );
  }

  @override
  bool get wantKeepAlive => true;
}
  

Вы можете просто вызвать его обычным способом, как любой другой виджет в вашем TabBarView:

 TabBarView(
  children: <Widget>[
    ItemList(),
    ItemList(),
  ],
),