简体   繁体   中英

Is it possible to “merge” scrolls on a PageView inside a TabBarView?

I have found flutter PageView inside TabBarView: scrolling to next tab at the end of page But this solution doesn't work for me

Is it possible to scroll parent TabBar with over scroll on PageView?

I have also found How to “merge” scrolls on a TabBarView inside a PageView? But this case is inverted

That's my code used in my app, but I am new in 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),
                  ),
                ],
              ),
            )
          ],
        ),
      ),
    );
  }
}

Hello @St1ggy it a carousel slider in each tabs you can achieve by following code

just import carousel_slider: ^2.3.1 in pubspec.yaml file under cupertino_icons packages

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),
            ],
          ),
        ),
      ),
    );
  }
}

You can customize you slider given in following package https://pub.dev/packages/carousel_slider

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