11

I am trying to place a PageView which pages are scrollable vertically into a CustomScrollView.

The reason for this setup is that I want to make use of SliverAppBar. If one starts scrolling vertically, the AppBar starts shrinking and ultimately docks at the top of the screen. At the same time the currently active page's content is expanded. Once the AppBar is docked and the page's content reached it's maximum allowed size, it itself starts scrolling.

I am running into all sorts of problem, mostly issues with unbounded sizes.

Basic Coder
  • 10,882
  • 6
  • 42
  • 75

1 Answers1

26

The answer you've found as you've mentioned in the comments is correct. Instead of a CustomScrollView, NestedScrollView should be used because there are multiple scrollable views that will be managed on the screen. As mentioned in the docs, the most common use case for NestedScrollView is a scrollable view with a flexible SliverAppBar containing a TabBar in the header - similar to your use case.

Here's a working sample based from the snippet provided in the post you've referenced.

import 'package:flutter/material.dart';

void main() {
  runApp(MyApp());
}

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

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);

  final String title;

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage>
    with SingleTickerProviderStateMixin {
  var _scrollController, _tabController;

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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: NestedScrollView(
        controller: _scrollController,
        headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) {
          return <Widget>[
            SliverAppBar(
              title: Text(widget.title),
              pinned: true,
              floating: true,
              snap: false,
              forceElevated: innerBoxIsScrolled,
              bottom: TabBar(
                tabs: <Tab>[
                  Tab(text: "Page 1"),
                  Tab(text: "Page 2"),
                ],
                controller: _tabController,
              ),
            ),
          ];
        },
        body: TabBarView(
          controller: _tabController,
          children: <Widget>[
            _pageView(),
            _pageView(),
          ],
        ),
      ),
    );
  }

  _pageView() {
    return ListView.builder(
      itemCount: 20,
      itemBuilder: (BuildContext context, int index) {
        return Card(
          child: Container(
            padding: EdgeInsets.all(16.0),
            child: Text('List Item $index'),
          ),
        );
      },
    );
  }
}

Demo

demo

Omatt
  • 8,564
  • 2
  • 42
  • 144