Flutter动画滑动标题栏

huangapple go评论54阅读模式
英文:

Flutter animated sliver header

问题

我正在尝试创建一个可以进行动画的个人资料页标头。

如果您考虑上面的图片,Section 1 是我们在完全展开的标头中看到的内容,Section 2 是我们想在固定模式下看到的内容。

现在,我想要过渡,将图像 - 紫色圆圈 - 移动到一侧,轻微缩小它,还要移动名称和链接。

我可以实现所有这些,但有一件事我不知道如何做:如何在展开视图中将它们居中显示。

由于我必须使用变换来移动小部件,所以不能简单地使用像列或中心这样的居中小部件。我也没有找到一种计算精确居中小部件位置的方法,因为它需要小部件的大小,而我没有这个信息。

英文:

I am trying to create a profile header sliver that can animate.

Flutter动画滑动标题栏

If you consider above image, Section 1 is what we see in the fully expanded sliver, and Section 2 is what we want to see in pinned mode.

Now I would like transition to move the image - purple circle - to the side, shrink it slightly, and also move the name and the links.

I can achieve all of that but one thing: How to center them in the expanded view.

As I have to use transform to move widgets around, I cannot simply use a centring widget like column or center. And I didn't find a way to calculate the exact position to center the widget, as it needs the size of the widget, that I don't have.

答案1

得分: 1

首先,我正在使用SliverPersistentHeaderDelegate,它提供了shrinkOffset,将在线性插值(lerp方法)中使用。

然后使用CompositedTransformTarget小部件来跟随中心小部件。

在这个示例中,可以使用targetAnchorfollowerAnchor,并使用t/shrinkOffset来维护其他动画。

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

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

class MySliverPersistentHeaderDelegate extends SliverPersistentHeaderDelegate {
  final LayerLink layerLink = LayerLink();
  @override
  Widget build(
      BuildContext context, double shrinkOffset, bool overlapsContent) {
    double t = shrinkOffset / maxExtent;

    return Material(
      color: Colors.cyanAccent.withOpacity(.2),
      child: Stack(
        children: [
          Align(
            alignment:
                Alignment.lerp(Alignment.center, Alignment.centerLeft, t)!,
            child: CompositedTransformTarget(
              link: layerLink,
              child: Padding(
                padding: const EdgeInsets.all(8.0),
                child: Container(
                  height: lerpDouble(100, kToolbarHeight - 10, t),
                  width: lerpDouble(100, kToolbarHeight - 10, t),
                  decoration: const ShapeDecoration(
                    shape: CircleBorder(),
                    color: Colors.deepPurple,
                  ),
                ),
              ),
            ),
          ),
          CompositedTransformFollower(
            link: layerLink,
            targetAnchor: Alignment.lerp(
                Alignment.bottomCenter, Alignment.centerRight, t)!,
            followerAnchor:
                Alignment.lerp(Alignment.topCenter, Alignment.centerLeft, t)!,
            child: Padding(
              padding: const EdgeInsets.all(8.0),
              child: Container(
                child: Column(
                  children: [Text("Sheikh")],
                ),
              ),
            ),
          ),
        ],
      ),
    );
  }

  @override
  double get maxExtent => kToolbarHeight * 6;

  @override
  double get minExtent => kToolbarHeight;

  @override
  bool shouldRebuild(covariant SliverPersistentHeaderDelegate oldDelegate) =>
      false;
}
英文:

Firstly I am using SliverPersistentHeaderDelegate and it provides shrinkOffset that will be used on linear interpolation(lerp method).

Then CompositedTransformTarget widget to follow the center widget.

On this example play with targetAnchor and followerAnchor and use t/shrinkOffset to maintain other animation.

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

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

class MySliverPersistentHeaderDelegate extends SliverPersistentHeaderDelegate {
  final LayerLink layerLink = LayerLink();
  @override
  Widget build(
      BuildContext context, double shrinkOffset, bool overlapsContent) {
    double t = shrinkOffset / maxExtent;

    return Material(
      color: Colors.cyanAccent.withOpacity(.2),
      child: Stack(
        children: [
          Align(
            alignment:
                Alignment.lerp(Alignment.center, Alignment.centerLeft, t)!,
            child: CompositedTransformTarget(
              link: layerLink,
              child: Padding(
                padding: const EdgeInsets.all(8.0),
                child: Container(
                  height: lerpDouble(100, kToolbarHeight - 10, t),
                  width: lerpDouble(100, kToolbarHeight - 10, t),
                  decoration: const ShapeDecoration(
                    shape: CircleBorder(),
                    color: Colors.deepPurple,
                  ),
                ),
              ),
            ),
          ),
          CompositedTransformFollower(
            link: layerLink,
            targetAnchor: Alignment.lerp(
                Alignment.bottomCenter, Alignment.centerRight, t)!,
            followerAnchor:
                Alignment.lerp(Alignment.topCenter, Alignment.centerLeft, t)!,
            child: Padding(
              padding: const EdgeInsets.all(8.0),
              child: Container(
                child: Column(
                  children: [Text("Sheikh")],
                ),
              ),
            ),
          ),
        ],
      ),
    );
  }

  @override
  double get maxExtent => kToolbarHeight * 6;

  @override
  double get minExtent => kToolbarHeight;

  @override
  bool shouldRebuild(covariant SliverPersistentHeaderDelegate oldDelegate) =>
      false;
}

huangapple
  • 本文由 发表于 2023年2月19日 00:24:44
  • 转载请务必保留本文链接:https://go.coder-hub.com/75494708.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定