Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Body in Nested Scroll body showing behind headerSliverBuilder

Tags:

flutter

dart

I've created a flutter widget that consists of a few slivers that make up the app bar and tabs, and below that, I have the TabBarView.

1) There is an excessive amount of padding between the tabs and the body ScrollView, but I'm not sure what element is causing it.

2) When scrolling the content in the ListView, it shows behind the tab and I'm not sure what I need to do to prevent that.

3)Lastly, You can scroll until there are no more visible items in the ListView, how would you scroll similar to html/css overflow, where it stops scrolling at the end of the content?

Here's my view

import 'package:flutter/material.dart';
import 'package:nssa/bloc/conference/bloc.dart';

class ConferencePage extends StatelessWidget {

  final Conference conference;

  ConferencePage(@required this.conference);

  TabBar getTabBar(List<Zone> zones) {
    return  TabBar(
      tabs: zones.map((zone) {
        return new Tab(text: zone.type);
      }).toList(growable: false)
    );
  }

  TabBarView getTabBody(List<Zone> zones) {
    return TabBarView(
      children: zones.map((zone) {
        return ListView(
          children: zone.upcomingEvents().map((event) {
            return new ListTile(title: Text(event.name));
          }).toList(growable: false)
        );
      }).toList(growable: false)
    );
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: DefaultTabController(
        length: this.conference.zones.length,
        child: NestedScrollView(
          headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) {
            return <Widget>[
              SliverAppBar(
                expandedHeight: 200.0,
                floating: true,
                pinned: true,
                flexibleSpace: FlexibleSpaceBar(
                  centerTitle: true,
                  title: Text(
                    this.conference.name,
                    style: TextStyle(
                      color: Colors.white,
                      fontSize: 16.0,
                    )
                  ),
                  background: Hero(
                    tag: this.conference.name,
                    child: Image.network(
                      this.conference.image,
                      fit: BoxFit.cover,
                    )
                  )
                ),
              ),
              SliverPersistentHeader(
                delegate: _SliverAppBarDelegate(
                  this.getTabBar(this.conference.zones),
                ),
                pinned: true,
              ),
            ];
          },
          body: this.getTabBody(this.conference.zones)
        ),
      ),
      floatingActionButton: FloatingActionButton(
        child: Icon(Icons.card_membership)
      ),
    );
  }
}

class _SliverAppBarDelegate extends SliverPersistentHeaderDelegate {
  _SliverAppBarDelegate(this._tabBar);

  final TabBar _tabBar;

  @override
  double get minExtent => _tabBar.preferredSize.height;
  @override
  double get maxExtent => _tabBar.preferredSize.height;

  @override
  Widget build(
      BuildContext context, double shrinkOffset, bool overlapsContent) {
    return new Container(
      child: _tabBar,
    );
  }

  @override
  bool shouldRebuild(_SliverAppBarDelegate oldDelegate) {
    return false;
  }
}

Here are my models

import 'package:flutter/foundation.dart';
import 'package:equatable/equatable.dart';
import 'package:meta/meta.dart';
import 'package:intl/intl.dart';

import 'dart:developer';

@immutable
class Zone extends Equatable {
  final String type;
  final List<String> divisions;
  final List<Event> events;
  final DateTime _now = DateTime.now();

  Zone (
    @required this.type,
    @required this.divisions,
    @required this.events,
  );

  @override
  List<Object> get props => [type, /*divisions,*/ events];

  Event currentEvent() {
    return this.events.firstWhere((event) => event.startDate.isBefore(_now) && event.endDate.isAfter(_now), orElse: () => null);
  }

  List<Event> pastEvents() {
    return this.events.where((event) => event.endDate.isBefore(_now)).toList(growable: false);
  }

  List<Event> upcomingEvents() {
    return this.events.where((event) => event.startDate.isAfter(_now)).toList(growable: false);
  }

  factory Zone.fromJson(Map<String, dynamic> zoneJSON) {
    List<String> divisions = (zoneJSON['divisions'] as List).map((division) {
      return division.toString();
    }).toList(growable: true);

    List<Event> events = (zoneJSON['events'] as List).map((event) {
      return new Event.fromJson(event);
    }).toList(growable: true);

    events.sort((a,b) => a.startDate.compareTo(b.startDate));

    return Zone(
        zoneJSON['type'],
        divisions,
        events,
    );
  }
}
@immutable
class Event extends Equatable {
  final String name;
  final String details;
  final DateTime startDate;
  final DateTime endDate;
  final String image;
  final String ticketURL;

  Event (
    @required this.name,
    @required this.details,
    @required this.startDate,
    @required this.endDate,
    @required this.image,
    @required this.ticketURL,
  );

  @override
  List<Object> get props => [name, startDate, endDate, details, image, ticketURL];

  factory Event.fromJson(Map<String, dynamic> eventJSON) {
    DateFormat dateFormat = DateFormat("yyyy-MM-dd");
    return Event(
        eventJSON['name'],
        eventJSON['details'],
        dateFormat.parse(eventJSON['startDate'].toString()),
        dateFormat.parse(eventJSON['endDate'].toString()),
        eventJSON['image'],
        eventJSON['ticketURL']
    );
  }
}

excessive padding

content behind tab

like image 887
Don P Avatar asked Jan 15 '20 06:01

Don P


People also ask

How do I prevent NestedScrollView from scrolling if body is small?

The problem can be solved by moving the SliverAppBar into the CustomScrollView and not use the NestedScrollView at all.

What is Nested scroll view?

NestedScrollView is just like ScrollView , but it supports acting as both a nested scrolling parent and child on both new and old versions of Android. Nested scrolling is enabled by default.

What is nested scroll view in flutter?

A scrolling view inside of which can be nested other scrolling views, with their scroll positions being intrinsically linked.

How do you make a TabBarView scrollable in flutter?

It is simple to add scrollable on flutter. Just create SingleChildScrollView widget as a TabBarView and put all the contents as it's child.


1 Answers

When using a NestedScrollView, you might need to wrap your SliverAppBar with a SliverOverlapAbsorber to avoid having the body content scrolling behing the appbar.

Also, you might be better off putting your TabBar in the bottom of your SliverAppBar, just like in the official example.

See documentation here: https://api.flutter.dev/flutter/widgets/NestedScrollView-class.html

like image 114
Louis Deveseleer Avatar answered Sep 16 '22 19:09

Louis Deveseleer