astrorain
astrorain

Reputation: 71

Flutter: NestedScrollView Header TabBar obstructs/overlaps TabBarView Elements

My goal is to use some kind of Profile Page where I have a SliverAppBar at the top which has a tabBar as bottom to switch between the Lists or elements shown below the AppBar. I found that this is archived by NestedScrollView but noticed a strange behavior when either having just a few elements and scrolling up, where it still scrolls up under the tab bar, even tho there are no new elements to show at the bottom, or when you have a lot of items and want to use some kind of persistent App Bar in one of the lists, to for example have a textfield which should be used to sort or filter the list.

I tried to use SliverOverlapAbsorber, but it didn't solve the problem. So below I just show the sample code without it: I thought about inserting a Container that changes it's height according to the scrolling position, to 'solve' this issue, but I'd prefer the proper way to do this..

here's a gif to illustrate the problem: https://gfycat.com/decentoccasionalhyena https://gfycat.com/fastslightekaltadeta


import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';

import 'package:widgettests/widgets/sliverHeader.dart';


class NestedTabbarSliverOverpaling extends StatefulWidget {
  @override
  _NestedTabbarSliverOverpalingState createState() => _NestedTabbarSliverOverpalingState();
}

class _NestedTabbarSliverOverpalingState extends State<NestedTabbarSliverOverpaling> with TickerProviderStateMixin {
  ScrollController _scrollController;
  TabController _tabController;

  @override
  void initState() {
    super.initState();

    _scrollController = new ScrollController();
    _tabController = new TabController(length: 2, vsync: this);
  }

  @override
  void dispose() {
    _scrollController.dispose();
    _tabController.dispose();
    super.dispose();
  }



  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: NestedScrollView(
        controller: _scrollController,
        physics: BouncingScrollPhysics(),
        dragStartBehavior: DragStartBehavior.start,
        headerSliverBuilder: (context, innerBoxIsScrolled) =>
        <Widget>[
        SliverAppBar(
          pinned: true,
          expandedHeight: 100,
          bottom: PreferredSize(
            preferredSize: Size.fromHeight(-5),
            child: TabBar(
                controller: _tabController,
                labelColor: Colors.white,
                tabs: <Widget>[Tab(text: '1st List',), Tab(text: '2nd List',),]
            ),
          ),
        ),

        ],
        body: TabBarView(
          controller: _tabController,
          children: <Widget>[
            SafeArea(
              top: false,
              bottom: false,
              child: _buildfirstList(context),
            ),

            SafeArea(
              top: false,
              bottom: false,
              child: _build2ndList(context),
            ),

          ],
        ),
      ),
    );
  }


  Widget _buildfirstList(BuildContext context) {
    final children = <Widget>[
      CustomScrollView(
        key: PageStorageKey<String>('1st'),
        physics: ClampingScrollPhysics(),
        slivers: <Widget>[
          SliverAppBar(
            backgroundColor: Colors.blueGrey,
            floating: true,
            snap: true,
            title: TextField(
              showCursor: false,
            ),
            titleSpacing: 2,
          ),
          _List(),
          //SliverFillRemaining(),
        ],
      ),

    ];

    return Stack(
      children: children,
    );
  }

  Widget _build2ndList(BuildContext context) {
    final children = <Widget>[
      CustomScrollView(
        key: PageStorageKey<String>('2nd'),
        physics: ClampingScrollPhysics(),
        slivers: <Widget>[
          _List(),
          //SliverFillRemaining(),
        ],
      ),

    ];

    return Stack(
      children: children,
    );
  }


  Widget _List() {
    return SliverList(
      delegate: SliverChildBuilderDelegate((BuildContext context, int index) {
        return new ListTile(
          title: Text('tile no. ${index}'),
        );
      },
        childCount: 55,
      ),
    );
  }






}

Upvotes: 2

Views: 2245

Answers (0)

Related Questions