简体   繁体   English

Flutter 自定义动画图标

[英]Flutter Custom Animated Icon

I am looking to make a item that gets added and removed from list.我希望制作一个可以从列表中添加和删除的项目。

what I am looking for is to have the + icon and the - icon and animate between the 2 for a clean and smooth look.我正在寻找的是拥有 + 图标和 - 图标,并在这两个图标之间设置动画,以获得干净流畅的外观。

I have the following code我有以下代码

Container(
            padding: EdgeInsets.fromLTRB(0, 0, 20, 0),
            child: AnimatedIcon(
              icon: AnimatedIcons.home_menu,
              progress: _animationController,
              color: Colors.white,
            ))

with

void _handleOnPressed() {
setState(() {
  isPlaying = !isPlaying;
  isPlaying
      ? _animationController.forward()
      : _animationController.reverse();
  });
}

This for fine for the built in animated icons in flutter.这对于 flutter 中的内置动画图标来说很好。

I am looking to use the + and the - icon, but with the same look.我希望使用 + 和 - 图标,但外观相同。

Is there a way to do this?有没有办法做到这一点?

You're in luck my friend!你很幸运,我的朋友! Flutter already has you covered with AnimatedIcon() Flutter 已经为您提供了 AnimatedIcon()

AnimatedIcon Class in the docs 文档中的 AnimatedIcon Class

Animated Icon Widget of the week Video本周视频动画图标小部件

Now to animate your Icons with Flare.现在用 Flare 为您的图标设置动画。 Jeff Delaney made a good tutorial for this. Jeff Delaney 为此做了一个很好的教程。

https://fireship.io/lessons/animated-navigation-flutter-flare/ https://fireship.io/lessons/animated-navigation-flutter-flare/

  class _CreatePackageViewState extends State<CreatePackageView>
with SingleTickerProviderStateMixin {  
   bool expanded = true;
  AnimationController controller;
  @override
   void initState() {
    super.initState();
    controller = AnimationController(
      vsync: this,
      duration: Duration(milliseconds: 400),
      reverseDuration: Duration(milliseconds: 400),
    );
  }



  IconButton(
        icon: AnimatedIcon(
          icon: AnimatedIcons.menu_close,
          progress: controller,
          semanticLabel: 'Show menu',
        ),
        onPressed: () {
          setState(() {
            expanded ? controller.forward() : controller.reverse();
            expanded = !expanded;
          });
        }),

}

You need 3 things for custom animations自定义动画需要三样东西

  1. Animation Controller Animation Controller
  2. Tween吐温
  3. Animation Animation

Simple example below下面的简单示例

import 'package:flutter/material.dart';

class AnimationsPractice extends StatefulWidget {
  @override
  _AnimationsPracticeState createState() => _AnimationsPracticeState();
}

class _AnimationsPracticeState extends State<AnimationsPractice> with SingleTickerProviderStateMixin {

  AnimationController controller;
  Animation animation;

  @override
  void initState() {
    super.initState();
    controller = AnimationController(
        duration: Duration(milliseconds: 500),
        vsync: this);

   animation = ColorTween(begin: Colors.purple, end: Colors.red[700]).animate(controller);

    controller.forward();

    animation.addStatusListener((status) {
      if(status == AnimationStatus.completed){
        controller.reverse(from: 1.0);
        print(animation.value);
      }
      else if(status == AnimationStatus.dismissed){
        controller.forward();
      }
    });

    controller.addListener(() {
      setState(() {
      });
      print(controller.value);
    });
  }

  @override
  void dispose() {
    super.dispose();
    controller.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: Colors.yellow,
      appBar: AppBar(
        title: Text('Heart Beat'),
      ),
      body: Center(
        child: Icon(
          Icons.favorite,
          size: animation.value * 100,
        ),
      ),
    );
  }
}

Use animated_icon_button package https://pub.dev/packages/animated_icon_button/install使用 animated_icon_button package https://pub.dev/packages/animated_icon_button/install

