英雄动画在 Flutter 中不起作用
Posted
技术标签:
【中文标题】英雄动画在 Flutter 中不起作用【英文标题】:Hero Animation Not Working in Flutter 【发布时间】:2018-11-01 18:31:22 【问题描述】:所以,我正在尝试为一家餐厅制作送货上门应用程序,但我似乎无法让我的英雄动画正常工作。首先,我制作了一个启动屏幕,其中显示了徽标,然后导航到徽标应该进行英雄转换的主页。初始屏幕和主页位于两个单独的 dart 文件中。这是我的初始屏幕的代码:
import 'package:flutter/material.dart';
import 'home_page.dart';
import 'dart:async';
class Splash extends StatefulWidget
@override
_SplashState createState() => new _SplashState();
class _SplashState extends State<Splash> with SingleTickerProviderStateMixin
Animation<double> _mainLogoAnimation;
AnimationController _mainLogoAnimationController;
@override
void initState()
super.initState();
goToHomePage();
_mainLogoAnimationController = new AnimationController(duration: new Duration(milliseconds: 2500) ,vsync: this);
_mainLogoAnimation = new CurvedAnimation(parent:
_mainLogoAnimationController, curve: Curves.easeIn);
_mainLogoAnimation.addListener(() => (this.setState(() )));
_mainLogoAnimationController.forward();
Future goToHomePage() async
await new Future.delayed(const Duration(milliseconds: 4000));
Navigator.of(context).push(new MaterialPageRoute(builder: (BuildContext context) => new HomePage()));
@override
Widget build(BuildContext context)
return new Material(
color: Colors.black,
child: new Center(
child: new Opacity(
opacity: 1.0 * _mainLogoAnimation.value,
child: new Hero(
tag: 'tbh_logo',
child: new Image(
image: new AssetImage('assets/images/tbh_main_logo.png'),
width: 300.0
)
)
)
)
);
这是主页的代码:
import 'package:flutter/material.dart';
import '../ui/drawer.dart';
import 'splash.dart';
class HomePage extends StatefulWidget
@override
_HomePageState createState() => new _HomePageState();
class _HomePageState extends State<HomePage>
@override
Widget build(BuildContext context)
return new Scaffold(
appBar: new AppBar(
title: new Text("The Barni House"),
backgroundColor: Colors.black,
),
drawer: new Drawer(child: MyDrawer()),
body: new Center(
child: Column(
children: <Widget>[
new Container(
child: new Hero(
tag: 'tbh_logo',
child: new Image(
image: new AssetImage('assets/images/tbh_main_logo.png'),
width: 300.0
)
)
)
],
)
),
);
【问题讨论】:
【参考方案1】:Hero 动画在 Flutter 中很容易实现。您只需在登录页面中导入包 package:flutter/scheduler.dart。见下面代码
import 'package:flutter/scheduler.dart' show timeDilation;
记得添加 timeDilation 变量并为其分配一个值,以秒为单位加速或减慢动画。在您的构建方法之后添加这些,如下例所示
Widget build(BuildContext context)
timeDilation = 2;
为了更好的动画,只需使用自定义动画
【讨论】:
【参考方案2】:检查了您的代码,因此英雄动画正在运行,但由于过渡持续时间仅为 300 毫秒,因此它发生得很快。
要实现以下结果,您可以制作 Custom MaterialPageRoute。
之前
@override
Duration get transitionDuration => const Duration(milliseconds: 300);
之后
@override
Duration get transitionDuration => const Duration(milliseconds: 1000);
此外,您还可以使用 CurvedAnimation
new CurvedAnimation(
parent: routeAnimation,
curve: Curves.elasticIn,
)
CustomRoute.dart
import 'package:flutter/cupertino.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter/widgets.dart';
final Tween<Offset> _kBottomUpTween = new Tween<Offset>(
begin: const Offset(0.0, 1.0),
end: Offset.zero,
);
// Offset from offscreen to the right to fully on screen.
final Tween<Offset> _kRightMiddleTween = new Tween<Offset>(
begin: const Offset(1.0, 0.0),
end: Offset.zero,
);
// Offset from offscreen below to fully on screen.
class AppPageRoute extends MaterialPageRoute<String>
@override
final bool maintainState;
@override
final WidgetBuilder builder;
CupertinoPageRoute<String> _internalCupertinoPageRoute;
AppPageRoute(
@required this.builder,
RouteSettings settings: const RouteSettings(),
this.maintainState: true,
bool fullscreenDialog: false,
) : assert(builder != null),
assert(settings != null),
assert(maintainState != null),
assert(fullscreenDialog != null),
super(
settings: settings,
fullscreenDialog: fullscreenDialog,
builder: builder,
)
assert(opaque); // PageRoute makes it return true.
@override
Color get barrierColor => null;
@override
Duration get transitionDuration => const Duration(milliseconds: 1000);
CupertinoPageRoute<String> get _cupertinoPageRoute
assert(_useCupertinoTransitions);
_internalCupertinoPageRoute ??= new CupertinoPageRoute<String>(
builder: builder,
fullscreenDialog: fullscreenDialog,
hostRoute: this,
);
return _internalCupertinoPageRoute;
bool get _useCupertinoTransitions
return _internalCupertinoPageRoute?.popGestureInProgress == true ||
Theme.of(navigator.context).platform == TargetPlatform.ios;
@override
Widget buildPage(BuildContext context, Animation<double> animation, Animation<double> secondaryAnimation)
final Widget result = builder(context);
assert(()
if (result == null)
throw new FlutterError('The builder for route "$settings.name" returned null.\n'
'Route builders must never return null.');
return true;
());
return result;
@override
Widget buildTransitions(
BuildContext context, Animation<double> animation, Animation<double> secondaryAnimation, Widget child)
if (_useCupertinoTransitions)
return _cupertinoPageRoute.buildTransitions(context, animation, secondaryAnimation, child);
return new _CustomPageTransition(routeAnimation: animation, child: child, fullscreenDialog: fullscreenDialog);
class _CustomPageTransition extends StatelessWidget
final Animation<Offset> _positionAnimation;
final Widget child;
final bool fullscreenDialog;
_CustomPageTransition(
Key key,
@required Animation<double> routeAnimation,
@required this.child,
@required this.fullscreenDialog,
) : _positionAnimation = !fullscreenDialog
? _kRightMiddleTween.animate(new CurvedAnimation(
parent: routeAnimation,
curve: Curves.elasticIn,
))
: _kBottomUpTween.animate(new CurvedAnimation(
parent: routeAnimation, // The route's linear 0.0 - 1.0 animation.
curve: Curves.elasticIn,
)),
super(key: key);
@override
Widget build(BuildContext context)
return new SlideTransition(
position: _positionAnimation,
child: child,
);
推新路线
Future goToHomePage() async
await new Future.delayed(const Duration(milliseconds: 4000));
Navigator.of(context).push(new AppPageRoute(builder: (BuildContext context) => new HomePage()));
您可以将自定义 MaterialPageRoute 用于启动屏幕和其他路由 MaterialPageRoute。
希望对你有帮助
【讨论】:
谢谢!从未真正考虑过制作自定义页面路由。 这对我帮助很大! :)【参考方案3】:// main.dart class
import 'package:flutter/material.dart';
import 'package:flutter/scheduler.dart' show timeDilation;
import 'package:flutter_test7/photo_hero.dart';
import 'package:flutter_test7/second_page.dart';
class HeroAnimation extends StatelessWidget
Widget build(BuildContext context)
timeDilation = 2.5; // 1.0 means normal animation speed.
return new Scaffold(
appBar: new AppBar(
title: const Text('Basic Hero Animation'),
),
body: new Center(
child: new PhotoHero(
photo: 'images/flippers-alpha.png',
width: 300.0,
onTap: ()
Navigator.of(context).pushNamed('/second_page');
,
),
),
);
void main()
runApp(
new MaterialApp(
home: new HeroAnimation(),
routes: <String, WidgetBuilder>
'/second_page': (context) => new SecondPage()
,
),
);
// photo_hero.dart class
import 'package:flutter/material.dart';
class PhotoHero extends StatelessWidget
const PhotoHero(Key key, this.photo, this.onTap, this.width)
: super(key: key);
final String photo;
final VoidCallback onTap;
final double width;
Widget build(BuildContext context)
return new SizedBox(
width: width,
child: new Hero(
tag: photo,
child: new Material(
color: Colors.transparent,
child: new InkWell(
onTap: onTap,
child: new Image.asset(
photo,
fit: BoxFit.contain,
),
),
),
),
);
// second_page.dart class
import 'package:flutter/material.dart';
import 'package:flutter_test7/photo_hero.dart';
class SecondPage extends StatefulWidget
@override
_SecondPageState createState() => new _SecondPageState();
class _SecondPageState extends State<SecondPage>
@override
Widget build(BuildContext context)
return new Scaffold(
appBar: new AppBar(
title: const Text('Flippers Page'),
),
body: new Container(
color: Colors.lightBlueAccent,
padding: const EdgeInsets.all(16.0),
alignment: Alignment.topLeft,
child: new PhotoHero(
photo: 'images/flippers-alpha.png',
width: 100.0,
onTap: ()
Navigator.of(context).pop();
,
),
),
);
希望这会有所帮助。
【讨论】:
时间膨胀是一个不错且简单的想法。酷:) 英雄在使用Navigator.push(context, MaterialPageRoute(builder: (context) => SeondPage()));
时有效,但在使用PageRouteBuilder
时无效以上是关于英雄动画在 Flutter 中不起作用的主要内容,如果未能解决你的问题,请参考以下文章