Flutter -如何创建炫酷粒子时钟效果!

本文作者通过使用Flutter构建一个具有随机背景、粒子效果和同步动画的时钟,分享了从艺术小白到使用数学和Flutter技术实现复杂界面的过程,包括粒子运动、色彩管理和界面布局的优化。
摘要由CSDN通过智能技术生成
  • 3、我们是否可以将背景形状、颜色、动画随机改变以使它:a. 看起来很酷,b. 足够满足1和2的随机性,c. 不会分散你看时间的注意力?

我以前从未完成过任何艺术,或者根本没有做过Flutter,所以我着手建造这样的时钟。

粒子与随机性

第一次迭代只是一个时钟。如上所述,我从示例数字时钟项目开始,而不是从头开始。创建的第一个Widget是一个CustomPainter,仅绘制了一个圆圈。很不错,但是从长远来看不是很有趣。

随机性增加了,从颜色开始,然后确定位置和大小。所有逻辑仍然在单个CustomPainterpaint()方法中,这几乎使动画变得不可能,因此需要将一堆逻辑重构成一个简单的粒子系统。我看了Flutter Vignettes项目,以寻求启发。

https://flutter.gskinner.com/

这时候,制作模拟粒子时钟的想法变得更加明显了。

将粒子变成模拟时钟

提出想法后,我要做的就是编写代码以实现所有目标。数学部分花费了我最多的时间才最终完成,大多是我多年以前学过的数学,不过好多我都忘记了,角度,弧度,PI和类似的东西,网上又许多解决方案,但是你将不得不做一些修改以适应您的用例。

以下是获取时针弧度的方法:

/// Gets the radians of the hour hand.

double _getHourRadians() =>

(time.hour * pi / 6) +

(time.minute * pi / (6 * 60)) +

(time.second * pi / (360 * 60));

我在计算中包括了time.minutetime.second,以使时针在数小时之间平滑地动画。

然后,从弧度获得2D运动矢量就很简单了。

// Particle movement vector.

p.vx = sin(-angle);

p.vy = cos(-angle);

现在,p.vxp.vy拥有 有关粒子在每个动画滴答声中应该移动多远的信息,同时保持在时针的角度里。

除了钟针外,粒子还可能作为噪音产生。然后它将从中心沿随机方向发射。在发出时,还将为所有粒子分配随机的速度颜色大小绘画样式(填充或笔划)。这使时钟看起来更有趣。

时钟的早期版本中。这有四分之一标记,有些粒子有速度标记。时钟的第一个版本只是粒子,这里就不花时间截图演示了。

使用Flutter Widgets 添加图层

到现在为止,所有内容都使用单个CustomPainter小部件(即widget,下文也一样)绘制。时钟看起来不错,但是很难告诉你时间。而且,背景是单色,看上去很无聊。

Flutter非常适合构建复杂的布局。毕竟,它是一个用于用户界面的工具包。将一堆小部件彼此堆叠,您只需将它们包装在Stack widget中。粒子时钟的最后一个场景小部件负责构建3个主要层:

  • 1、Background:一个带有CustomPaint小部件的堆栈,该小部件绘制不同颜色和绘画样式的随机形状,以及一个应用了模糊效果的BackdropFilter

  • 2、Clock Face: 带有2个CustomPaint 小部件的堆栈,

  • a. 时钟标记-绘制时钟标记。每分钟标记,每5分钟标记具有额外的可见性。

  • b. 秒针-绘制两秒的针弧。

  • 3、 Particle FX: 一个CustomPaint小部件,用于绘制所有粒子。

@override

Widget build(BuildContext context) {

return AnimatedContainer(

duration: Duration(milliseconds: 1500),

curve: Curves.easeOut,

color: _bgColor,

child: ClipRect(

child: Stack(

children: [

_buildBgBlurFx(),

_buildClockFace(),

CustomPaint(

painter: ClockFxPainter(fx: _fx),

child: Container(),

),

],

),

),

);

}

即使底层代码很复杂,Flutter仍可以通过小部件组合来管理布局。

时钟绘图层和覆盖层。

这是与上述相同的图片,但没有覆盖层。

与时间同步的动画

我很早就想到,如果动画与时钟的滴答声同步发生,那就太酷了。最终版本中的解决方案非常简单。没有到达到想象中的目标。最初,我把它变成了一个非常复杂的问题,并尝试了各种怪异的技巧使它起作用。

@override

void tick(Duration duration) {

var secFrac = DateTime.now().millisecond / 1000;

var vecSpeed = duration.compareTo(easingDelayDuration) > 0

? max(.2, Curves.easeInOutSine.transform(1 - secFrac))

: 1;

particles.asMap().forEach((i, p) {

// Movement

p.x -= p.vx * vecSpeed;

p.y -= p.vy * vecSpeed;

// etc…

}

}

以上代码在每个动画刻度上运行。通过结合使用DateTime.now()(以毫秒为单位)和Curves,我们得到一个介于01之间的值。max函数确保该数字保持在0.2以上,以始终保持粒子随着每个刻度移动。

然后,在计算粒子的新xy位置时,将vecSpeed编号与运动矢量结合使用。

调色板和清晰度

在图形用户界面中随机分配颜色时,通常会让人感到厌烦。当然,这是有充分的理由,因为它通常会使GUI的访问性降低。在保持易读性的同时将随机颜色应用于GUI并不是一个容易解决的问题。幸运的是,Flutter有一些工具可以使我们更轻松。

首先,我使用了ColourLovers API来获取其用户最喜欢的一些调色板。简而言之,许多调色板的颜色之间的对比度很差。我根据WCAG Contrast指南,创建了一个过滤调色板阵列的脚本来解决了这一问题。过滤后,该列表仅包含调色板,其中至少存在一种对比度大于或等于4.5的颜色组合。

然后,在Flutter中,我们仅需使用Color类的computeLuminance方法即可找到良好的匹配项。

/// Gets a random palette from a list of palettes and sorts its’

/// colors by luminance.

///

/// Given if [dark] or not, this method makes sure the luminance

/// of the background color is valid.

static Palette getPalette(List palettes, bool dark) {

Palette result;

while (result == null) {

Palette palette = Rnd.getItem(palettes);

List colors = Rnd.shuffle(palette.components);

var luminance = colors[0].computeLuminance();

if (dark ? luminance <= .1 : luminance >= .1) {

var lumDiff = colors

.sublist(1)

.asMap()

.map(

(i, color) => MapEntry(

i,

[i, (luminance - color.computeLuminance()).abs()],

),

)

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则近万的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

img

img

img

img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注:Android)

最后

其实Android开发的知识点就那么多,面试问来问去还是那么点东西。所以面试没有其他的诀窍,只看你对这些知识点准备的充分程度。so,出去面试时先看看自己复习到了哪个阶段就好。

当然我也为你们整理好了百度、阿里、腾讯、字节跳动等等互联网超级大厂的历年面试真题集锦。这也是我这些年来养成的习惯,一定要学会把好的东西,归纳整理,然后系统的消化吸收,这样才能极大的提高学习效率和成长进阶。碎片、零散化的东西,我觉得最没有价值的。就好比你给我一张扑克牌,我只会觉得它是一张废纸,但如果你给我一副扑克牌,它便有了它的价值。这和我们收集资料就要收集那些系统化的,是一个道理。

网上学习 Android的资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。希望这份系统化的技术体系对大家有一个方向参考。

《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!

进阶。碎片、零散化的东西,我觉得最没有价值的。就好比你给我一张扑克牌,我只会觉得它是一张废纸,但如果你给我一副扑克牌,它便有了它的价值。这和我们收集资料就要收集那些系统化的,是一个道理。

[外链图片转存中…(img-a42gC4pu-1712614879919)]

网上学习 Android的资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。希望这份系统化的技术体系对大家有一个方向参考。

《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值