【问题标题】:Is it possible to “merge” scrolls on a PageView inside a TabBarView?是否可以在 TabBarView 内的 PageView 上“合并”滚动?
【发布时间】:2021-01-14 14:54:06
【问题描述】:

我找到了flutter PageView inside TabBarView: scrolling to next tab at the end of page 但是这个解决方案对我不起作用

是否可以在 PageView 上滚动父 TabBar 并滚动?

我也找到了How to “merge” scrolls on a TabBarView inside a PageView? 但是这种情况是倒置的

这是我在应用程序中使用的代码,但我是 Flutter 的新手 Actual result in this video

class _HomeState extends State<Home> with SingleTickerProviderStateMixin {
  final List<PageController> _controllers = List.generate(
    EPeriod.values.length,
    (index) => PageController(),
  );
  TabController _tabBarController;

  @override
  void initState() {
    super.initState();
    _tabBarController = TabController(
      vsync: this,
      length: EPeriod.values.length,
    );
  }

  @override
  void dispose() {
    _tabBarController.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    StyleGuide().init(context);

    return Scaffold(
      backgroundColor: StyleGuide.colors.accent,
      body: Padding(
        padding: EdgeInsets.only(
          top: StyleGuide.sizes.topPadding,
          bottom: StyleGuide.sizes.bottomPadding,
        ),
        child: _buildContent(),
      ),
    );
  }

  Widget _buildContent() {
    return Center(
      child: Column(
        children: <Widget>[
          _buildAppBar(),
          _buildTabBarView(),
        ],
      ),
    );
  }

  Widget _buildTabBarView() {
    return DefaultTabController(
      length: EPeriod.values.length,
      child: Column(
        children: [
          Container(
            decoration: BoxDecoration(
              border: Border(
                bottom: BorderSide(
                  width: 1,
                  color: StyleGuide.colors.white.withOpacity(0.1),
                ),
              ),
            ),
            child: TabBar(
              controller: _tabBarController,
              indicatorColor: StyleGuide.colors.white,
              labelStyle: StyleGuide.styles.titleTabBar,
              tabs: EPeriod.values
                  .map((period) => Container(
                        alignment: Alignment.center,
                        height: 40,
                        child: Text(describeEnum(period).toUpperCase()),
                      ))
                  .toList(),
            ),
          ),
          Container(
            height: 166,
            child: TabBarView(
              controller: _tabBarController,
              children:
                  EPeriod.values.asMap().entries.map(_buildPeriodData).toList(),
            ),
          )
        ],
      ),
    );
  }

  Widget _buildPeriodDataSummaryPage(EPeriod period) {
    return Column(
      crossAxisAlignment: CrossAxisAlignment.center,
      mainAxisAlignment: MainAxisAlignment.center,
      children: [
        Text(
          'Balance'.toUpperCase(),
          style: StyleGuide.styles.titleSmall.copyWith(
            color: StyleGuide.colors.white.withOpacity(0.5),
          ),
        ),
        Text(
          '-\$171 559.80',
          style: StyleGuide.styles.titleLarge,
        ),
        Text(
          '+5.21%',
          style: StyleGuide.styles.titleSmall.copyWith(
            fontSize: 16,
            color: StyleGuide.colors.white.withOpacity(0.8),
          ),
        ),
      ],
    );
  }

