how to implement a sliverAppBar with a tabBar

2019-01-28 09:21发布

问题:

the flutter document show a demo for SliverAppBar + TabBar + TabBarView with ListView use NestedScrollView, and it's a bit complex, so I wonder is there a simply and clear way to implement it. I tried this:

CustomScrollView
  slivers:
    SliverAPPBar
      bottom: TabBar
    TabBarView
      children: MyWidget(list or plain widget)

got error:

flutter: The following assertion was thrown building Scrollable(axisDirection: right, physics:
flutter: A RenderViewport expected a child of type RenderSliver but received a child of type _RenderExcludableScrollSemantics.
flutter: RenderObjects expect specific types of children because they coordinate with their children during layout and paint. For example, a RenderSliver cannot be the child of a RenderBox because a RenderSliver does not understand the RenderBox layout protocol.

and

flutter: Another exception was thrown: 'package:flutter/src/widgets/framework.dart': Failed assertion: line 3497 pos 14: 'owner._debugCurrentBuildTarget == this': is not true.

HERE IS MY CODE:

import 'package:flutter/material.dart';

main(List<String> args) {
  runApp(MyScrollTabListApp());
}

class MyScrollTabListApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(title: "aa", home: MyScrollTabListHomePage());
  }
}

class MyScrollTabListHomePage extends StatefulWidget {
  @override
  MyScrollTabListHomePageState createState() {
    return new MyScrollTabListHomePageState();
  }
}

class MyScrollTabListHomePageState extends State<MyScrollTabListHomePage>
    with SingleTickerProviderStateMixin {
  final int _listItemCount = 300;
  final int _tabCount = 8;
  TabController _tabController;

  @override
  void initState() {
    _tabController = TabController(length: _tabCount, vsync: this);
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: CustomScrollView(
        slivers: <Widget>[
          SliverAppBar(
            expandedHeight: 240.0,
            title: Text("Title"),
            pinned: true,
            bottom: TabBar(
              controller: _tabController,
              isScrollable: true,
              tabs: List<Tab>.generate(_tabCount, (int i) {
                return Tab(text: "TAB$i");
              }),
            ),
          ),
          TabBarView(
            controller: _tabController,
            children: List<Widget>.generate(_tabCount, (int i) {
              return Text('line $i');
            }),
          ),
        ],
      ),
    );
  }
}

and for the official demo, it use struct like this

DefaultTabController
    NestedScrollView
      headerSliverBuilder
        SliverOverlapAbsorber
          handle
          SliverAppBar
        TabBarView
          CustomScrollView
            SliverOverlapInjector
              handle
              SliverPadding

回答1:

Here is an example for TabView with SilverAppBar

class SilverAppBarWithTabBarScreen extends StatefulWidget {
  @override
  _SilverAppBarWithTabBarState createState() => _SilverAppBarWithTabBarState();
}

class _SilverAppBarWithTabBarState extends State<SilverAppBarWithTabBarScreen>
    with SingleTickerProviderStateMixin {
  TabController controller;

  @override
  void initState() {
    super.initState();
    controller = new TabController(length: 3, vsync: this);
  }

  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      body: new CustomScrollView(
        slivers: <Widget>[
          new SliverAppBar(
            title: Text("Silver AppBar With ToolBar"),
            pinned: true,
            expandedHeight: 160.0,
            bottom: new TabBar(
              tabs: [
                new Tab(text: 'Tab 1'),
                new Tab(text: 'Tab 2'),
                new Tab(text: 'Tab 3'),
              ],
              controller: controller,
            ),
          ),
          new SliverList(
          new SliverFillRemaining(
        child: TabBarView(
          controller: controller,
          children: <Widget>[
               Text("Tab 1"),
               Text("Tab 2"),
               Text("Tab 3"),
             ],
            ),
          ),
        ],
      ),
    );
  }
}


回答2:

Great video here explaining it all. Turns out you need the scrollView controller: https://youtu.be/3Cm7WzH3gb8