Flutter 解决NestedScrollView与TabBar双列表滚动位置同步问题



前言

最近写flutter项目,遇到NestedScrollView与TabBar双列表滚动位置同步问题,下面是解决方案,希望帮助到大家。


一、需要实现的效果如下

1、UI图:
请添加图片描述
需要实现的效果是,左边滑动的时候,右边的列表不要随左边滑动。右边滑动的时候,左边也不要滑动。

二、flutter实现代码如下:

1、用flutter原生的NestedScrollView是有问题的
2、使用第三方库解决这个问题extended_nested_scroll_view: ^6.2.1
3、完整的代码如下:

import 'package:extended_nested_scroll_view/extended_nested_scroll_view.dart';
import 'package:flutter/material.dart';

void main() {
  runApp(const MyBitApp());
}

class MyBitApp extends StatelessWidget {
  const MyBitApp({super.key});

  // This widget is the root of your application.
  
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
        useMaterial3: true,
      ),
      home: MyApp(),
    );
  }
}

class MyApp extends StatelessWidget {
  
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'NestedScrollView Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> with SingleTickerProviderStateMixin {
  late TabController _tabController;
  late List<ScrollController> _scrollControllers;
  late ScrollController nestedScrollController;

  
  void initState() {
    super.initState();
    _tabController = TabController(length: 2, vsync: this);
    _scrollControllers = [
      ScrollController(),
      ScrollController(),
    ];
    nestedScrollController = ScrollController();
  }

  
  void dispose() {
    _tabController.dispose();
    for (var controller in _scrollControllers) {
      controller.dispose();
    }
    super.dispose();
  }

  
  Widget build(BuildContext context) {
    // var tabBarHeight = primaryTabBar.preferredSize.height;
    double statusBarHeight = MediaQuery.of(context).padding.top;
    var pinnedHeaderHeight = statusBarHeight + kToolbarHeight;
    return Scaffold(
      body: DefaultTabController(
        length: 2,
        child: ExtendedNestedScrollView(
          onlyOneScrollInBody: true,
          pinnedHeaderSliverHeightBuilder: () => pinnedHeaderHeight,
          headerSliverBuilder: (context, innerBoxIsScrolled) {
            return [
              SliverAppBar(
                title: Text('NestedScrollView Demo'),
                pinned: true,
                floating: true,
                expandedHeight: 200,
                stretch: true,
                elevation: 0,
                stretchTriggerOffset: 100,
                bottom: TabBar(
                  controller: _tabController,
                  tabs: [
                    Tab(text: 'Tab 1'),
                    Tab(text: 'Tab 2'),
                  ],
                ),
              ),
            ];
          },
          body: TabBarView(
            controller: _tabController,
            children: [
              KeepAliveWrapper(
                child: MediaQuery.removePadding(
                  removeTop: true,
                  context: context,
                  child: ListView.builder(
                    itemCount: 1000,
                    itemBuilder: (context, index) {
                      return ListTile(
                        title: Text('Tab 1 Item $index'),
                      );
                    },
                  ),
                ),
              ),
              KeepAliveWrapper(
                child: MediaQuery.removePadding(
                  removeTop: true,
                  context: context,
                  child: ListView.builder(
                    itemCount: 1000,
                    itemBuilder: (context, index) {
                      return ListTile(
                        title: Text('Tab 2 Item $index'),
                      );
                    },
                  ),
                ),
              ),
            ],
          ),
        ),
      ),
    );
  }
}

class KeepAliveWrapper extends StatefulWidget {
  final Widget child;

  const KeepAliveWrapper({Key? key, required this.child}) : super(key: key);

  
  _KeepAliveWrapperState createState() => _KeepAliveWrapperState();
}

class _KeepAliveWrapperState extends State<KeepAliveWrapper> with AutomaticKeepAliveClientMixin {
  
  Widget build(BuildContext context) {
    super.build(context);
    return widget.child;
  }

  
  bool get wantKeepAlive => true;
}

总结

这就是Flutter解决NestedScrollView与TabBar双列表滚动位置同步问题相关代码,希望能帮助到你!

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
要实现 Flutter NestedScrollView 和 TabView 滚动列表某一项,可以使用 ScrollController 和 TabController 来实现。 步骤如下: 1. 在 NestedScrollView 中添加 controller 属性,用于监听滚动事件。 2. 在 TabView 中添加 controller 属性,用于控制 Tab 切换。 3. 在列表中添加 controller 属性,用于监听列表滚动事件。 4. 在 TabView 中添加 onTap 属性,用于监听 Tab 切换事件。 5. 在 onTap 事件中,使用 ScrollController 和 TabController 来控制列表和 TabView 的滚动和切换。 具体实现细节可以参考以下代码: ```dart class MyPage extends StatefulWidget { @override _MyPageState createState() => _MyPageState(); } class _MyPageState extends State<MyPage> with SingleTickerProviderStateMixin { TabController _controller; ScrollController _scrollController; List _tabs = ['Tab1', 'Tab2', 'Tab3', 'Tab4', 'Tab5']; List<Widget> _tabViews = []; @override void initState() { super.initState(); _controller = TabController(length: _tabs.length, vsync: this); _scrollController = ScrollController(); for (int i = 0; i < _tabs.length; i++) { _tabViews.add(ListView.builder( controller: _scrollController, itemCount: 50, itemBuilder: (context, index) { return ListTile( title: Text('${_tabs[i]} - Item $index'), ); }, )); } } @override void dispose() { _controller.dispose(); _scrollController.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return Scaffold( body: NestedScrollView( controller: _scrollController, headerSliverBuilder: (context, innerBoxIsScrolled) { return [ SliverAppBar( title: Text('NestedScrollView'), pinned: true, floating: true, snap: true, bottom: TabBar( controller: _controller, tabs: _tabs.map((tab) => Tab(text: tab)).toList(), ), ), ]; }, body: TabBarView( controller: _controller, children: _tabViews, ), ), ); } } ``` 以上代码中,我们使用了一个 List 来存储 Tab 标题,使用 for 循环来创建 TabView,每个 TabView 都是一个 ListView,通过传入不同的数据来区分不同的 TabView,同时在 ListView 中添加了 controller 属性来监听列表滚动事件。 在 TabBar 中添加了 onTap 属性,当 Tab 切换时,使用 _controller.animateTo() 方法来控制 TabView 的滚动位置,同时也使用 _scrollController.animateTo() 方法来控制列表滚动位置。 这样就可以实现在 NestedScrollView 和 TabView 中滚动列表某一项的效果了。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

明似水

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值