簡體   English   中英

Flutter 自定義動畫圖標

[英]Flutter Custom Animated Icon

我希望制作一個可以從列表中添加和刪除的項目。

我正在尋找的是擁有 + 圖標和 - 圖標,並在這兩個圖標之間設置動畫,以獲得干凈流暢的外觀。

我有以下代碼

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

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

這對於 flutter 中的內置動畫圖標來說很好。

我希望使用 + 和 - 圖標,但外觀相同。

有沒有辦法做到這一點?

你很幸運,我的朋友! Flutter 已經為您提供了 AnimatedIcon()

文檔中的 AnimatedIcon Class

本周視頻動畫圖標小部件

現在用 Flare 為您的圖標設置動畫。 Jeff Delaney 為此做了一個很好的教程。

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;
          });
        }),

}

自定義動畫需要三樣東西

  1. Animation Controller
  2. 吐溫
  3. Animation

下面的簡單示例

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,
        ),
      ),
    );
  }
}

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

我知道它不如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;
        });
      },
    );

結果: 結果


或者您可以使用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;
        });
      },
    )

結果: 結果-2


使用這種方法,您可以使用任何您想要的圖標,並且不需要創建單獨的AnimationController來控制過渡,這與AnimatedIcon不同

看起來 Flutter 團隊使用名為 vitool 的命令行工具將 SVG 轉換為可用作動畫圖標的路徑。 如果你有一個相對簡單的動畫 SVG,你可以嘗試在這個存儲庫的 bin 文件夾中運行 main.dart 命令行工具:https://github.com/flutter/flutter/tree/master/dev/tools/vitool 我還沒有嘗試過,但如果我發現任何問題,我會嘗試並報告。 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,
(...)

您可以簡單地使用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

參考圖片

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM