Flutter滑动持续化组件

3
我有以下代码,我尽可能地缩短它以便更容易处理。我想向下滚动以显示默认的appBar,而不是背景。我尝试了一些解决方案,但没有成功。希望能够平滑地在它们之间切换。
我想使用已有的相同代码,因为我是在其基础上构建的。
我附上了问题的图示。

enter image description here

主要代码:
import 'package:flutter/material.dart';

import 'home_page.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      debugShowCheckedModeBanner: false,
      home: HomePage(),
    );
  }
}

主页代码:
import 'package:flutter/material.dart';

class HomePage extends StatelessWidget {
  const HomePage({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: CustomScrollView(
        slivers: [
          const SliverPersistentHeader(pinned: true, delegate: SliverHeaderDelegateComponent(expandedHeight: 300)),
          SliverList(
            delegate: SliverChildListDelegate(
              [
                Container(
                  height: 1000,
                  color: Colors.blue.withOpacity(0.5),
                  child: const Center(child: Text('Body')),
                )
              ],
            ),
          ),
        ],
      ),
    );
  }
}

银色头部委托组件代码:
class SliverHeaderDelegateComponent extends SliverPersistentHeaderDelegate {
  final double expandedHeight;

  const SliverHeaderDelegateComponent({required this.expandedHeight});

  @override
  Widget build(BuildContext context, double shrinkOffset, bool overlapsContent) {
    final appBarSize = expandedHeight - shrinkOffset;
    final proportion = 2 - (expandedHeight / appBarSize);
    final percent = proportion < 0 || proportion > 1 ? 0.0 : proportion;
    return StatefulBuilder(
      builder: (BuildContext context, StateSetter setState) => SizedBox(
        height: expandedHeight + expandedHeight / 2,
        child: Stack(
          clipBehavior: Clip.none,
          children: [
            Container(
              height: 500,
              decoration: const BoxDecoration(
                color: Colors.black,
                image: DecorationImage(
                  image: NetworkImage(
                      'https://www.digitalartsonline.co.uk/cmsdata/slideshow/3662115/baby-driver-rory-hi-res.jpg'),
                  fit: BoxFit.cover,
                ),
              ),
            ),
            PositionedDirectional(
              start: 0.0,
              end: 0.0,
              top: appBarSize > 0 ? appBarSize : 0,
              bottom: -100,
              child: Opacity(
                opacity: percent,
                child: Padding(
                  padding: EdgeInsets.symmetric(horizontal: 30 * percent),
                  child: const Card(
                    elevation: 20.0,
                    child: Center(
                      child: Text("Widget"),
                    ),
                  ),
                ),
              ),
            ),
          ],
        ),
      ),
    );
  }

  @override
  double get maxExtent => expandedHeight + expandedHeight / 2;

  @override
  double get minExtent => kToolbarHeight;

  @override
  bool shouldRebuild(SliverPersistentHeaderDelegate oldDelegate) {
    return true;
  }
}

看看这个能否帮到你:https://stackoverflow.com/a/68468773/13431819 - Agni Gari
我想在SliverPersistentHeader上应用required,而不是在SliverAppBar上。 - Mohammed
如果你能帮助我,我将非常感激你。 - Mohammed
1个回答

0
这是使用你请求的 SliverHeaderDelegateComponent 的解决方案。 在这个例子中,AppBar 在折叠时显示,但是如果您想在展开时显示它,可以取消注释已注释的部分。(更新:根据评论部分的要求改进了淡入淡出效果)
class SliverHeaderDelegateComponent extends SliverPersistentHeaderDelegate {
  final double expandedHeight;

  const SliverHeaderDelegateComponent({required this.expandedHeight});

  @override
  Widget build(
      BuildContext context, double shrinkOffset, bool overlapsContent) {
    final deadline = (expandedHeight + minExtent);
    double percent = shrinkOffset > deadline ? 1 : shrinkOffset / deadline;
    final appBarSize = expandedHeight - shrinkOffset;
    return StatefulBuilder(
      builder: (BuildContext context, StateSetter setState) => SizedBox(
        height: expandedHeight + expandedHeight / 2,
        child: Stack(
          clipBehavior: Clip.none,
          children: [
            // shrinkOffset == 0 // if you want to show it on expand
            shrinkOffset > expandedHeight + minExtent // show it on collapse
                ? AppBar(title: Text('App Bar'))
                : Container(
                    height: 500,
                    decoration: const BoxDecoration(
                      color: Colors.black,
                      image: DecorationImage(
                        image: NetworkImage(
                            'https://www.digitalartsonline.co.uk/cmsdata/slideshow/3662115/baby-driver-rory-hi-res.jpg'),
                        fit: BoxFit.cover,
                      ),
                    ),
                  ),
            PositionedDirectional(
              start: 0.0,
              end: 0.0,
              top: appBarSize > 0 ? appBarSize : 0,
              bottom: -100,
              child: Opacity(
                opacity: 1 - percent,
                // opacity: percent < 0.5 ? 1 : (1 - percent) * 2, // if you want to start fading when reach half way scroll
                child: Padding(
                  padding: EdgeInsets.symmetric(horizontal: 30 * percent),
                  child: const Card(
                    elevation: 20.0,
                    child: Center(
                      child: Text("Widget"),
                    ),
                  ),
                ),
              ),
            ),
          ],
        ),
      ),
    );
  }

  @override
  double get maxExtent => expandedHeight + expandedHeight / 2;

  @override
  double get minExtent => kToolbarHeight;

  @override
  bool shouldRebuild(SliverPersistentHeaderDelegate oldDelegate) {
    return true;
  }
}

朋友,谢谢你的帮助,我想再问你一个问题。 - Mohammed
我如何使用百分比变量控制不透明度?我是唯一一个确切理解计算方式的人,因为每当我尝试更改它时,它都不能正常工作。 - Mohammed
我希望当我接近滚动条的末尾时,小部件逐渐消失,而不是从中间开始消失,就像代码中一样。 - Mohammed
@Mohammed,我已经更新了我的答案以修复您的小部件的淡出效果,请查看。如果您想延迟它,当滚动到一半时,注释部分开始淡出。 - Ante Bule
是的,我看到了,谢谢您。 - Mohammed

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接