0

I already implemented NestedScrollView and this is my result.

Before Scrolled:

enter image description here

After Scrolled:

enter image description here

The question are:

  1. In the Before Scrolled section, how to make the default Live Button is in the center of AppBar?
  2. In the After Scrolled section, when the user scrolled to the top, the Live Button is moved from the center (default) to the right (besides Chat Button).
  3. In the After Scrolled section, when the user scrolled to the top, the title should not overlap with Back Button, Live Button, and Chat Button but the title prefix is should ​​to the right of Back Button, and the title suffix should to the left of Live Button, and Live Button should to the left of Chat Button.

This is my code for building AppBar:

Widget _customAppBar(EventEntity event) {
    return SliverAppBar(
      expandedHeight: 200 + _appBarHeight,
      floating: false,
      pinned: true,
      leading: _buildNavButton(), // Back Button (Left)
      actions: <Widget>[
        // Live Button (Right)
        event?.status != null &&
            event.status == EventStatus.LIVE
            ? Center(child: LiveLabel(),)
            : Container(),
        // Chat Button (Right)
        HelpButton(),
      ],
      flexibleSpace: FlexibleSpaceBar(
        centerTitle: true,
        title: Text(
          widget.event.name.trim(),
          style: TextStyle(
            fontWeight: FontWeight.bold,
            fontSize: 24,
          ),
          overflow: TextOverflow.ellipsis,
          maxLines: 1,
          textAlign: TextAlign.center,
        ),
        background: Hero(
          tag: '--${widget.visibilityFilter} __${widget.event.id}',
          child: DinoNetworkImage(
            imageUrl: widget.event.image,
            fit: BoxFit.contain,
          ),
        ),
      ),
    );
  }

And this is the build method:

Widget build(BuildContext context) {
    return Scaffold(
      key: _scaffoldKey,
      body: SafeArea(
        top: true,
        bottom: false,
        child: Stack(
          fit: StackFit.expand,
          children: <Widget>[
            NestedScrollView(
              headerSliverBuilder: (BuildContext context,
                  bool innerBoxIsScrolled) {
                return <Widget>[
                  _customAppBar(widget.event),
                ];
              },
              body: SingleChildScrollView(
                ....
              ),
            ),
            ....
          ],
        ),
      ),
    );
  }

How to make that happens with my code?

R Rifa Fauzi Komara
  • 1,915
  • 6
  • 27
  • 54

1 Answers1

0

I solved this with using ScrollController and Visibility widget, and this is my code:

// Init variable
ScrollController _controller = ScrollController();
var _showLiveButton = false;
var _hideLiveButton = true;
var _isScrolledDone = false;


// Function for handler scrolled
void _listener() {
    if (_controller.offset / 160 > 1) {
      setState(() {
        _showLiveButton = true;
        _hideLiveButton = false;
        _isScrolledDone = true;
      });
    } else {
      setState(() {
        _showLiveButton = false;
        _hideLiveButton = true;
        _isScrolledDone = false;
      });
    }
}

// Don't forget to init and dispose the controller
@override
  void initState() {
    super.initState();
    _controller.addListener(_listener);
  }

  @override
  void dispose() {
    _controller.removeListener(_listener);
    super.dispose();
  }

Widget _buildLiveButtonAfterScrolled(EventEntity event) {
    if (event?.status != null && event.status == EventStatus.LIVE) {
      return Center(
        child: Visibility(
          visible: _showLiveButton,
          child: LiveLabel(),
        ),
      );
    } else {
      return Container();
    }
  }

  Widget _buildDefaultLiveButton(EventEntity event) {
    if (event?.status != null && event.status == EventStatus.LIVE) {
      return Expanded(
        child: Padding(
          padding: EdgeInsets.only(
            left: MediaQuery.of(context).size.width / 8,
          ),
          child: Center(
            child: Visibility(
              visible: _hideLiveButton,
              child: LiveLabel(),
            ),
          ),
        ),
      );
    } else {
      return Container();
    }
  }

  Widget _buildTitleAppBar() {
    if (_isScrolledDone) {
      return Container(
        margin: EdgeInsets.only(
          left: MediaQuery.of(context).size.width / 7,
          right: MediaQuery.of(context).size.width / 3.3,
        ),
        child: Text(
          widget.event.name.trim(),
          style: TextStyle(
            fontWeight: FontWeight.bold,
            fontSize: 24,
          ),
          overflow: TextOverflow.ellipsis,
          maxLines: 1,
          textAlign: TextAlign.start,
        ),
      );
    } else {
      return Text(
        widget.event.name.trim(),
        style: TextStyle(
          fontWeight: FontWeight.bold,
          fontSize: 24,
        ),
        overflow: TextOverflow.ellipsis,
        maxLines: 1,
        textAlign: TextAlign.center,
      );
    }
  }

  Widget _customAppBar(EventEntity event) {
    return SliverAppBar(
      expandedHeight: 200 + _appBarHeight,
      floating: false,
      pinned: true,
      leading: _buildNavButton(),
      actions: <Widget>[
        _buildDefaultLiveButton(event),
        _buildLiveButtonAfterScrolled(event),
        HelpButton(),
      ],
      flexibleSpace: FlexibleSpaceBar(
        centerTitle: true,
        title: _buildTitleAppBar(),
        background: Hero(
          tag: '--${widget.visibilityFilter} __${widget.event.id}',
          child: DinoNetworkImage(
            imageUrl: widget.event.image,
            fit: BoxFit.contain,
          ),
        ),
      ),
    );
  }

Widget build(BuildContext context) {
    return Scaffold(
      key: _scaffoldKey,
      body: SafeArea(
        top: true,
        bottom: false,
        child: Stack(
          fit: StackFit.expand,
          children: <Widget>[
            NestedScrollView(
              controller: _controller, // <--- Don't forget to add it
              headerSliverBuilder: (BuildContext context,
                  bool innerBoxIsScrolled) {
                return <Widget>[
                  _customAppBar(widget.event),
                ];
              },
              body: SingleChildScrollView(
                ....
              ),
            ),
            ....
          ],
        ),
      ),
    );
  }

R Rifa Fauzi Komara
  • 1,915
  • 6
  • 27
  • 54