  Widget _buildPeriodDataPieChartPage(EPeriod period) {
    return Row(
      children: [
        Container(
          width: StyleGuide.sizes.screenWidth / 2,
          // TODO: chart
        ),
        Container(
          width: StyleGuide.sizes.screenWidth / 2,
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.start,
            mainAxisAlignment: MainAxisAlignment.center,
            children: [
              Text(
                'Incomes'.toUpperCase(),
                style: StyleGuide.styles.titleSmall.copyWith(
                  color: StyleGuide.colors.white.withOpacity(0.5),
                ),
              ),
              Text(
                '\$171 559.80',
                style: StyleGuide.styles.titleMedium,
              ),
              SizedBox(height: 16),
              Text(
                'Expenses'.toUpperCase(),
                style: StyleGuide.styles.titleSmall.copyWith(
                  color: StyleGuide.colors.white.withOpacity(0.5),
                ),
              ),
              Text(
                '-\$171 559.80',
                style: StyleGuide.styles.titleMedium,
              ),
            ],
          ),
        ),
      ],
    );
  }

  Widget _buildPeriodDataPage(int index, EPeriod period) {
    Function widget =
        index == 0 ? _buildPeriodDataSummaryPage : _buildPeriodDataPieChartPage;
    return widget(period);
  }

  Widget _buildPeriodData(MapEntry<int, EPeriod> entry) {
    var period = entry.value;
    var index = entry.key;

    final _controller = _controllers[index];

    return Container(
      height: 170,
      child: Stack(
        children: [
          PageView.builder(
            allowImplicitScrolling: true,
            controller: _controller,
            itemCount: 2,
            itemBuilder: (context, index) => _buildPeriodDataPage(
              index,
              period,
            ),
            onPageChanged: (page) {
              var nextIndex = _tabBarController.index + 1;
              if (page == 2 && nextIndex < _tabBarController.length) {
                _tabBarController.animateTo(_tabBarController.index + 1);
              }

              var prevIndex = _tabBarController.index - 1;
              if (page == -1 && prevIndex > -1) {
                _tabBarController.animateTo(prevIndex);
              }
            },
          ),
          DotsIndicator(
            controller: _controller,
            itemCount: 2,
            onPageSelected: (page) {
              _controller.animateToPage(
                page,
                duration: Home._kDuration,
                curve: Home._kCurve,
              );
            },
          ),
        ],
      ),
    );
  }

  Widget _buildAppBar() {
    return Container(
      height: 44,
      child: Padding(
        padding: const EdgeInsets.symmetric(horizontal: 12),
        child: Row(
          mainAxisAlignment: MainAxisAlignment.spaceBetween,
          crossAxisAlignment: CrossAxisAlignment.center,
          children: [
            Expanded(
              child: Container(
                alignment: Alignment.centerLeft,
                child: GestureDetector(
                  child: Image.asset(
                    settingsIcon,
                    color: StyleGuide.colors.white,
                  ),
                ),
              ),
            ),
            Expanded(
              child: Container(
                alignment: Alignment.center,
                child: Text('Accounts', style: StyleGuide.styles.titleAppBar),
              ),
            ),
            Expanded(
              child: Row(
                mainAxisAlignment: MainAxisAlignment.end,
                children: [
                  GestureDetector(
                    child:
                        Image.asset(searchIcon, color: StyleGuide.colors.white),
                  ),
                  SizedBox(width: 12),
                  GestureDetector(
                    child: Image.asset(addIcon, color: StyleGuide.colors.white),
                  ),
                ],
              ),
            )
          ],
        ),
      ),
    );
  }
}

【问题讨论】:

    标签: flutter


    【解决方案1】:

    你好@St1ggy 它是每个选项卡中的轮播滑块,您可以通过以下代码实现

    只需在cupertino_icons包下的pubspec.yaml文件中导入carousel_slider: ^2.3.1

    import 'package:carousel_slider/carousel_slider.dart';
    import 'package:flutter/material.dart';
    
    void main() {
      runApp(TabBarDemo());
    }
    
    class TabBarDemo extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          home: DefaultTabController(
            length: 3,
            child: Scaffold(
              appBar: AppBar(
                bottom: TabBar(
                  physics: NeverScrollableScrollPhysics(),
                  tabs: [
                    Tab(icon: Icon(Icons.directions_car)),
                    Tab(icon: Icon(Icons.directions_transit)),
                    Tab(icon: Icon(Icons.directions_bike)),
                  ],
                ),
                title: Text('Tabs Demo'),
              ),
              body: TabBarView(
                children: [
                  CarouselSlider(
                    options: CarouselOptions(height: 400.0),
                    items: [1,2,3,4,5].map((i) {
                      return Builder(
                        builder: (BuildContext context) {
                          return Container(
                              width: MediaQuery.of(context).size.width,
                              margin: EdgeInsets.symmetric(horizontal: 5.0),
                              decoration: BoxDecoration(
                                  color: Colors.amber
                              ),
                              child: Text('text $i', style: TextStyle(fontSize: 16.0),)
                          );
                        },
                      );
                    }).toList(),
                  ),
                  Icon(Icons.directions_transit),
                  Icon(Icons.directions_bike),
                ],
              ),
            ),
          ),
        );
      }
    }
    

    您可以自定义以下包中提供的滑块 https://pub.dev/packages/carousel_slider

    【讨论】:

    • 我试过这个,但不,这不是我需要的 :( 如果 PageView 遇到滚动,我需要滚动 TabBar
    • 请稍等,让我再看一遍视频
    • 视频包含我的实际错误结果,但我需要“合并”滚动
    • 所以你想如果你向左滚动并且分页结束它应该改变标签到左边我是对的
    • 是的!这就是我想要的。但不知道有没有可能
    猜你喜欢
    • 1970-01-01
    • 2019-02-20
    • 1970-01-01
    • 1970-01-01
    • 2019-11-25
    • 2023-01-23
    • 1970-01-01
    • 1970-01-01
    • 2013-07-08
    相关资源
    最近更新 更多