简介

flutter中有默认的Route组件,叫做MaterialPageRoute,一般情况下我们在flutter中进行跳转的话,只需要向Navigator中传入一个MaterialPageRoute就可以了。

但是MaterialPageRoute太普通了,如果我们想要做点不同的跳转特效应该如何处理呢?

一起来看看吧。

自定义跳转使用

正常情况下,我们进行路由跳转需要用到Navigator和MaterialPageRoute,如下所示:

 Navigator.push(context, MaterialPageRoute(builder: (context) {
return const NextPage();

如果要实现特定的路由动画,那么需要进行路由的自定义。

在flutter中也就是要使用PageRouteBuilder来自定义一个Route。

先来看下PageRouteBuilder的定义:

class PageRouteBuilder<T> extends PageRoute<T> {

  PageRouteBuilder({
super.settings,
required this.pageBuilder,
this.transitionsBuilder = _defaultTransitionsBuilder,
this.transitionDuration = const Duration(milliseconds: 300),
this.reverseTransitionDuration = const Duration(milliseconds: 300),
this.opaque = true,
this.barrierDismissible = false,
this.barrierColor,
this.barrierLabel,
this.maintainState = true,
super.fullscreenDialog,
})

PageRouteBuilder也是PageRoute的一种,在构建PageRouteBuilder的时候,通过控制不同的属性值,我们可以自由控制pageBuilder,transitionsBuilder,transitionDuration,reverseTransitionDuration等特性。

可以看到自由程度还是非常高的。

其中pageBuilder是路由将会跳转的页面,这个是必须要指定的,要不然路由也就没有意义了。

另外路由转换的效果可以经由transitionsBuilder来设置。

这里的RouteTransitionsBuilder是一个Function,返回一个Widget:

typedef RouteTransitionsBuilder = Widget Function(BuildContext context, Animation<double> animation, Animation<double> secondaryAnimation, Widget child);

所以理论上,我们可以返回任何widget,但是一般来说,我们会返回一个AnimatedWidget,表示一个动画效果。

flutter动画基础

flutter中有个专门的动画包叫做flutter/animation.dart, flutter中所有动画的核心叫做Animation。

Animation中定义了很多listener用来监控动画的变动情况,并且还提供了一个AnimationStatus来存储当前的动画状态:

abstract class Animation<T> extends Listenable implements ValueListenable<T> {
const Animation(); AnimationWithParentMixin<T> @override
void addListener(VoidCallback listener); @override
void removeListener(VoidCallback listener); void addStatusListener(AnimationStatusListener listener); void removeStatusListener(AnimationStatusListener listener); AnimationStatus get status;

AnimationStatus是一个枚举类,它包含了现在动画的各种状态:

enum AnimationStatus {
dismissed, forward, reverse, completed,
}

dismissed表示动画暂停在开头。

forward表示动画在从头到尾播放。

reverse表示动画在从尾到头播放。

completed表示动画播放完毕,停在了结尾。

有了动画的表示之后,如何对动画进行控制呢?这里就需要用到AnimationController了。

AnimationController可以控制动画的duration,动画的最低值lowerBound默认是0.0,动画的最高值upperBound默认是1.0等等。

默认情况AnimationController中从最低值到最高值是线性变化的,如果你想设置不同的Bound值,那么可以尝试自定义 Animatable, 如果你想动画的变动是非线性的,那么可以尝试继承Animation来实现自己的变动曲线。

实现一个自定义的route

这里我们使用flutter中的SlideTransition,SlideTransition是一个AnimatedWidget,它表示的是一个组件的位置变化的动画。

class SlideTransition extends AnimatedWidget {
const SlideTransition({
super.key,
required Animation<Offset> position,
this.transformHitTests = true,
this.textDirection,
this.child,
}) : assert(position != null),
super(listenable: position);

看下它的构造函数,可以看到SlideTransition需要一个position的属性,这个position是一个Animation对象,里面包含的是Offset。

同时这个position是一个listenable对象,通过监听里面Offset的变化,从而重新build对应的widget从而实现动画的效果。

Offset是一个表示位置的类,(0,0) 表示这个widget的左顶点在屏幕的左上角,同样的(1,1)表示这个widget的左顶点在屏幕的右下角。

因为route过后是一个新的页面,我们希望出现一个页面从右下角移动到左上角的动画,那么我们可以这样做:

Route customRoute() {
return PageRouteBuilder(
pageBuilder: (context, animation, secondaryAnimation) => const SecondPage(),
transitionsBuilder: (context, animation, secondaryAnimation, child) {
const begin = Offset(1.0, 1.0);
const end = Offset.zero;
const curve = Curves.easeOut; var tween = Tween(begin: begin, end: end).chain(CurveTween(curve: curve)); return SlideTransition(
position: animation.drive(tween),
child: child,
);
},
);
}

这里的begin和end表示widget从屏幕的右下角移动到了屏幕的左上角。

Tween表示的是开始值和结束值之间的线性插值,是一个动态过程,另外我们还可以这个插值变动的曲线,这里使用了CurveTween,选中了Curves.easeOut这种曲线类型。

最后调用animation.drive方法把Tween和Animation关联起来,这样一个路由动画就完成了。

总结

最后程序运行的结果如下:

其实flutter中的动画很简单,大家记住就是widget位置沿不同的曲线变化即可。

本文的例子:https://github.com/ddean2009/learn-flutter.git

flutter系列之:如何自定义动画路由的更多相关文章

  1. 【Flutter 实战】17篇动画系列文章带你走进自定义动画

    老孟导读:Flutter 动画系列文章分为三部分:基础原理和核心概念.系统动画组件.8篇自定义动画案例,共17篇. 动画核心概念 在开发App的过程中,自定义动画必不可少,Flutter 中想要自定义 ...

  2. 【Flutter 实战】自定义动画-涟漪和雷达扫描

    老孟导读:此篇文章是 Flutter 动画系列文章第五篇,本文介绍2个自定义动画:涟漪和雷达扫描效果. 涟漪 实现涟漪动画效果如下: 此动画通过 CustomPainter 绘制配合 Animatio ...

  3. Android中的动画详解系列【3】——自定义动画研究

    在上一篇中我们使用到了位移动画TranslateAnimation,下面我们先来看看TranslateAnimation是如何实现Animation中的抽象方法的: /* * Copyright (C ...

  4. AngularJS路由系列(2)--刷新、查看路由,路由事件和URL格式,获取路由参数,路由的Resolve

    本系列探寻AngularJS的路由机制,在WebStorm下开发.主要包括: ● 刷新路由● 查看当前路由以及所有路由● 路由触发事件● 获取路由参数 ● 路由的resolve属性● 路由URL格式 ...

  5. Flutter系列博文链接

    Flutter系列博文链接 ↓: Flutter基础篇: Flutter基础篇(1)-- 跨平台开发框架和工具集锦 Flutter基础篇(2)-- 老司机用一篇博客带你快速熟悉Dart语法 Flutt ...

  6. android 自定义动画

    android自定义动画注意是继承Animation,重写里面的initialize和applyTransformation,在initialize方法做一些初始化的工作,在applyTransfor ...

  7. Android开发学习之路-RecyclerView的Item自定义动画及DefaultItemAnimator源码分析

    这是关于RecyclerView的第二篇,说的是如何自定义Item动画,但是请注意,本文不包含动画的具体实现方法,只是告诉大家如何去自定义动画,如何去参考源代码. 我们知道,RecyclerView默 ...

  8. 深入学习jQuery自定义动画

    × 目录 [1]属性对象 [2]可选参数 [3]选项参数 前面的话 很多情况下,前面介绍的jQuery动画的简单效果无法满足用户的各种需求,那么就需要对动画有更多的限制,需要采取一些高级的自定义动画来 ...

  9. 自定义动画css属性

    自定义动画: 1.animation-name(自定义动画名称) 元素所应用的动画名称,必须与@keyframes使用,名称由@keyframes定义. keyframes(动画关键帧):以@keyf ...

  10. [UE4]CustomAnimationBlueprintNode 自定义动画蓝图节点

    目的:在AnimationBlueprint中使用自定义动画控制节点. 主要过程: 1.      引用相关模块.在Client.Build.cs文件中,PublicDependencyModuleN ...

随机推荐

  1. AD使用积累 - 板子上开孔的方法

    有时候画板子时需要需要在板子上开一些槽孔,可以参考如下两种方法: 第一种方法:封闭曲线转换为槽孔. 1.在机械层画一个封闭图形或者画一根线: 2.选中这个图形或线,选择工具 - 转换 - 以选中的元素 ...

  2. vue项目启动报错问题解决. Module build failed: Error: Node Sass does not yet support your current environment

    导入vue项目后,启动报错,异常如下: 1 error in ./src/pages/home.vue 2 Module build failed: Error: Node Sass does not ...

  3. idea修改背景颜色|护眼色|项目栏背景修改

    https://blog.csdn.net/heytyrell/article/details/89743068

  4. jQuery.extend 函数详解(转)

    地址:http://www.jb51.net/article/29591.htm JQuery的extend扩展方法: Jquery的扩展方法extend是我们在写插件的过程中常用的方法,该方法有一些 ...

  5. 关于一维数组传入函数的使用 //西电oj214题字符统计

    #include<stdio.h> void count(char str[],int num[]){//形参用[],传递数组首地址后可以直接正常用数组str[i] int i; for( ...

  6. 使用redis分布式锁重复执行采坑

    事件:生产环境部署两台,每天凌晨1点,定时任务同步更新(先删除,后全部插入)账号表,使用了redis分布式锁,发现定时任务还是执行了两次,导致数据重复,影响对应业务. 原因分析:定时任务执行的逻辑是调 ...

  7. DB2通过java代码生成自定义uuid()函数

    一.简单的方法 此种方法在快速大量生成时,会有重复 SELECT concat (hex (RAND ()), hex (RAND ())) as uuid FROM SYSIBM.SYSDUMMY1 ...

  8. OS基础-四大基本特征

    现代计算机操作系统的四大基本特性(并发/共享/虚拟/异步) 1.并发性 1.1.并发与并行区别 并发是指宏观上在一段时间内能同时运行多个程序,而并行则指同一时刻能运行多个指令.并发需要硬件支持,如多流 ...

  9. [rk3568][buildroot] 移除RK3568 iodomain check

    1. 问题背景 RK3568 基线代码默认会起一个服务监控RK3568 iodomain,该服务间隔性输出log信息: 由于该功能非必要,故选择移除该部分逻辑 2.解决方案 查看源码编译脚本,如下图所 ...

  10. 给c++写python的split()与input()【python一样写c++、一】

    python的split确实是很香的功能. 写c++的时候,就会想着,要是能直接input().split()那不挺好. 实际上真的可以:自己动手,丰衣足食. 先放成品展示. int main(){ ...