且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

英雄动画在Flutter中不起作用

更新时间:2023-01-08 15:42:19

已检查您的代码可以使英雄动画正常工作,但是由于过渡持续时间仅为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