首页 > 解决方案 > Flutter 中的条子是否可以同时具有“扩展”和“收缩”效果?

问题描述

我已经使用,实现了一个屏幕,CustomScrollView如下所示:SliverAppBarFlexibleSpaceBar

在此处输入图像描述

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

滚动时将图像扩展到全屏

这样的事情可以通过使用sliversin Flutter 来完成吗?

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

请帮忙,因为我不确定我应该往哪个方向走。

这是上面屏幕的代码:

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

标签: flutterdartexpandflutter-sliversliverappbar

解决方案


CustomScrollView与_SliverPersistentHeader

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

使用的DelegateSliverPersistentHeader看起来像:

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

推荐阅读