英雄动画在Flutter中不起作用 [英] Hero Animation Not Working in Flutter

查看:498
本文介绍了英雄动画在Flutter中不起作用的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

因此,我正试图为一家杂乱无章的餐厅制作送货上门应用,而我的英雄动画似乎无法正常工作。首先,我创建了一个初始屏幕,其中显示徽标,然后导航到该徽标应该进行英雄转换的主页。初始屏幕和主页位于两个独立的dart文件中。这是我的启动屏幕的代码:

  import‘package:flutter / material.dart’; 
导入 home_page.dart;
导入 dart:async;

类Splash扩展了StatefulWidget {
@override
_SplashState createState()=>新的_SplashState();
}

类_SplashState扩展了State< Splash>与SingleTickerProviderStateMixin
{

Animation< double> _mainLogoAnimation;
AnimationController _mainLogoAnimationController;

@override
void initState(){
super.initState();
goToHomePage();
_mainLogoAnimationController =新的AnimationController(持续时间:新的持续时间(毫秒:2500),vsync:此);
_mainLogoAnimation =新的CurvedAnimation(父级:
_mainLogoAnimationController,曲线:Curves.easeIn);
_mainLogoAnimation.addListener(()=>(this.setState((){}))));
_mainLogoAnimationController.forward();
}

Future goToHomePage()async {
等待new Future.delayed(const Duration(milliseconds:4000));
Navigator.of(context).push(new MaterialPageRoute(builder:(BuildContext context)=> new HomePage()));
}

@override
小部件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(
图像:new AssetImage('assets / images / tbh_main_logo.png'),
宽度:300.0




);
}
}

这是主页的代码:

  import'package:flutter / material.dart'; 
import‘../ui/drawer.dart’;
导入 splash.dart;

类HomePage扩展了StatefulWidget {
@override
_HomePageState createState()=>新的_HomePageState();
}

类_HomePageState扩展了State< HomePage> {
@override
Widget build(BuildContext context){
return new Scaffold(
appBar:new AppBar(
title:new Text( The Barni House) ,
backgroundColor:Colors.black,
),
抽屉:new Drawer(child:MyDrawer()),
body:new Center(
child:Column(
个孩子:< Widget> [
个新Container(
个孩子:new Hero(
标签:'tbh_logo',
个孩子:new Image(
图片:new AssetImage('assets / images / tbh_main_logo.png'),
宽度:300.0



],

),
);
}
}


解决方案

已检查您的代码可以使英雄动画正常工作,但是由于过渡持续时间仅为300毫秒,因此动画发生得很快。



要获得以下结果,您可以使自定义MaterialPageRoute



之前

  @override 
持续时间获得transitionDuration => const持续时间(毫秒:300);

之后

  @override 
持续时间获得transitionDuration => const持续时间(毫秒:1000);

此外,您还可以玩 CurvedAnimation

  new CurvedAnimation(
父级:routeAnimation,
曲线:Curves.elasticIn,



CustomRoute .dart

  import'package:flutter / cupertino.dart'; 
导入的 package:flutter / foundation.dart;
导入的 package:flutter / gestures.dart;
导入的 package:flutter / material.dart;
导入的 package:flutter / rendering.dart;
导入的 package:flutter / widgets.dart;

最终的Tween< Offset> _kBottomUpTween =新的Tween< Offset>(
开始:const Offset(0.0,1.0),
结束:Offset.zero,
);

//从屏幕外向右偏移到完全显示在屏幕上。
最终Tween< Offset> _kRightMiddleTween =新的Tween< Offset>(
开始:const Offset(1.0,0.0),
结束:Offset.zero,
);

//从下面的屏幕外偏移到完全显示在屏幕上。
类AppPageRoute扩展了MaterialPageRoute< String> {
@override
final boolmaintainState;

@override
最终的WidgetBuilder构建器;
CupertinoPageRoute< String> _internalCupertinoPageRoute;

AppPageRoute({
@必需this.builder,
RouteSettings设置:const RouteSettings(),
this.maintainState:true,
bool fullscreenDialog: false,
}):assert(builder!= null),
assert(settings!= null),
assert(maintainState!= null),
assert(fullscreenDialog!= null),
super(
settings:设置,
fullscreenDialog:fullscreenDialog,
builder:builder,
){
assert(opaque); // PageRoute使它返回true。
}

@override
Color get barrierColor =>空值;

@override
持续时间获得transitionDuration => const持续时间(毫秒:1000);

CupertinoPageRoute< String>获取_cupertinoPageRoute {
assert(_useCupertinoTransitions);
_internalCupertinoPageRoute ?? =新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
窗口小部件buildPage(BuildContext context,Animation< double>动画,Animation< double> secondaryAnimation){
最终窗口小部件结果= builder(context) ;
assert((){
if(result == null){
throw new FlutterError('路线 $ {settings.name}的生成器返回null。\n'
'路由生成器绝对不能返回null。');
}
返回true;
}());
返回结果;
}

@override
小部件buildTransitions(
BuildContext上下文,Animation< double>动画,Animation< double> secondaryAnimation,Widget小部件){
如果(_useCupertinoTransitions){
return _cupertinoPageRoute.buildTransitions(context,animation,secondaryAnimation,child);
}

返回新的_CustomPageTransition(routeAnimation:动画,child:child,fullscreenDialog:fullscreenDialog);
}
}

类_CustomPageTransition扩展了StatelessWidget {
final Animation< Offset> _positionAnimation;

个最终Widget子对象;
final bool fullscreenDialog;

_CustomPageTransition({
Key key,
@required Animation< double> routeAnimation,
@required this.child,
@ required.fullscreenDialog,
}):_positionAnimation =!fullscreenDialog
吗? _kRightMiddleTween.animate(new CurvedAnimation(
父代:routeAnimation,
曲线:Curves.elasticIn,
))
:_kBottomUpTween.animate(new CurvedAnimation(
父代:routeAnimation ,//路径的线性0.0-1.0动画。
curve:Curves.elasticIn,
)),
super(key:key);

@override
小部件构建(BuildContext上下文){
返回新的SlideTransition(
位置:_positionAnimation,
子代:child,
) ;
}
}

推新路线

  Future goToHomePage()async {
等待new Future.delayed(const Duration(milliseconds:4000));
Navigator.of(context).push(new AppPageRoute(builder:(BuildContext context)=> new HomePage()));
}

您可以将自定义MaterialPageRoute用于初始屏幕和其他路线 MaterialPageRoute。 / p>

希望有帮助


So, I'm trying to make a home delivery app for a restaurant in flutter and I can't seem to get my hero animation working. First I made a splash screen where the logo shows up and then it navigates to home page where the logo is supposed to do a hero transition. The splash screen and the home page are in two separate dart files. Here's the code for my splash screen:

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

And here's the code for the home page:

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

解决方案

Checked your code so the hero animation is working but its happening to fast because of the transition duration is only 300 milliseconds.

To achieve the below result you can make a Custom MaterialPageRoute.

Before

@override
  Duration get transitionDuration => const Duration(milliseconds: 300);

After

@override
  Duration get transitionDuration => const Duration(milliseconds: 1000);

Also, you can play with the 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,
    );
  }
}

Push new Route

 Future goToHomePage() async {
    await new Future.delayed(const Duration(milliseconds: 4000));
    Navigator.of(context).push(new AppPageRoute(builder: (BuildContext context) => new HomePage()));
  }

You can use Custom MaterialPageRoute for the splash screen and for other routes MaterialPageRoute.

Hope it helps

这篇关于英雄动画在Flutter中不起作用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