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

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

问题描述

我试图在 SliverAppBar 上重叠几个像素的 SliverList.类似于

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

 @override小部件构建(BuildContext 上下文){返回脚手架(正文:自定义滚动视图(条子:<小部件>[SliverAppBar(浮动:假,扩展高度:MediaQuery.of(context).size.height * 0.50,弹性空间:弹性空间条(背景:Image.network(pet.photos.first)),),银名单(委托:SliverChildListDelegate([容器(身高:40,装饰:盒子装饰(颜色:颜色.红色,边界半径:边界半径.only(左上角:半径.圆形(30),右上角:半径.圆形(30),),),),]),)],),);}

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

解决方案

您可以使用以下使用 Stack 和滚动侦听器的小部件来实现类似屏幕截图的效果.它基于 https://pub.dartlang.org/packages/sliver_fab.

小部件:

import 'package:flutter/material.dart';类 DetailScaffold 扩展 StatefulWidget {最终的 ScrollController 控制器;最终的 ScrollPhysics 物理;最终列表<小部件>条子;最终双expandHeight;///更改边缘行为以考虑 [SliverAppBar.pinned].//////当[ScrollController.offset]达到折叠状态时隐藏边缘///[SliverAppBar] 的高度,以防止它与应用栏重叠.final bool hasPinnedAppBar;详细脚手架({@required this.expandedHeight,这个控制器,this.physics,this.slivers,this.hasPinnedAppBar = false,}) {断言(expandedHeight != null);断言(hasPinnedAppBar != null);}@覆盖_DetailScaffoldState createState() =>_DetailScaffoldState();}类 _DetailScaffoldState 扩展状态<DetailScaffold>{滚动控制器 ctrl;@覆盖无效初始化状态(){super.initState();ctrl = widget.controller ??滚动控制器();ctrl.addListener(() => setState(() {}));}@覆盖无效处置(){if (widget.controller == null) {ctrl.dispose();}super.dispose();}@覆盖小部件构建(BuildContext 上下文){返回堆栈(孩子们:<小部件>[自定义滚动视图(控制器: ctrl,物理:widget.physics,条子:widget.slivers,),_buildEdge(),],);}_buildEdge() {变量边缘高度 = 12.0;var paddingTop = MediaQuery.of(context).padding.top;var defaultOffset =(paddingTop + widget.expandedHeight) - edgeHeight;var top = defaultOffset;var edgeSize = edgeHeight;如果(ctrl.hasClients){双偏移 = ctrl.offset;顶部 -= 偏移量 >0 ?偏移量:0;if (widget.hasPinnedAppBar) {//隐藏边缘以防止滚动期间工具栏重叠.var 断点 =widget.expandedHeight - kToolbarHeight - edgeHeight;if (offset >= 断点) {edgeSize = edgeHeight - (偏移量 - 断点);if (edgeSize < 0) {边缘尺寸 = 0;}顶部 += (edgeHeight - edgeSize);}}}返回定位(顶部:顶部,左:0,对:0,孩子:容器(高度:边缘尺寸,装饰:盒子装饰(颜色:Theme.of(context).canvasColor,边界半径:边界半径.vertical(顶部:半径.圆形(12),),),),);}}

使用它:

class Home 扩展 StatelessWidget {@覆盖小部件构建(BuildContext 上下文){变种扩展高度 = 128.0;返回详细信息支架(扩展高度:扩展高度,条子:<小部件>[SliverAppBar(扩展高度:扩展高度,弹性空间:弹性空间条(背景:容器(颜色:Colors.purple),),),银名单(委托:SliverChildBuilderDelegate((_, i) {return ListTile(title: Text('Item $i'));}, childCount: 50),),],);}}

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.

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!

解决方案

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.

The widget:

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),
          ),
        ),
      ),
    );
  }
}

Using it:

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天全站免登陆