我已经实现了CustomScrollViewSliverAppBarFlexibleSpaceBar的屏幕,如下所示:

flutter - Flutter中的 strip 是否可能同时具有 'expand'和 'contract'效果?-LMLPHP

现在,我试图通过复制以下效果来尝试进一步扩展功能:

Expand image to fullscreen on scroll

可以通过在Flutter中使用slivers来完成类似的事情吗?

基本上,我希望图像在屏幕打开时以其初始大小显示,但是根据滚动方向,它应该设置动画->收缩/淡入淡出(保持列表滚动功能)或扩展到全屏显示(也许是新路径?)。

请帮忙,因为我不确定应该朝哪个方向前进。

这是上述屏幕的代码:

import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  static const double bottomNavigationBarHeight = 48;

  @override
  Widget build(BuildContext context) => MaterialApp(
        debugShowCheckedModeBanner: false,
        home: SliverPage(),
      );
}

class SliverPage extends StatefulWidget {
  @override
  _SliverPageState createState() => _SliverPageState();
}

class _SliverPageState extends State<SliverPage> {
  double appBarHeight = 0.0;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: CustomScrollView(
        physics: AlwaysScrollableScrollPhysics(),
        slivers: <Widget>[
          SliverAppBar(
            centerTitle: true,
            expandedHeight: MediaQuery.of(context).size.height * 0.4,
            pinned: true,
            flexibleSpace: LayoutBuilder(builder: (context, boxConstraints) {
              appBarHeight = boxConstraints.biggest.height;
              return FlexibleSpaceBar(
                centerTitle: true,
                title: AnimatedOpacity(
                    duration: Duration(milliseconds: 200),
                    opacity: appBarHeight < 80 + MediaQuery.of(context).padding.top ? 1 : 0,
                    child: Padding(padding: EdgeInsets.only(bottom: 2), child: Text("TEXT"))),
                background: Image.network(
                  'https://images.pexels.com/photos/443356/pexels-photo-443356.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=650&w=940',
                  fit: BoxFit.cover,
                ),
              );
            }),
          ),
          SliverList(delegate: SliverChildListDelegate(_buildList(40))),
        ],
      ),
    );
  }

  List _buildList(int count) {
    List<Widget> listItems = List();

    for (int i = 0; i < count; i++) {
      listItems.add(
          new Padding(padding: new EdgeInsets.all(20.0), child: new Text('Item ${i.toString()}', style: new TextStyle(fontSize: 25.0))));
    }

    return listItems;
  }
}

最佳答案

结合使用CustomScrollViewSliverPersistentHeader

child: LayoutBuilder(
  builder: (context, constraints) {
    return CustomScrollView(
      controller: ScrollController(initialScrollOffset: constraints.maxHeight * 0.6),
      slivers: <Widget>[
        SliverPersistentHeader(
          pinned: true,
          delegate: Delegate(constraints.maxHeight),
        ),
        SliverList(
          delegate: SliverChildBuilderDelegate(
            (ctx, i) => Container(height: 100, color: i.isOdd? Colors.green : Colors.green[700]),
            childCount: 12,
          ),
        ),
      ],
    );
  },
),
Delegate使用的SliverPersistentHeader类如下所示:
class Delegate extends SliverPersistentHeaderDelegate {
  final double _maxExtent;

  Delegate(this._maxExtent);

  @override
  Widget build(BuildContext context, double shrinkOffset, bool overlapsContent) {
    var t = shrinkOffset / maxExtent;
    return Material(
      elevation: 4,
      child: Stack(
        fit: StackFit.expand,
        children: <Widget>[
          Image.asset('images/bg.jpg', fit: BoxFit.cover,),
          Opacity(
            opacity: t,
            child: Container(
              color: Colors.deepPurple,
              alignment: Alignment.bottomCenter,
              child: Transform.scale(
                scale: ui.lerpDouble(16, 1, t),
                child: Text('scroll me down',
                  style: Theme.of(context).textTheme.headline5.copyWith(color: Colors.white)),
              ),
            ),
          ),
        ],
      ),
    );
  }

  @override double get maxExtent => _maxExtent;
  @override double get minExtent => 64;
  @override bool shouldRebuild(SliverPersistentHeaderDelegate oldDelegate) => true;
}

10-05 20:59