支持自定义动画的Text文本组件

533 阅读4分钟

前言

Flutter 是 Google 开源的应用开发框架,仅通过一套代码就能构建支持Android、iOS、Windows、Linux等多平台的应用。Flutter的性能非常高,拥有120fps的刷新率,也是目前非常流行的跨平台UI开发框架。

本专栏为大家收集了Github上近70个优秀开源库,后续也将持续更新。希望可以帮助大家提升搬砖效率,同时祝愿Flutter的生态越来越完善🎉🎉。

正文

一、🚀 轮子介绍

  • 名称:animated_text_kit
  • 概述:一个生成动画文本的StatefulWidget,内置多种动画并支持添加自定义动画效果
  • 出版商:aagarwal9782@gmail.com
  • 仓库地址:Animated-Text-Kit
  • 推荐指数: ⭐️⭐️⭐️⭐️
  • 常用指数: ⭐️⭐️⭐️⭐️
  • 效果预览:

cover.gif

二、⚙️ 安装及使用

dependencies:
  animated_text_kit: ^4.2.1
import 'package:animated_text_kit/animated_text_kit.dart';

三、🔧 常用属性

属性描述
pause文本动画之间的暂停时间
displayFullTextOnTap点击是否立即完成动画
isRepeatingAnimation动画是否重复播放,配合totalRepeatCount使用
repeatForever动画是否无限重复播放
totalRepeatCount动画重复播放次数,若repeatForever不为False则此项忽略
onTap点击动画文本回调
onNext(int index, bool isLast)这是在下一个文本动画之前、上一个动画的暂停之后调用的,index代表播放次数,isLast代表是否是最后一次播放
onNextBeforePause(int index, bool isLast)这是在下一个文本动画之前、在上一个动画暂停之前调用的,index代表播放次数,isLast代表是否是最后一次播放
onFinished动画播放结束时调用

四、🗂 示例

Tips:示例效果需要提前下载对应字体,若考虑到字体文件过大需要处理可参考这篇文章: 安装包太大?使用fontTools给字体文件瘦个身

1.滚动

滚动.gif

Row(
  mainAxisSize: MainAxisSize.min,
  children: <Widget>[
    const SizedBox(width: 20.0, height: 100.0),
    const Text(
      'Be',
      style: TextStyle(fontSize: 43.0),
    ),
    const SizedBox(width: 20.0, height: 100.0),
    DefaultTextStyle(
      style: const TextStyle(
        fontSize: 40.0,
        fontFamily: 'Horizon',
      ),
      child: AnimatedTextKit(
        animatedTexts: [
          RotateAnimatedText('AWESOME'),
          RotateAnimatedText('OPTIMISTIC'),
          RotateAnimatedText('DIFFERENT'),
        ]
        onTap: () {
          print("Tap Event");
        },
      ),
    ),
  ],
);

2.渐现

渐现.gif

return SizedBox(
  width: 250.0,
  child: DefaultTextStyle(
    style: const TextStyle(
      fontSize: 32.0,
      fontWeight: FontWeight.bold,
    ),
    child: AnimatedTextKit(
      animatedTexts: [
        FadeAnimatedText('do IT!'),
        FadeAnimatedText('do it RIGHT!!'),
        FadeAnimatedText('do it RIGHT NOW!!!'),
      ],
      onTap: () {
        print("Tap Event");
      },
    ),
  ),
);

3.打字

打字.gif

return SizedBox(
  width: 250.0,
  child: DefaultTextStyle(
    style: const TextStyle(
      fontSize: 30.0,
      fontFamily: 'Bobbers',
    ),
    child: AnimatedTextKit(
      animatedTexts: [
        TyperAnimatedText('It is not enough to do your best,'),
        TyperAnimatedText('you must know what to do,'),
        TyperAnimatedText('and then do your best'),
        TyperAnimatedText('- W.Edwards Deming'),
      ]
      onTap: () {
        print("Tap Event");
      },
    ),
  ),
);

4.打字(带下划线)

打字_带下划线.gif

return SizedBox(
  width: 250.0,
  child: DefaultTextStyle(
    style: const TextStyle(
      fontSize: 30.0,
      fontFamily: 'Agne',
    ),
    child: AnimatedTextKit(
      animatedTexts: [
        TypewriterAnimatedText('Discipline is the best tool'),
        TypewriterAnimatedText('Design first, then code'),
        TypewriterAnimatedText('Do not patch bugs out, rewrite them'),
        TypewriterAnimatedText('Do not test bugs out, design them out'),
      ],
      onTap: () {
        print("Tap Event");
      },
    ),
  ),
);

5.缩放

缩放.gif

return SizedBox(
  width: 250.0,
  child: DefaultTextStyle(
    style: const TextStyle(
      fontSize: 70.0,
      fontFamily: 'Canterbury',
    ),
    child: AnimatedTextKit(
      animatedTexts: [
        ScaleAnimatedText('Think'),
        ScaleAnimatedText('Build'),
        ScaleAnimatedText('Ship'),
      ],
      onTap: () {
        print("Tap Event");
      },
    ),
  ),
);

6.闪光

闪光.gif

const colorizeColors = [
  Colors.purple,
  Colors.blue,
  Colors.yellow,
  Colors.red,
];

const colorizeTextStyle = TextStyle(
  fontSize: 50.0,
  fontFamily: 'Horizon',
);

