如何正确使用 SlideTransition?

How to use SlideTransition properly?

我正在尝试从屏幕的 center 到屏幕的 top 动画图像(或徽标)。

为此,我查看了 SlideTransition。它有效,但仅适用于纵向。旋转设备时,图像会超出屏幕范围。 (也许我没有正确理解 Offset 属性!)如果我让它在水平方向上工作,肖像的输出就会改变。

让我向您展示输出:

纵向:

动画前

动画后(随心所欲)

水平:

动画前

动画后 (这里有问题)

因此,如您所见,在水平模式下,徽标会超出屏幕范围。

代码如下:

import 'package:flutter/material.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'SlideTransition Demo',
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> with SingleTickerProviderStateMixin {
  AnimationController _controller;
  Animation<Offset> _offsetAnimation;

  @override
  void initState() {
    _controller = AnimationController(vsync: this, duration: Duration(milliseconds: 300));

    _offsetAnimation = _controller
        .drive(CurveTween(curve: Curves.easeInOut))
        .drive(Tween<Offset>(begin: Offset(0.0, 0.0), end: Offset(0.0, -1.0)));

    super.initState();
  }

  @override
  void dispose() {
    _controller?.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('SlideTransition Demo'),
      ),
      body: Stack(
        children: <Widget>[
          Align(
            alignment: Alignment.center,
            child: SlideTransition(
              position: _offsetAnimation,
              child: FlutterLogo(
                size: 200,
              ),
            ),
          ),
        ],
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          if (_controller.status == AnimationStatus.completed) {
            _controller.reverse();
          } else if (_controller.status == AnimationStatus.dismissed) {
            _controller.forward();
          }
        },
        child: Icon(Icons.play_arrow),
      ),
    );
  }
}

您可以复制粘贴 运行 下面的完整代码
您可以使用 OrientationBuilder 并将 Offset 修改为您需要的

代码片段

body: OrientationBuilder(
        builder: (context, orientation) {
          if (orientation == Orientation.portrait) {
            _offsetAnimation = _controller
                .drive(CurveTween(curve: Curves.easeInOut))
                .drive(Tween<Offset>(
                    begin: Offset(0.0, 0.0), end: Offset(0.0, -1.0)));
          } else {
            _offsetAnimation = _controller
                .drive(CurveTween(curve: Curves.easeInOut))
                .drive(Tween<Offset>(
                    begin: Offset(0.0, 0.0), end: Offset(-1.0, 0.0)));
          }

工作演示

完整代码

import 'package:flutter/material.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'SlideTransition Demo',
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage>
    with SingleTickerProviderStateMixin {
  AnimationController _controller;
  Animation<Offset> _offsetAnimation;
  Animation<Offset> _offsetAnimationLandscape;

  @override
  void initState() {
    _controller =
        AnimationController(vsync: this, duration: Duration(milliseconds: 300));

    super.initState();
  }

  @override
  void dispose() {
    _controller?.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('SlideTransition Demo'),
      ),
      body: OrientationBuilder(
        builder: (context, orientation) {
          if (orientation == Orientation.portrait) {
            _offsetAnimation = _controller
                .drive(CurveTween(curve: Curves.easeInOut))
                .drive(Tween<Offset>(
                    begin: Offset(0.0, 0.0), end: Offset(0.0, -1.0)));
          } else {
            _offsetAnimation = _controller
                .drive(CurveTween(curve: Curves.easeInOut))
                .drive(Tween<Offset>(
                    begin: Offset(0.0, 0.0), end: Offset(-1.0, 0.0)));
          }
          return Stack(
            children: <Widget>[
              Align(
                alignment: Alignment.center,
                child: SlideTransition(
                  position: _offsetAnimation,
                  child: FlutterLogo(
                    size: 200,
                  ),
                ),
              ),
            ],
          );
        },
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          if (_controller.status == AnimationStatus.completed) {
            _controller.reverse();
          } else if (_controller.status == AnimationStatus.dismissed) {
            _controller.forward();
          }
        },
        child: Icon(Icons.play_arrow),
      ),
    );
  }
}

SlideTransition 进行分数翻译。并且此翻译取决于 SlideTransition 小部件的子项的大小。

Tween(begin: Offset(0.0, 0.0), end: Offset(0.0, -1.0))

此补间在 y 轴上平移(移动)FlutterLogo 200(FlutterLogo 小部件的高度)

Tween(begin: Offset(0.0, 0.0), end: Offset(0.0, -0.5))

此补间在 y 轴上平移(移动)FlutterLogo 100(FlutterLogo 小部件的半高)

如果您只想将图像从 center 动画化到 topCenter,那么您可以使用 AlignTransition.

示例

class FirstPage extends StatefulWidget {
  @override
  FirstPageState createState() => FirstPageState();
}

class FirstPageState extends State<FirstPage> with TickerProviderStateMixin {
  AnimationController _animationController;
  AlignmentGeometryTween _tween;

  @override
  void initState() {
    super.initState();
    _animationController = AnimationController(
      vsync: this,
      duration: Duration(seconds: 3),
    );
    _tween = AlignmentGeometryTween(
      begin: Alignment.center,
      end: Alignment.topCenter,
    );
  }

  TickerFuture _play() {
    _animationController.reset();
    return _animationController.animateTo(
      1.0,
      curve: Curves.easeInOut,
    );
  }

  @override
  void dispose() {
    _animationController.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      home: Scaffold(
        appBar: AppBar(title: Text("Demo")),
        body: AlignTransition(
          alignment: _tween.animate(_animationController),
          child: FlutterLogo(
            size: 200,
          ),
        ),
        floatingActionButton: FloatingActionButton(
          child: Icon(Icons.play_arrow),
          onPressed: _play,
        ),
      ),
    );
  }
}

演示: DartPad