如何在Flutter中滚动时为多个小部件设置动画

qjp7pelc  于 2023-01-14  发布在  Flutter
关注(0)|答案(1)|浏览(107)

我需要在滚动用户列表时实现自定义动画。

我的当前视图由以下元素组成:
SingleChildScrollView包含Column,其中:

  • Row的三个顶部元素(每个都是一个自定义小部件,基本上Stack的化身,奖章和细节(Column))
  • Row作为表头
  • 其他用户的ListView

SingleChildScrollViewNotificationListener Package ,ScrollNotification被填充到provider。然后,在每个顶部元素中侦听滚动值,以执行其自己的动画。
我想知道一些通用的路径和算法。我尝试了AnimatedPositioned,但一旦它应用于多个元素,它会导致性能问题。我应该使用AnimationController或一些更自定义的东西到目前为止?任何帮助将不胜感激。

bvjxkvbb

bvjxkvbb1#

正如pskink提到的,使用SliverPersistentHeader可以存档,这是一个演示小部件来说明它是如何做到的。你需要发挥价值。我最喜欢的部分是使用.lerpdoubleLerp ...来定位项目。

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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: CustomScrollView(
        slivers: [
          SliverPersistentHeader(
            pinned: true,
            delegate: CustomSliverPersistentHeaderDelegate(),
          ),
          const SliverToBoxAdapter(
            child: SizedBox(
              height: 3333,
              width: 200,
            ),
          ),
        ],
      ),
    );
  }
}

class CustomSliverPersistentHeaderDelegate
    extends SliverPersistentHeaderDelegate {
  @override
  Widget build(
      BuildContext context, double shrinkOffset, bool overlapsContent) {
    return LayoutBuilder(builder: (_, constraints) {

      final t = shrinkOffset / maxExtent;
      final width = constraints.maxWidth;
      final itemMaxWidth = width / 4;

      double xFactor = -.4;
      return ColoredBox(
        color: Colors.cyanAccent.withOpacity(.3),
        child: Stack(
          children: [
            Align(
              alignment:
                  Alignment.lerp(Alignment.center, Alignment(xFactor, -.2), t)!
                    ..x,
              child: buildRow(
                  color: Colors.deepPurple, itemMaxWidth: itemMaxWidth, t: t),
            ),
            Align(
              alignment: Alignment.lerp(
                  Alignment.centerRight, Alignment(xFactor, 0), t)!,
              child:
                  buildRow(color: Colors.red, itemMaxWidth: itemMaxWidth, t: t),
            ),
            Align(
              alignment: Alignment.lerp(
                  Alignment.centerLeft, Alignment(xFactor, .2), t)!,
              child: buildRow(
                  color: Colors.amber, itemMaxWidth: itemMaxWidth, t: t),
            ),
          ],
        ),
      );
    });
  }

  Container buildRow(
      {required Color color, required double itemMaxWidth, required double t}) {
    return Container(
      width: lerpDouble(itemMaxWidth, itemMaxWidth * .3, t),
      height: lerpDouble(itemMaxWidth, itemMaxWidth * .3, t),
      color: color,
    );
  }
/// you need to increase when it it not pinned 
  @override
  double get maxExtent => 400;

  @override
  double get minExtent => 300;

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

相关问题