I know it's not as beautiful as AnimatedIcon , but you could actually get very similar transition with any 2 icons of your choice with just a few lines of code:我知道它不如AnimatedIcon漂亮,但您实际上可以通过几行代码使用您选择的任何 2 个图标获得非常相似的过渡:

 IconButton(
      icon: AnimatedSwitcher(
          duration: const Duration(milliseconds: 300),
          transitionBuilder: (child, anim) => RotationTransition(
                turns: child.key == ValueKey('icon1')
                    ? Tween<double>(begin: 1, end: 0.75).animate(anim)
                    : Tween<double>(begin: 0.75, end: 1).animate(anim),
                child: FadeTransition(opacity: anim, child: child),
              ),
          child: _currIndex == 0
              ? Icon(Icons.close, key: const ValueKey('icon1'))
              : Icon(
                  Icons.arrow_back,
                  key: const ValueKey('icon2'),
                )),
      onPressed: () {
        setState(() {
          _currIndex = _currIndex == 0 ? 1 : 0;
        });
      },
    );

Result:结果: 结果


Or you can use ScaleTransition instead of FadeTransition , and get even more similar animation:或者您可以使用ScaleTransition代替FadeTransition ,并获得更相似的 animation:

IconButton(
      icon: AnimatedSwitcher(
          duration: const Duration(milliseconds: 350),
          transitionBuilder: (child, anim) => RotationTransition(
                turns: child.key == ValueKey('icon1')
                    ? Tween<double>(begin: 1, end: 0.75).animate(anim)
                    : Tween<double>(begin: 0.75, end: 1).animate(anim),
                child: ScaleTransition(scale: anim, child: child),
              ),
          child: _currIndex == 0
              ? Icon(Icons.close, key: const ValueKey('icon1'))
              : Icon(
                  Icons.arrow_back,
                  key: const ValueKey('icon2'),
                )),
      onPressed: () {
        setState(() {
          _currIndex = _currIndex == 0 ? 1 : 0;
        });
      },
    )

Result:结果: 结果-2


With this approach you could use any icons you want, and it doesn't require creating separate AnimationController just to control the transition, unlike AnimatedIcon使用这种方法,您可以使用任何您想要的图标,并且不需要创建单独的AnimationController来控制过渡,这与AnimatedIcon不同

It looks like the Flutter team use a command line tool called vitool to convert SVGs to paths that can be consumed as an animated icon.看起来 Flutter 团队使用名为 vitool 的命令行工具将 SVG 转换为可用作动画图标的路径。 If you have a relatively simple animated SVG, you can try running the main.dart command line tool within the bin folder of this repository:https://github.com/flutter/flutter/tree/master/dev/tools/vitool .如果你有一个相对简单的动画 SVG,你可以尝试在这个存储库的 bin 文件夹中运行 main.dart 命令行工具:https://github.com/flutter/flutter/tree/master/dev/tools/vitool I haven't attempted yet, but I will try and report back if I find any issues.我还没有尝试过,但如果我发现任何问题,我会尝试并报告。 The output should look like the following: output 应如下所示:

const _AnimatedIconData _$menu_arrow = _AnimatedIconData(
  Size(48.0, 48.0),
  <_PathFrames>[
    _PathFrames(
      opacities: <double>[
        1.0,
        1.0,
        1.0,
        1.0,
        1.0,
        1.0,
        1.0,
(...)

you can simply use animate_icons 2.0.0 package to animate two icons您可以简单地使用animate_icons 2.0.0 package 为两个图标设置动画

AnimateIcons(
    startIcon: Icons.add_circle,
    endIcon: Icons.add_circle_outline,
    size: 100.0,
    controller: controller,
    // add this tooltip for the start icon
    startTooltip: 'Icons.add_circle',
    // add this tooltip for the end icon
    endTooltip: 'Icons.add_circle_outline',
    size: 60.0,
    onStartIconPress: () {
        print("Clicked on Add Icon");
        return true;
    },
    onEndIconPress: () {
        print("Clicked on Close Icon");
        return true;
    },
    duration: Duration(milliseconds: 500),
    startIconColor: Colors.deepPurple,
    endIconColor: Colors.deepOrange,
    clockwise: false,
),

https://pub.dev/packages/animate_icons https://pub.dev/packages/animate_icons

参考图片

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM