在Flutter中创建滚动动画

作者: 开心人开发世界 | 来源:发表于2019-07-09 18:20 被阅读44次

使用Flutter从头开始构建平滑的滚动动画

介绍

在本文中,我们将介绍如何使用Flutter SDK从头开始创建自定义滚动动画。Flutter是一个功能强大的工具,用于创建运行良好的本机移动应用程序,并且在创建丰富的用户体验(如动画)方面具有极大的灵活性。

如果您没有Flutter环境,请转到安装页面。此处提供了本文中示例项目的源代码。


入门

对于本演示,我创建了一个默认的Flutter项目,使用flutter create并仅使用Flutter中直接可用的类,没有向项目添加依赖项。在许多情况下,可以直接完成任务(例如自定义动画),而无需额外的库。

这个示例应用程序的基本思想是创建一个包含几个项的简单列表视图,并且当视图向上或向下滚动时,在后台顺时针/逆时针旋转齿轮。我们将通过使用用于列表视图的滚动控制器并将其传递到动画背景来实现此目的,该动画背景构建与滚动位置同步旋转的自定义窗口小部件。


应用入口点

我们将从主应用程序文件lib/main.dart开始:

import 'package:flutter/material.dart';
import 'demo-card.dart';
import 'items.dart';
import 'animated-bg.dart';

void main() => runApp(AnimationDemo());

class AnimationDemo extends StatelessWidget {

    @override
    Widget build(BuildContext context) {

        return MaterialApp(
            title: 'Flutter Demo',
            theme: ThemeData(primarySwatch: Colors.deepPurple),
            home: MyHomePage(title: 'Flutter Animation Demo'),
        );
    }
}

class MyHomePage extends StatefulWidget {

    MyHomePage({Key key, this.title}) : super(key: key);
    final String title;

    @override
    _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {

    ScrollController _controller = new ScrollController();

    List<DemoCard> get _cards =>
        items.map((Item _item) => DemoCard(_item)).toList();

    @override
    Widget build(BuildContext context) {

        return Scaffold(

            backgroundColor: Colors.black,
            appBar: AppBar(title: Text(widget.title)),
            body: Stack(

                alignment: AlignmentDirectional.topStart,
                children: <Widget>[

                    AnimatedBackground(controller: _controller),
                    Center(
                        child: ListView(
                            controller: _controller,
                            children: _cards
                        )
                    )
                ]
            )
        );
    }
}

main.dart文件中,有以下组件的导入:

  • demo-card.dart (从Item构建Card小部件)
  • items.dart(为演示应用程序定义Item类和模拟内容)
  • animated-bg.dart(构建动画背景小部件)

主app类(AnimationDemo)设置一个包装默认主页小部件(MyHomePage)的基本应用程序。在MyHomePage类中有一个_controller属性,它被初始化为ScrollController类的一个新实例,以便稍后传递给AnimatedBackground(它在后台驱动齿轮旋转动画)和ListView(它呈现滚动列表演示项目)。还有一个_cards属性,它以items.dart中导入的Item对象列表开头,并返回DemoCard列表 要在ListView中呈现的小部件。


物品类

我们检查的第一个导入文件是lib/items.dart

import 'package:flutter/material.dart';

class Item {

    String name;
    String description;
    MaterialColor color;
    IconData icon;
    Item(this.name, this.description, this.color, this.icon);
}

List<Item> items = [
    Item('A', "Something cool", Colors.amber, Icons.ac_unit),
    Item('B', "Hey, why not?", Colors.cyan, Icons.add_photo_alternate),
    Item('C', "This might be OK", Colors.indigo, Icons.airplay),
    Item('D', "Totally awesome", Colors.green, Icons.crop),
    Item('E', "Rockin out", Colors.pink, Icons.album),
    Item('F', "Take a look", Colors.blue, Icons.adb)
];

Item类提供了将沿着要的实例被传递的数据结构DemoCard在要被渲染的ListView。除了名称,描述(在演示中当前未使用),颜色和为每个项目呈现的Icon之外,没有太多其他内容。Item对象列表将作为要在ListView中呈现的简单内容的列表。


DemoCard类

下一个要检查的文件是lib/demo-card.dart

import 'package:flutter/material.dart';
import 'items.dart';

class DemoCard extends StatelessWidget {

    DemoCard(this.item);
    final Item item;

    static final Shadow _shadow = Shadow(offset: Offset(2.0, 2.0), color: Colors.black26);
    final TextStyle _style = TextStyle(color: Colors.white70, shadows: [_shadow]); 

    @override
    Widget build(BuildContext context) {

        return Card(
                
            elevation: 3,
            shape: RoundedRectangleBorder(
                side: BorderSide(width: 1, color: Colors.black26),
                borderRadius: BorderRadius.circular(32)
            ),
            color: item.color.withOpacity(.7),
            child: Container(

                constraints: BoxConstraints.expand(height: 256),
                child: RawMaterialButton(

                    onPressed: () {  },
                    child: Column(
                        
                        mainAxisAlignment: MainAxisAlignment.spaceAround,
                        crossAxisAlignment: CrossAxisAlignment.stretch,
                        children: <Widget>[
                            Row(
                                mainAxisAlignment: MainAxisAlignment.spaceAround,
                                children: <Widget>[

                                    Text(item.name, style: _style.copyWith(fontSize: 64)),
                                    Icon(item.icon, color: Colors.white70, size: 72),
                                ]
                            )
                        ],
                    ),
                )
            )
        );
    }
}

DemoCard类接收一个Item在其构造并返回一个卡片式Widget呈现TextIcon时显示的元素名称图标对每个项目定义。使用ShadowTextStyleRoundedRectangleBorder以及卡片的高程(设置为3)应用一些基本样式。Column Row小部件用于跨卡片中的子元素。


AnimatedBackground类

保存最后的最好,让我们看看lib/animated-bg.dart

import 'package:flutter/material.dart';
import 'dart:math' as math;

class AnimatedBackground extends StatefulWidget {

    AnimatedBackground({Key key, this.controller}) : super(key: key);

    final ScrollController controller;

    @override
    _AnimatedBackgroundState createState() => _AnimatedBackgroundState();
}

class _AnimatedBackgroundState extends State<AnimatedBackground> {

    get offset => widget.controller.hasClients ? widget.controller.offset : 0;

    @override
    Widget build(BuildContext context) {
    
        return AnimatedBuilder(

            animation: widget.controller,
            builder: (BuildContext context, Widget child) {

                return  OverflowBox(
                    
                    maxWidth: double.infinity,
                    alignment: Alignment(4, 3),
                    child: Transform.rotate(
                        angle: ((math.pi * offset) / -1024),
                        child: Icon(Icons.settings, size: 512, color: Colors.white)
                    )
                );
            }
        );
    }
}

在文件的顶部,dart:math导入库以获得对π常数的访问,以进行旋转齿轮的旋转变换计算。该AnimatedBackground类构造函数将ScrollController将驱动旋转。如果控制器具有客户端(即控制器已正确初始化并连接到像ListView这样的实际滚动元素)_offset属性将返回控制器偏移量,否则它将返回零。该构建方法返回一个AnimatedBuilder,是以控制器(其被用作一个Listenable在滚动事件上重新绘制自己)并构建一个OverflowBox,它被对齐以将齿轮放在屏幕外。

数值4并将3齿轮放置在被测设备的左下角,即iPhone Xʀ模拟器。在实践中,应根据设备屏幕的高度和宽度计算Alignment值,以提供精确值,将齿轮放置在任何设备上的所需位置(左下角,中心偏离侧面等),但为此例如,我们会保持简单。

最后一个是动画本身发生的好部分,在Transform类的rotate静态方法中。此类按预期将角度旋转角度。对于这个演示,我希望齿轮缓慢移动并感觉更多与滚动物理网格相比,而不是它具有1:1值的疯狂飞轮效果,我希望齿轮逆时针滚动,就好像它是物理驾驶列表,所以我把偏移量乘起来。然后除以-1024。


结论

本文和示例项目仅演示了Flutter为创建自定义动画用户体验提供的一些功能。只使用几个基本类和简单的数学,我们有一个完整的动画,为无聊的东西添加一个更有趣的元素(如设置屏幕)。

这些概念可以扩展为创建启动画面,加载动画,页面转换,通知效果或任何其他可以想象的内容。几乎任何以double参数为参数的东西都可以被动画化,从而可以直接实现效果,例如本例中使用的旋转,以及不透明度,位置和许多其他属性。

感谢阅读并祝你下一个Flutter项目好运!

源码:https://github.com/kenreilly/flutter-scroll-animation-demo

相关文章

  • 在Flutter中创建滚动动画

    使用Flutter从头开始构建平滑的滚动动画 介绍 在本文中,我们将介绍如何使用Flutter SDK从头开始创建...

  • Flutter 动画效果

    在动画方面 Flutter 提供了 Animation 类提供使用。 动画 Flutter 中创建动画,请创建名为...

  • Flutter - 创建拍手动画

    在本文中,我们将从头开始探索Flutter动画。我们将通过在Flutter中创建拍手动画的模型来学习关于动画的一些...

  • Flutter如何实现视差滚动?

    Flutter如何实现视差滚动? 效果如下: 在Flutter 中实现视差滚动,非常简单,Flutter已经提供相...

  • Flutter中创建滚动效果

    1. 前言 Flutter作为时下最流行的技术之一,凭借其出色的性能以及抹平多端的差异优势,早已引起大批技术爱好者...

  • flutter 滚动隐藏悬浮按钮

    flutter 滚动隐藏悬浮按钮 实现思路,当开始滚动的时候,执行动画让中间的悬浮按钮向右移动。当滚动结束的时候复...

  • Flutter中的动画

    Flutter中的动画 Flutter中的动画 https://flutterchina.club/tutoria...

  • Flutter动画animation

    参考 动画 flutter中动画抽象 划重点 Flutter 中的动画系统基于Animation对象,widget...

  • Flutter 中数字的滚动动画

    先上个图:

  • Flutter - 登录动画

    在Flutter应用程序中实现超级流畅的动画 在这篇文章中,我将带您完成在Flutter应用程序中实现流畅动画的步...

网友评论

    本文标题:在Flutter中创建滚动动画

    本文链接:https://www.haomeiwen.com/subject/snqfkctx.html