如何在SliverAppBar上重叠SliverList [英] How to overlap SliverList on a SliverAppBar

查看:172
本文介绍了如何在SliverAppBar上重叠SliverList的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试将SliverListSliverAppBar重叠几个像素.类似于这篇文章.我希望FlexibleSpaceBar中的图像位于我的SliverList半径以下. 我正在尝试实现以下目标.

I'm trying to overlap a SliverList a few pixels over the SliverAppBar. Similar to this post. I'd like the image in the FlexibleSpaceBar to go under the radius of my SliverList. I'm attempting to achieve the below.

我只能这样获得半径.无法将SliverList重叠到SliverAppBar上.

I can only get the radius like so. Without the ability to overlap the SliverList onto he SliverAppBar.

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: CustomScrollView(
        slivers: <Widget>[
          SliverAppBar(
            floating: false,
            expandedHeight: MediaQuery.of(context).size.height * 0.50,
            flexibleSpace: FlexibleSpaceBar(
              background: Image.network(pet.photos.first)
            ),
          ),
          SliverList(
            delegate: SliverChildListDelegate([
              Container(
                height: 40,
                decoration: BoxDecoration(
                  color: Colors.red,
                  borderRadius: BorderRadius.only(
                    topLeft: Radius.circular(30),
                    topRight: Radius.circular(30),
                  ),
                ),
              ),
            ]),
          )
        ],
      ),
    );
  }

任何方向将不胜感激,谢谢!

Any direction would be appreciated, thanks!

推荐答案

您可以使用下面的小部件,该小部件使用Stack和滚动侦听器来实现类似屏幕快照的功能.它基于 https://pub.dartlang.org/packages/sliver_fab .

You can use the following widget which uses Stack and scroll listeners to achieve something like the screenshots. It's based on https://pub.dartlang.org/packages/sliver_fab.

小部件:

import 'package:flutter/material.dart';

class DetailScaffold extends StatefulWidget {
  final ScrollController controller;
  final ScrollPhysics physics;
  final List<Widget> slivers;

  final double expandedHeight;

  /// Changes edge behavior to account for [SliverAppBar.pinned].
  ///
  /// Hides the edge when the [ScrollController.offset] reaches the collapsed
  /// height of the [SliverAppBar] to prevent it from overlapping the app bar.
  final bool hasPinnedAppBar;

  DetailScaffold({
    @required this.expandedHeight,
    this.controller,
    this.physics,
    this.slivers,
    this.hasPinnedAppBar = false,
  }) {
    assert(expandedHeight != null);
    assert(hasPinnedAppBar != null);
  }

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

class _DetailScaffoldState extends State<DetailScaffold> {
  ScrollController ctrl;

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

    ctrl = widget.controller ?? ScrollController();
    ctrl.addListener(() => setState(() {}));
  }

  @override
  void dispose() {
    if (widget.controller == null) {
      ctrl.dispose();
    }

    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Stack(
      children: <Widget>[
        CustomScrollView(
          controller: ctrl,
          physics: widget.physics,
          slivers: widget.slivers,
        ),
        _buildEdge(),
      ],
    );
  }

  _buildEdge() {
    var edgeHeight = 12.0;
    var paddingTop = MediaQuery.of(context).padding.top;

    var defaultOffset =
        (paddingTop + widget.expandedHeight) - edgeHeight;

    var top = defaultOffset;
    var edgeSize = edgeHeight;

    if (ctrl.hasClients) {
      double offset = ctrl.offset;
      top -= offset > 0 ? offset : 0;

      if (widget.hasPinnedAppBar) {
        // Hide edge to prevent overlapping the toolbar during scroll.
        var breakpoint =
            widget.expandedHeight - kToolbarHeight - edgeHeight;

        if (offset >= breakpoint) {
          edgeSize = edgeHeight - (offset - breakpoint);
          if (edgeSize < 0) {
            edgeSize = 0;
          }

          top += (edgeHeight - edgeSize);
        }
      }
    }

    return Positioned(
      top: top,
      left: 0,
      right: 0,
      child: Container(
        height: edgeSize,
        decoration: BoxDecoration(
          color: Theme.of(context).canvasColor,
          borderRadius: BorderRadius.vertical(
            top: Radius.circular(12),
          ),
        ),
      ),
    );
  }
}

使用它:

class Home extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    var expandedHeight = 128.0;

    return DetailScaffold(
      expandedHeight: expandedHeight,
      slivers: <Widget>[
        SliverAppBar(
          expandedHeight: expandedHeight,
          flexibleSpace: FlexibleSpaceBar(
            background: Container(color: Colors.purple),
          ),
        ),
        SliverList(
          delegate: SliverChildBuilderDelegate((_, i) {
            return ListTile(title: Text('Item $i'));
          }, childCount: 50),
        ),
      ],
    );
  }
}

这篇关于如何在SliverAppBar上重叠SliverList的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