草庐IT

flutter - 将小部件从其容器外部动画到其最终位置

coder 2023-05-09 原文

我正在尝试创建一个动画,其中小部件从其容器外部移动到其最终位置。

类似这样的:

或类似的内容(在选择练习屏幕中):

事先不知道容器内部的最终位置(由容器计算,如网格、行、列等)。

我认为我需要一个知道其在屏幕上的位置的小部件。用于在容器上方绘制动画并为容器中两个小部件的不透明度设置动画的叠加层。 我在正确的轨道上吗?

最佳答案

我为此创建了一个包:https://github.com/letsar/flutter_sidekick .

要完成这些类型的动画,您可以使用 SidekickTeamBuilder 小部件。

这里是一个创建以下动画的代码示例:

import 'package:flutter/material.dart';
import 'package:flutter_sidekick/flutter_sidekick.dart';
import '../widgets/utils.dart';

class BubblesExample extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return SidekickTeamBuilder<String>(
      animationDuration: Duration(milliseconds: 500),
      initialSourceList: <String>[
        'Log\nextension',
        'Goblet\nSquats',
        'Squats',
        'Barbell\nLunge',
        'Burpee',
        'Dumbell\nLunge',
        'Front\nSquats',
      ],
      builder: (context, sourceBuilderDelegates, targetBuilderDelegates) {
        return Center(
          child: Padding(
            padding: const EdgeInsets.all(8.0),
            child: ListView(
              children: <Widget>[
                ConstrainedBox(
                  constraints: BoxConstraints(minHeight: 150.0),
                  child: Wrap(
                    spacing: 4.0,
                    runSpacing: 4.0,
                    children: targetBuilderDelegates.map((builderDelegate) {
                      return builderDelegate.build(
                        context,
                        GestureDetector(
                          onTap: () => builderDelegate.state
                              .move(builderDelegate.message),
                          child: Bubble(
                            radius: 30.0,
                            fontSize: 12.0,
                            backgroundColor: Colors.blue,
                            foregroundColor: Colors.white,
                            child: Padding(
                              padding: const EdgeInsets.all(2.0),
                              child: Text(
                                builderDelegate.message,
                                textAlign: TextAlign.center,
                              ),
                            ),
                          ),
                        ),
                        animationBuilder: (animation) => CurvedAnimation(
                              parent: animation,
                              curve: FlippedCurve(Curves.easeOut),
                            ),
                        flightShuttleBuilder: (
                          context,
                          animation,
                          type,
                          from,
                          to,
                        ) =>
                            buildShuttle(
                              animation,
                              builderDelegate.message,
                            ),
                      );
                    }).toList(),
                  ),
                ),
                SizedBox(
                  height: 100.0,
                  child: Row(
                    mainAxisAlignment: MainAxisAlignment.center,
                    crossAxisAlignment: CrossAxisAlignment.center,
                    children: <Widget>[
                      CircleButton(
                        text: '>',
                        onPressed: () => SidekickTeamBuilder.of<String>(context)
                            .moveAll(SidekickFlightDirection.toSource),
                      ),
                      SizedBox(width: 60.0, height: 60.0),
                      CircleButton(
                        text: '<',
                        onPressed: () => SidekickTeamBuilder.of<String>(context)
                            .moveAll(SidekickFlightDirection.toTarget),
                      ),
                    ],
                  ),
                ),
                Center(
                  child: Wrap(
                    spacing: 4.0,
                    runSpacing: 4.0,
                    children: sourceBuilderDelegates.map((builderDelegate) {
                      return builderDelegate.build(
                        context,
                        GestureDetector(
                          onTap: () => builderDelegate.state
                              .move(builderDelegate.message),
                          child: Bubble(
                            radius: 50.0,
                            fontSize: 20.0,
                            backgroundColor: Colors.green,
                            foregroundColor: Colors.white,
                            child: Padding(
                              padding: const EdgeInsets.all(2.0),
                              child: Text(
                                builderDelegate.message,
                                textAlign: TextAlign.center,
                              ),
                            ),
                          ),
                        ),
                        animationBuilder: (animation) => CurvedAnimation(
                              parent: animation,
                              curve: Curves.easeOut,
                            ),
                        flightShuttleBuilder: (
                          context,
                          animation,
                          type,
                          from,
                          to,
                        ) =>
                            buildShuttle(
                              animation,
                              builderDelegate.message,
                            ),
                      );
                    }).toList(),
                  ),
                ),
              ],
            ),
          ),
        );
      },
    );
  }

  Widget buildShuttle(
    Animation<double> animation,
    String message,
  ) {
    return AnimatedBuilder(
      animation: animation,
      builder: (_, __) {
        return Bubble(
          radius: Tween<double>(begin: 50.0, end: 30.0).evaluate(animation),
          fontSize: Tween<double>(begin: 20.0, end: 12.0).evaluate(animation),
          backgroundColor: ColorTween(begin: Colors.green, end: Colors.blue)
              .evaluate(animation),
          foregroundColor: Colors.white,
          child: Padding(
            padding: const EdgeInsets.all(2.0),
            child: Text(
              message,
              textAlign: TextAlign.center,
            ),
          ),
        );
      },
    );
  }
}

class Bubble extends StatelessWidget {
  const Bubble({
    Key key,
    this.child,
    this.backgroundColor,
    this.foregroundColor,
    this.radius,
    this.fontSize,
  }) : super(key: key);

  final Widget child;

  final Color backgroundColor;

  final Color foregroundColor;

  final double radius;

  final double fontSize;

  @override
  Widget build(BuildContext context) {
    final ThemeData theme = Theme.of(context);
    TextStyle textStyle =
        theme.primaryTextTheme.subhead.copyWith(color: foregroundColor);
    Color effectiveBackgroundColor = backgroundColor;
    if (effectiveBackgroundColor == null) {
      switch (ThemeData.estimateBrightnessForColor(textStyle.color)) {
        case Brightness.dark:
          effectiveBackgroundColor = theme.primaryColorLight;
          break;
        case Brightness.light:
          effectiveBackgroundColor = theme.primaryColorDark;
          break;
      }
    } else if (foregroundColor == null) {
      switch (ThemeData.estimateBrightnessForColor(backgroundColor)) {
        case Brightness.dark:
          textStyle = textStyle.copyWith(color: theme.primaryColorLight);
          break;
        case Brightness.light:
          textStyle = textStyle.copyWith(color: theme.primaryColorDark);
          break;
      }
    }

    textStyle = textStyle.copyWith(fontSize: fontSize);

    final double diameter = radius * 2;
    return Container(
      width: diameter,
      height: diameter,
      decoration: BoxDecoration(
        color: effectiveBackgroundColor,
        shape: BoxShape.circle,
      ),
      child: Center(
        child: IconTheme(
          data: theme.iconTheme.copyWith(color: textStyle.color),
          child: DefaultTextStyle(
            style: textStyle,
            child: child,
          ),
        ),
      ),
    );
  }
}

关于flutter - 将小部件从其容器外部动画到其最终位置,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52918813/

有关flutter - 将小部件从其容器外部动画到其最终位置的更多相关文章

  1. Unity 3D 制作开关门动画,旋转门制作,推拉门制作,门把手动画制作 - 2

    Unity自动旋转动画1.开门需要门把手先动,门再动2.关门需要门先动,门把手再动3.中途播放过程中不可以再次进行操作觉得太复杂?查看我的文章开关门简易进阶版效果:如果这个门可以直接打开的话,就不需要放置"门把手"如果门把手还有钥匙需要旋转,那就可以把钥匙放在门把手的"门把手",理论上是可以无限套娃的可调整参数有:角度,反向,轴向,速度运行时点击Test进行测试自己写的代码比较垃圾,命名与结构比较拉,高手轻点喷,新手有类似的需求可以拿去做参考上代码usingSystem.Collections;usingSystem.Collections.Generic;usingUnityEngine;u

  2. ruby - 正则表达式在哪个位置失败? - 2

    我需要一个非常简单的字符串验证器来显示第一个符号与所需格式不对应的位置。我想使用正则表达式,但在这种情况下,我必须找到与表达式相对应的字符串停止的位置,但我找不到可以做到这一点的方法。(这一定是一种相当简单的方法……也许没有?)例如,如果我有正则表达式:/^Q+E+R+$/带字符串:"QQQQEEE2ER"期望的结果应该是7 最佳答案 一个想法:你可以做的是标记你的模式并用可选的嵌套捕获组编写它:^(Q+(E+(R+($)?)?)?)?然后你只需要计算你获得的捕获组的数量就可以知道正则表达式引擎在模式中停止的位置,你可以确定匹配结束

  3. ruby - 从外部访问类的实例变量 - 2

    我理解(我认为)Ruby中类变量和类的实例变量之间的区别。我想知道如何从该类外部访问该类的实例变量。从内部(即在类方法中而不是实例方法中),它可以直接访问,但是从外部,有没有办法做MyClass.class.[@$#]variablename?我没有任何具体原因要这样做,只是学习Ruby并想知道是否可行。 最佳答案 classMyClass@my_class_instance_var="foo"class上述yield:>>foo我相信Arkku演示了如何从类外部访问类变量(@@),而不是类实例变量(@)。我从这篇文章中提取了上述内

  4. ruby - 下载位置 Selenium-webdriver Cucumber Chrome - 2

    我将Cucumber与Ruby结合使用。通过Selenium-Webdriver在Chrome中运行测试时,我想将下载位置更改为测试文件夹而不是用户下载文件夹。我当前的chrome驱动程序是这样设置的:Capybara.default_driver=:seleniumCapybara.register_driver:seleniumdo|app|Capybara::Selenium::Driver.new(app,:browser=>:chrome,desired_capabilities:{'chromeOptions'=>{'args'=>%w{window-size=1920,1

  5. ruby - Heroku production.log 文件位置 - 2

    我想在heroku.com上查看我的应用程序日志的内容,所以我关注了thisexcellentadvice并拥有我所有的日志内容。但是我现在很想知道我的日志文件实际在哪里,因为“log/production.log”似乎是空的:C:\>herokuconsoleRubyconsoleforajpbrevx.heroku.com>>files=Dir.glob("*")=>["public","tmp","spec","Rakefile","doc","config.ru","app","config","lib","README","Gemfile.lock","vendor","sc

  6. ruby - 在 Ruby 中查找多个正则表达式匹配的模式和位置 - 2

    这应该是一个简单的问题,但我找不到任何相关信息。给定一个Ruby中的正则表达式,对于每个匹配项,我需要检索匹配的模式$1、$2,但我还需要匹配位置。我知道=~运算符为我提供了第一个匹配项的位置,而string.scan(/regex/)为我提供了所有匹配模式。如果可能,我需要在同一步骤中获得两个结果。 最佳答案 MatchDatastring.scan(regex)do$1#Patternatfirstposition$2#Patternatsecondposition$~.offset(1)#Startingandendingpo

  7. ruby - 无法安装 gem - make 未被识别为内部或外部命令可运行程序或批处理文件 - 2

    我想在Windows7上安装带有ruby​​1.9.3的rspec-railsgem。我收到一些错误消息,提示无法安装某些json库。所以,我使用下面的说明来解决它。来源=The'json'nativegemrequiresinstalledbuildtools从[rubyinstaller.org][3]下载[Ruby1.9.3][2]从[rubyinstaller.org][3]下载DevKit文件对于Ruby1.9.3,使用[DevKit-tdm-32-4.5.2-20110712-1620-sfx.exe][4]将DevKit解压到路径C:\Ruby193\DevKit运行cd

  8. ruby - 使用 Class.new 时访问外部范围 - 2

    是否有可能以某种方式访问​​Class.new范围内的a?a=5Class.new{defb;aend}.new.b#NameError:undefinedlocalvariableormethod`a'for#:0x007fa8b15e9af0>#:in`b' 最佳答案 即使@MarekLipka的回答是正确的——改变变量范围总是有风险的。这是可行的,因为每个block都带有创建它的上下文,因此您的局部变量a突然变得不那么局部了——它变成了一个“隐藏的”全局变量:a=5object=Class.new{define_method(

  9. ruby-on-rails - 尝试打开 .gitignore 以在文本编辑器中对其进行编辑,但在 OS X Mountain Lion 上找不到文件位置 - 2

    我使用“newapp_name”创建了一个新的Rails应用程序,我正在尝试编辑.gitignore文件,但在我的应用程序文件夹中找不到它。我在哪里可以找到它?我安装了Git。 最佳答案 .gitignore位于项目的root中,而不是app子目录中。首先打开终端并进入您的目录。您需要使用ls-a来显示stash文件。然后使用打开.gitignore 关于ruby-on-rails-尝试打开.gitignore以在文本编辑器中对其进行编辑,但在OSXMountainLion上找不到文件位

  10. ruby-on-rails - 在 Rails 中存储(结构化)配置数据的位置 - 2

    对于我正在编写的Rails3应用程序,我正在考虑从本地文件系统上的XML、YAML或JSON文件中读取一些配置数据。重点是:我应该把这些文件放在哪里?Rails应用程序中是否有用于存储此类内容的默认位置?附带说明一下,我的应用程序部署在Heroku上。 最佳答案 我经常做的是:如果文件是通用配置文件:我在目录/config中创建一个YAML文件,每个环境有一个上层key如果我为每个环境(大项目)创建一个文件:我为每个环境创建一个YAML并将它们存储在/config/environments/然后我在加载YAML的地方创建了一个初始化

随机推荐