return SizedBox(
  width: 250.0,
  child: AnimatedTextKit(
    animatedTexts: [
      ColorizeAnimatedText(
        'Larry Page',
        textStyle: colorizeTextStyle,
        colors: colorizeColors,
      ),
      ColorizeAnimatedText(
        'Bill Gates',
        textStyle: colorizeTextStyle,
        colors: colorizeColors,
      ),
      ColorizeAnimatedText(
        'Steve Jobs',
        textStyle: colorizeTextStyle,
        colors: colorizeColors,
      ),
    ],
    isRepeatingAnimation: true,
    onTap: () {
      print("Tap Event");
    },
  ),
);

7.水波

水波.gif

return SizedBox(
  width: 250.0,
  child: TextLiquidFill(
    text: 'LIQUIDY',
    waveColor: Colors.blueAccent,
    boxBackgroundColor: Colors.redAccent,
    textStyle: TextStyle(
      fontSize: 80.0,
      fontWeight: FontWeight.bold,
    ),
    boxHeight: 300.0,
  ),
);

8.跳动

跳动.gif

return DefaultTextStyle(
  style: const TextStyle(
    fontSize: 20.0,
  ),
  child: AnimatedTextKit(
    animatedTexts: [
      WavyAnimatedText('Hello World'),
      WavyAnimatedText('Look at the waves'),
    ],
    isRepeatingAnimation: true,
    onTap: () {
      print("Tap Event");
    },
  ),
);

9.闪烁

闪烁.gif

return SizedBox(
  width: 250.0,
  child: DefaultTextStyle(
    style: const TextStyle(
      fontSize: 35,
      color: Colors.white,
      shadows: [
        Shadow(
          blurRadius: 7.0,
          color: Colors.white,
          offset: Offset(0, 0),
        ),
      ],
    ),
    child: AnimatedTextKit(
      repeatForever: true,
      animatedTexts: [
        FlickerAnimatedText('Flicker Frenzy'),
        FlickerAnimatedText('Night Vibes On'),
        FlickerAnimatedText("C'est La Vie !"),
      ],
      onTap: () {
        print("Tap Event");
      },
    ),
  ),
);

五、🏠 创建你自己的自定义动画

你可以通过 AnimatedText 轻松创建自己的动画,可以参考一下以下代码,这里写了一个文字从左上方滑入,然后向右下方划出并渐渐消失的动画效果

未命名.gif

import 'package:animated_text_kit/animated_text_kit.dart';
import 'package:flutter/material.dart';
class SlideAnimatedText extends AnimatedText {
/// 过渡高度,默认 [TextStyle.fontSize] * 10 / 3
final double? transitionHeight;

/// 对齐,默认[Alignment.center]
final AlignmentGeometry alignment;

/// 文本方向,默认[TextDirection.ltr]
final TextDirection textDirection;

/// 控制文本是否划入(划出),默认true
final bool slideOut;

SlideAnimatedText(
    String text, {
        TextAlign textAlign = TextAlign.start,
        TextStyle? textStyle,
        Duration duration = const Duration(milliseconds: 2000),
        this.transitionHeight,
        this.alignment = Alignment.center,
        this.textDirection = TextDirection.ltr,
        this.slideOut = true,
    }) : super(
            text: text,
            textAlign: textAlign,
            textStyle: textStyle,
            duration: duration,
        );

late Animation<double> _fadeIn, _fadeOut;
late Animation<Alignment> _slideIn, _slideOut;

@override
void initAnimation(AnimationController controller) {
    final direction = textDirection;
    final inIntervalEnd = slideOut ? 0.1 : 1.0;
    
    _slideIn = AlignmentTween(
    begin: Alignment.topLeft.add(alignment).resolve(direction),
    end: Alignment.center.add(alignment).resolve(direction),
    ).animate(
        CurvedAnimation(
        parent: controller,
        curve: Interval(0.0, inIntervalEnd, curve: Curves.linear),
        ),
    );
    
    _fadeIn = Tween<double>(begin: 0.1, end: 1.0).animate(
    CurvedAnimation(
        parent: controller,
        curve: Interval(0.0, inIntervalEnd, curve: Curves.easeOut),
        ),
    );
    
    if (slideOut) {
    _slideOut = AlignmentTween(
        begin: Alignment.center.add(alignment).resolve(direction),
        end: Alignment.bottomRight.add(alignment).resolve(direction),
    ).animate(
    CurvedAnimation(
        parent: controller,
        curve: const Interval(0.7, 1.0, curve: Curves.linear),
        ),
    );

    _fadeOut = Tween<double>(begin: 1.0, end: 0.0).animate(
        CurvedAnimation(
        parent: controller,
        curve: const Interval(0.7, 1.0, curve: Curves.easeIn),
        ),
       );
    }
}

@override
Widget completeText(BuildContext context) =>
    slideOut ? SizedBox.shrink() : super.completeText(context);
@override
Widget animatedBuilder(BuildContext context, Widget? child) {
    final fontSize =
        textStyle?.fontSize ?? DefaultTextStyle.of(context).style.fontSize;
return SizedBox(
    height: transitionHeight ?? (fontSize! * 10 / 3),
    child: AlignTransition(
    alignment: _slideIn.value.y != 0.0 || !slideOut ? _slideIn : _slideOut,
    child: Opacity(
opacity: _fadeIn.value != 1.0 || !slideOut
? _fadeIn.value
: _fadeOut.value,
        child: textWidget(text),
            ),
        ),
    );
}}

使用

AnimatedTextKit(
    animatedTexts: [
        SlideAnimatedText('自定义动画'),
    ],
    repeatForever: true,
),