Flutter在项目中使用动画不使用包实现详解

目录
  • 前言
  • 正文
    • 1 按下按钮柔软的感觉
    • 2 想要一个像 Instagram 一样的喜欢按钮吗?
    • 3 动画页面过渡
    • 4 动画文字
    • 5 更改/闪动文本样式

前言

动画对于 web 和移动应用程序都非常重要。但是在移动应用程序中不应该使用夸张的动画。简单但是很多动画使你的应用程序更好用。以至于当你点击一个按钮时,一种平滑的感觉或者页面过渡都会影响到你。

正文

1 按下按钮柔软的感觉

class _CustomButtonState extends State<CustomButton>
    with SingleTickerProviderStateMixin {
  late double _scale;
  late AnimationController _controller;
  @override
  void initState() {
    super.initState();
    _controller = AnimationController(
      vsync: this,
      duration: const Duration(milliseconds: 350),
      lowerBound: 0.0,
      upperBound: 0.1,
    )..addListener(() {
        setState(() {});
      });
  }
  @override
  void dispose() {
    _controller.dispose();
    super.dispose();
  }
  void _tapDown(TapDownDetails details) {
    _controller.forward();
  }
  void _tapUp(TapUpDetails details) {
    _controller.reverse();
  }
  @override
  Widget build(BuildContext context) {
    _scale = 1 - _controller.value;
    return GestureDetector(
      onTap: widget.onTap,
      onTapDown: _tapDown,
      onTapUp: _tapUp,
      child: Transform.scale(
        scale: _scale,
        child:

首先,我们创建一个名为 CustomButton 的 StatewWidget。我们将在应用程序的任何地方使用这个按钮。也许宽度,里面的文字会改变。在最后一个子部分之后,我们将设计我们的按钮。(我不想在这里占用太多的空间,你可以在文章的最后找到完成项目的源代码)。

在我们看到模拟器中的动画之前,我们还有一个场景。当我们按下这个按钮时,我们希望出现一个弹出窗口。弹出窗口突然出现在 Flutter 的屏幕上。同样,我们可以通过使用动画给人一种柔软的感觉。请确保您的应用程序将更加专业和吸引眼球的方式:)

return showGeneralDialog(
    context: context,
    pageBuilder: (context, animation, secondaryAnimation) {
      return ScaleTransition(
        scale: Tween<double>(begin: 0.5, end: 1).animate(animation),
        child: AlertDialog(

只要将这些 widget 包装在 AlertDialog 的顶部,您就会看到一个非常漂亮的效果

2 想要一个像 Instagram 一样的喜欢按钮吗?

class _FavoritesButtonState extends State<FavoritesButton>
    with SingleTickerProviderStateMixin {
  bool isFavorite = false;
  late final AnimationController _controller = AnimationController(
      vsync: this, duration: const Duration(milliseconds: 300));
  @override
  Widget build(BuildContext context) {
    return Container(
      height: 10.h,
      width: 10.w,
      decoration: const BoxDecoration(
        shape: BoxShape.circle,
        color: Colors.white,
        boxShadow: [
          BoxShadow(
            offset: Offset(0, 1),
            color: Colors.grey,
            blurRadius: 1,
          ),
        ],
      ),
      child: AnimatedBuilder(
          animation: _controller,
          builder: (context, child) => GestureDetector(
                child: isFavorite
                    ? AnimatedSwitcher(
                        switchInCurve: Curves.easeInOutBack,
                        transitionBuilder: (child, animation) =>
                            ScaleTransition(
                              scale: animation,
                              child: child,
                            ),
                        duration: const Duration(milliseconds: 300),
                        child: Icon(
                          Icons.favorite,
                          size: 3.7.h,
                          color: Colors.red,
                          key: const ValueKey('isFav'),
                        ))
                    : AnimatedSwitcher(
                        switchInCurve: Curves.easeInOutBack,
                        transitionBuilder: (child, animation) =>
                            ScaleTransition(
                          scale: animation,
                          child: child,
                        ),
                        duration: const Duration(milliseconds: 300),
                        child: Icon(
                          Icons.favorite_border_outlined,
                          size: 3.7.h,
                          color: Colors.grey,
                          key: const ValueKey('isNotFav'),
                        ),
                      ),
                onTap: () {
                  setState(() {
                    isFavorite = !isFavorite;
                  });
                },
              )),
    );
  }
}

当 isFavorite 状态改变时,动画将出现,按钮的内部将被涂成红色。这里最重要的部分是关键作业。如果您不这样做,系统将检测到两个相同的动画将不会出现。

3 动画页面过渡

实际上,这里有一个包依赖项。不过别担心,这是必要的。因为在 Flutter Navigator.push() 等方法现在是原始的。我强烈推荐使用 GoRoute 或 AutoRoute。在本文中,我们将讨论 GoRoute 中可用的动画。

import 'package:animations/view/empty/empty_view.dart';
import 'package:animations/view/home/home_view.dart';
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
animationPage({required GoRouterState state, required Widget route}) =>
    CustomTransitionPage<void>(
      key: state.pageKey,
      child: route,
      transitionsBuilder: (BuildContext context, Animation<double> animation,
              Animation<double> secondaryAnimation, Widget child) =>
          SlideTransition(
        position: animation.drive(
          Tween<Offset>(
            begin: const Offset(-1, 0),
            end: Offset.zero,
          ).chain(CurveTween(curve: Curves.fastOutSlowIn)),
        ),
        child: child,
      ),
    );
final routes = GoRouter(
  initialLocation: '/home',
  debugLogDiagnostics: true,
  routes: [
    GoRoute(
      path: '/home',
      pageBuilder: (context, state) {
        return animationPage(
          state: state,
          route: const HomeView(),
        );
      },
      routes: [
        GoRoute(
          path: 'empty',
          pageBuilder: (context, state) {
            return animationPage(
              state: state,
              route: const EmptyView(),
            );
          },
        ),
      ],
    ),
  ],
);

下面是将执行主要工作的方法 animationPage() 。我们用这种方法包装相关页面并完成工作。您可以通过更改 start: const Offset (-1,0)值来实现不同的动画。我想像书页一样过渡。这就是它看起来的样子

此外,我想提出一个批评。如果不使用动画,页面转换在 Flutter 中是非常粗糙的。

4 动画文字

通过您现在将看到的动画,您可以在页面首次打开时显示可滚动的文本。闲话少说,让我们检查一下代码,然后讨论一下我们能做些什么。

class _AnimatedTextState extends State<AnimatedText>
    with TickerProviderStateMixin {
  late final AnimationController _controller = AnimationController(
    duration: const Duration(seconds: 3),
    vsync: this,
  )..forward();
  late final Animation<double> _animation = CurvedAnimation(
    parent: _controller,
    curve: Curves.fastOutSlowIn,
  );
  @override
  void dispose() {
    _controller.dispose();
    super.dispose();
  }
  @override
  Widget build(BuildContext context) {
    return SizeTransition(
      sizeFactor: _animation,
      axis: Axis.horizontal,
      axisAlignment: -1,
      child: CustomText(
        widget.text,
        textStyle: widget.textStyle,
      ),
    );
  }
}

我想让你注意两件事。第一个是。.正向()方法正向()方法。这表示当打开该页面时,该动画仅显示一次。如果用 repeat() 替换它,它将是连续的。第二,轴对齐参数。我做了这个 -1。文本从左到右。如果我做 1,它会是相反的。这是我最喜欢的动画。您可以将此动画应用于除 Text 之外的许多其他 widget 。

5 更改/闪动文本样式

class ChangingText extends StatefulWidget {
  const ChangingText(this.text, {super.key});
  final String text;
  @override
  State<ChangingText> createState() => _ChangingTextState();
}
class _ChangingTextState extends State<ChangingText>
    with TickerProviderStateMixin {
  late AnimationController _controller;
  late TextStyleTween _styleTween;
  late CurvedAnimation _curvedAnimation;
  @override
  void initState() {
    super.initState();
    _controller = AnimationController(
      duration: const Duration(milliseconds: 750),
      vsync: this,
    )..repeat(reverse: true);
    _styleTween = TextStyleTween(
      begin: GoogleFonts.poppins(
        fontSize: 15.sp,
        color: AppConstants.java,
      ),
      end: TextStyle(
        fontSize: 15.sp,
        color: AppConstants.bittersweet,
      ),
    );
    _curvedAnimation = CurvedAnimation(
      parent: _controller,
      curve: Curves.elasticInOut,
    );
  }
  @override
  void dispose() {
    _controller.dispose();
    super.dispose();
  }
  @override
  Widget build(BuildContext context) {
    return Center(
      child: DefaultTextStyleTransition(
        style: _styleTween.animate(_curvedAnimation),
        child: CustomText(widget.text),
      ),
    );
  }
}

我在这里使用了 repeat() 。这意味着它将连续运行。您可以在要显示给用户的文本、按钮、卡片 widget 中显示这一点。也许是竞选宣言。我把你留给你的想象力,所有你要做的就是复制动画相关的代码,并发挥他们:)

代码

github.com/bedirhanssa…

以上就是Flutter在项目中使用动画不使用包实现详解的详细内容,更多关于Flutter项目动画使用的资料请关注我们其它相关文章!

(0)

相关推荐

  • Flutter 阻止系统键盘弹出的优雅方式

    目录 前言 系统键盘弹出的原因 拦截系统键盘弹出信息 画自己的键盘 结语 前言 开篇先吐槽一下,输入框和文本,一直都是官方每个版本改动的重点,先不说功能上全不全的问题,每次版本升级,必有 breaking change .对于 extended_text_field | Flutter Package (flutter-io.cn) 和 extended_text | Flutter Package (flutter-io.cn) 来说,新功能都是基于官方的代码,每次版本升级,merge 代码就

  • flutter Bloc 实现原理示例解析

    目录 序言 1. 事件流 > 状态流 (中转) 2. 使用 BlocBuilder 实时监听状态变更, 如何实现的呢? 总结 扩展 序言 在flutter开发中,我们使用 bloc 框架,基于状态变更进行响应式开发.本篇文章,小轰将 bloc 核心业务块进行拆解简化,聊一聊它的实现思想,bloc 核心能力分为如下两点: 添加事件 event,将 '事件流' 转换为 '状态流' state 监听 bloc 流,每次 state 状态变更,通知 widget 更新 下面,用自定义Bloc的方式,来给

  • Flutter 移动程序安全性提高的八个建议

    目录 正文 1. Obfuscate code 混淆代码 2. background snapshots 后台快照 3. Stay up-to-date 更新程序 4. Flushing in-memory cache 刷新内存缓存 5. local authentication 本地认证 6. Secure Storage 安全储存 7. Restrict network traffic 限制网络流量 8. jail-breaking protection 越狱保护 正文 这里有一些步骤,我们

  • 封装flutter状态管理工具示例详解

    目录 引言 RxBinder 代码实现 Demo 完美运行 引言 关于 Flutter 状态管理,公司项目使用的是Bloc方案.Bloc 其实本质上是 provider 的封装扩展库,整体通过 InheritedWidget .Notifier 外加 Stream中转实现状态变更通知. 关于 Bloc 实现原理,有兴趣的同学可以观看这篇文章 Bloc原理解析 RxBinder 撇开Bloc内部实现策略,小轰尝试基于数据驱动模型,自定义一套状态管理工具.构思如下: 主要成员如下: RxBinder

  • flutter Bloc add两次只响应一次问题解析

    目录 问题描述 原因分析 处理方式 问题描述 连续调用两次addEvent,结果最终只能响应一次,第二次事件无法响应. @override Stream<SomeState> mapEventToState(SomeEvent event) async*{ if(event is InCreaseEvent){ state.num ++; yield state; } } someBloc.add(InCreaseEvent()); someBloc.add(InCreaseEvent());

  • Flutter runApp到渲染上屏分析详解

    目录 起源 分析准备 ensureInitialized scheduleAttachRootWidget scheduleWarmUpFrame 总结 起源 flutter作为一个跨平台的框架,在绘制上体现出了它跨平台的良好性能.那么,它是如何从runApp()后 绘制上屏的呢?本文将与你一起去探索这一过程. ps: 为了思维不中断, 本文仅对整体流程作分析,不会深入分析具体实现 我们运行一个flutter app ,入口一定是从runApp() 中进行的. 那么flutter 在runApp

  • Flutter在项目中使用动画不使用包实现详解

    目录 前言 正文 1 按下按钮柔软的感觉 2 想要一个像 Instagram 一样的喜欢按钮吗? 3 动画页面过渡 4 动画文字 5 更改/闪动文本样式 前言 动画对于 web 和移动应用程序都非常重要.但是在移动应用程序中不应该使用夸张的动画.简单但是很多动画使你的应用程序更好用.以至于当你点击一个按钮时,一种平滑的感觉或者页面过渡都会影响到你. 正文 1 按下按钮柔软的感觉 class _CustomButtonState extends State<CustomButton> with

  • webpack项目中使用vite加速的兼容模式详解

    目录 前言 目的 要处理的问题 动手 共用 index.html 共用配置 兼容环境变量 自动导入 资源引入 svg-sprite-loader 替代方案 其他 效果 前言 随着公司前端工程越来越大,启动是无尽的等待,修改是焦急的等待. vite 到现在生态也起来了,就有了把项目改造成 vite 的想法,但是项目后面可能要依赖 qiankun 改造成微前端项目,现在 qiankun 对 vite 还没有好的解决方法,我就想采取一个折中的办法,保留 webpack,再兼容 vite,两条路都留着.

  • Java实现读取项目中文件(.json或.properties)的方法详解

    目录 1. 读取json file 1.1 Json dependency 1.2 字节流 1.3 buffer reader 2. 读取properties file 3. 好看的css样式 1. 读取json file 1.1 Json dependency <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>

  • vue项目中v-model父子组件通信的实现详解

    前言 我们在vue项目中,经常有这样的需求,父组件绑定v-model,子组件输入更改父组件v-model绑定的数值.很多朋友对这种操作不是很清楚,这需要对v-model有比较深入的了解,今天谈谈v-model. vue的双向数据绑定 v-model这个指令只能用在<input>, <select>,<textarea>这些表单元素上,所谓双向绑定,指的就是我们在js中的vue实例中的data与其渲染的dom元素上的内容保持一致,两者无论谁被改变,另一方也会相应的更新为相

  • .Net项目中NLog的配置和使用实例详解

    引言: 因为之前在项目开发中一直都是使用的Log4Net作为项目的日志记录框架,最近忽然感觉对它已经有点腻了,所以尝试着使用了NLog作为新项目的日志记录框架(当然作为一名有志向的攻城狮永远都不能只局限于眼前的技术,要不断的使用和学习新的技术).当然serilog也是一个不错的日志记录框架哟,不过今天主要还是要讲述的是NLog在项目中的配置和使用. NLog框架源码:https://github.com/NLog/NLog 一.导入NLog NuGet PackAge: 二.配置NLog 配置文

  • Vue项目中打包优化的四种方法详解

    目录 前言 打包优化的目的: 性能优化的主要方向: 1.异步组件配置(路由懒加载) 2.去掉打包后的 console 3.使用CDN 4.yarn build生成dist目录 总结 前言 默认情况下,通过import语法导入的第三方依赖包,最终会全部打包到一个js文件中,会导致单文件体积过大大,在网速底下时会阻塞网页加载,影响用户体验. 打包优化的目的: 1.项目启动速度,和性能 2.必要的清理数据 3.减少打包后的体积 第一点是核心,第二点呢其实主要是清理console 性能优化的主要方向:

  • Vue2项目中对百度地图的封装使用详解

    目录 需求 知识点 实现 打点控件封装 代码总览 代码 总结 百度地图的使用: vue项目,有个 vue-baidu-map 可以用,但是好久不更新了. React项目,百度官方出了个React版的,可以直接用,React-BMapGL. 除此以外,百度官方的都是 JavaScript API,这里以此来用vue封装下,方便使用. 需求 组件按需引入.个人喜欢代码干干净净,只要项目需要的功能就行了 简单的封装下,方便直接按官方文档使用需要的功能,方便复用 基于Vue2 .JavaScript A

  • TS 项目中高效处理接口返回数据方法详解

    目录 写在前面 问题 解答 区别 总结 必备高效神器 写在前面 在 TypeScript 项目中,TypeScript 对接口返回数据的处理,是日常项目开发中一个比较棘手的问题. 那我们该如何 高效 的解决这个问题呢? 问题 项目中使用 ts 都会碰到如下场景:从接口请求过来的数据该如何进行处理? const fetchInfo = async (url: string, id: string) => { return $http.get(url, params); } const res =

  • Vue项目中如何使用Axios封装http请求详解

    前言 使用axios可以统一做请求响应拦截,例如请求响应时我们拦截响应信息,判断状态码,从而弹出报错信息.请求超时的时候断开请求,还可以很方便地使用then或者catch来处理请求. 下载源码 安装 npm install axios --save 建立http.js文件 在/src/utils/目录下建立一个htttp.js 1.首先导入axios和router. import axios from 'axios'; import router from '../router'; 2.接着设置

  • Lua中的模块(module)和包(package)详解

    前言 从Lua5.1版本开始,就对模块和包添加了新的支持,可是使用require和module来定义和使用模块和包.require用于使用模块,module用于创建模块.简单的说,一个模块就是一个程序库,可以通过require来加载.然后便得到了一个全局变量,表示一个table.这个table就像是一个命名空间,其内容就是模块中导出的所有东西,比如函数和常量,一个符合规范的模块还应使require返回这个table.现在就来具体的总结一下require和module这两个函数. require函

随机推荐