基于Flutter制作一個(gè)心碎動(dòng)畫(huà)特效
前言
繼續(xù)動(dòng)畫(huà)探索,今天用Flutter制作一個(gè)心碎的感覺(jué),靈感來(lái)源于今天的股市,哎,心哇涼哇涼的。廢話不多說(shuō),開(kāi)始。
效果圖先上:
實(shí)現(xiàn)步驟
1、繪制一個(gè)心
首先我們使用兩段三階貝塞爾曲線制作一個(gè)心型,這里因?yàn)樾枰獙?shí)現(xiàn)心碎的效果,所以我們需要將心的兩段用兩段路徑path
進(jìn)行繪制出來(lái),效果:
繪制代碼:
canvas.translate(size.width / 2, size.height / 2); Paint paint = Paint(); paint ..style = PaintingStyle.stroke ..strokeWidth = 2 ..color = Colors.black87; Path path = Path(); path.moveTo(0, 0); path.cubicTo(-200, -80, -60, -240, 0, -140); path.close(); Path path2 = Path(); canvas.save(); canvas.drawPath( path, paint ..color = Colors.red ..style = PaintingStyle.stroke); canvas.restore(); path2.cubicTo(200, -80, 60, -240, 0, -140); path2.close(); canvas.drawPath( path2, paint..color = Colors.black87);
2、繪制心的裂痕
我們看到心確實(shí)分成兩半了,但是中間還缺少裂痕,接下來(lái)我們就繪制心碎的裂痕,也很簡(jiǎn)單,在兩段路徑path
閉合前進(jìn)行繪制線,效果:
繪制代碼:
path.relativeLineTo(-10, 30); path.relativeLineTo(20, 5); path.relativeLineTo(-20, 30); path.relativeLineTo(20, 20); path.relativeLineTo(-10, 20); path.relativeLineTo(10, 10); path2.relativeLineTo(-10, 30); path2.relativeLineTo(20, 5); path2.relativeLineTo(-20, 30); path2.relativeLineTo(20, 20); path2.relativeLineTo(-10, 20); path2.relativeLineTo(10, 10);
OK,我們已經(jīng)看到心已經(jīng)有了裂痕,如何心碎,只需將畫(huà)布進(jìn)行翻轉(zhuǎn)一定角度即可,這里我們將畫(huà)布翻轉(zhuǎn)45°,看下效果:
左邊:
右邊:
3、加入動(dòng)畫(huà)
已經(jīng)有心碎的感覺(jué)了,接下來(lái)加入動(dòng)畫(huà)元素讓心碎的過(guò)程動(dòng)起來(lái)。
思路: 我們可以想一下,心碎的過(guò)程是什么樣子,心的顏色慢慢變灰,心然后慢慢裂開(kāi),下方的動(dòng)畫(huà)運(yùn)動(dòng)曲線看起來(lái)更符合心碎的過(guò)程,里面有不舍,不甘,但最后心還是慢慢的碎了。
我們把畫(huà)筆進(jìn)行填充將這個(gè)動(dòng)畫(huà)加入進(jìn)來(lái)看下最終效果。
是不是心碎了一地。
知識(shí)點(diǎn): 這里我們需要找到紅色和灰色的RGB色值,通過(guò)Color.fromRGBO(r, g, b, opacity)
方法賦值顏色的色值。然后通過(guò)動(dòng)畫(huà)值改變RGB的值即可。 這里我使用的色值是:
紅色:Color.fromRGBO(255, 0, 0, 1)
灰色:Color.fromRGBO(169, 169, 169, 1)
完整代碼
class XinSui extends StatefulWidget { const XinSui({Key? key}) : super(key: key); @override _XinSuiState createState() => _XinSuiState(); } class _XinSuiState extends State<XinSui> with SingleTickerProviderStateMixin { late AnimationController _controller = AnimationController(vsync: this, duration: Duration(milliseconds: 4000)) ..repeat(); late CurvedAnimation cure = CurvedAnimation(parent: _controller, curve: Curves.bounceInOut); late Animation<double> animation = Tween<double>(begin: 0.0, end: 1.0).animate(cure); @override Widget build(BuildContext context) { return Container( child: CustomPaint( size: Size(double.infinity, double.infinity), painter: _XinSuiPainter(animation), ), ); } @override void dispose() { _controller.dispose(); super.dispose(); } } class _XinSuiPainter extends CustomPainter { Animation<double> animation; _XinSuiPainter(this.animation) : super(repaint: animation); @override void paint(Canvas canvas, Size size) { canvas.translate(size.width / 2, size.height / 2); Paint paint = Paint(); paint ..style = PaintingStyle.stroke ..strokeWidth = 2 ..color = Colors.black87; Path path = Path(); path.moveTo(0, 0); path.cubicTo(-200, -80, -60, -240, 0, -140); path.relativeLineTo(-10, 30); path.relativeLineTo(20, 5); path.relativeLineTo(-20, 30); path.relativeLineTo(20, 20); path.relativeLineTo(-10, 20); path.relativeLineTo(10, 10); path.close(); Path path2 = Path(); canvas.save(); canvas.rotate(-pi / 4 * animation.value); canvas.drawPath( path, paint ..color = Colors.red ..color = Color.fromRGBO( 255 - (86 * animation.value).toInt(), (animation.value * 169).toInt(), (animation.value * 169).toInt(), 1) ..style = PaintingStyle.fill); canvas.restore(); path2.cubicTo(200, -80, 60, -240, 0, -140); path2.relativeLineTo(-10, 30); path2.relativeLineTo(20, 5); path2.relativeLineTo(-20, 30); path2.relativeLineTo(20, 20); path2.relativeLineTo(-10, 20); path2.relativeLineTo(10, 10); path2.close(); canvas.rotate(pi / 4 * animation.value); canvas.drawPath( path2,paint); } @override bool shouldRepaint(covariant _XinSuiPainter oldDelegate) { return oldDelegate.animation != animation; } }
小結(jié)
動(dòng)畫(huà)曲線Curves配合繪制可以實(shí)現(xiàn)很多好玩的東西,這個(gè)需要勤加練習(xí)方能掌握,僅將此心碎獻(xiàn)給今天受傷的股民朋友們
到此這篇關(guān)于基于Flutter制作一個(gè)心碎動(dòng)畫(huà)特效的文章就介紹到這了,更多相關(guān)Flutter心碎動(dòng)畫(huà)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Android獲取系統(tǒng)儲(chǔ)存以及內(nèi)存信息的方法(一)
這篇文章主要為大家詳細(xì)介紹了Android獲取系統(tǒng)儲(chǔ)存以及內(nèi)存信息的方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-10-10強(qiáng)制去除Unity自動(dòng)添加的Android隱私權(quán)限
大家好,本篇文章主要講的是強(qiáng)制去除Unity自動(dòng)添加的Android隱私權(quán)限,感興趣的同學(xué)趕快來(lái)看一看吧,對(duì)你有幫助的話記得收藏一下,方便下次瀏覽2021-12-12Android使用OKhttp3實(shí)現(xiàn)登錄注冊(cè)功能+springboot搭建后端的詳細(xì)過(guò)程
這篇教程主要實(shí)現(xiàn)Android使用OKhttp3實(shí)現(xiàn)登錄注冊(cè)的功能,后端使用SSM框架,本文通過(guò)實(shí)例圖文相結(jié)合給大家介紹的非常詳細(xì),需要的朋友參考下吧2021-07-07mui.init()與mui.plusReady()區(qū)別和關(guān)系
給大家分享一下在使用MUI進(jìn)行APP開(kāi)發(fā)的時(shí)候,mui.init()與mui.plusReady()區(qū)別以及使用上不同之處。2017-11-11Jetpack Compose按鈕組件使用實(shí)例詳細(xì)講解
這篇文章主要介紹了Jetpack Compose按鈕組件使用實(shí)例,按鈕組件Button是用戶和系統(tǒng)交互的重要組件之一,它按照Material Design風(fēng)格實(shí)現(xiàn),我們先看下Button的參數(shù)列表,通過(guò)參數(shù)列表了解下Button的整體功能2023-04-04將替代ListView的RecyclerView 的使用詳解(一)
這篇文章主要介紹了將替代ListView的RecyclerView 的使用詳解(一)的相關(guān)資料,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下2016-07-07Android使用Canvas?2D實(shí)現(xiàn)循環(huán)菜單效果
循環(huán)菜單有很多種自定義方式,我們可以利用ViewPager或者RecyclerView?+?CarouselLayoutManager?或者RecyclerView?+?PageSnapHelper來(lái)實(shí)現(xiàn)這種效果,今天我們使用Canvas?2D來(lái)實(shí)現(xiàn)這種效果,感興趣的朋友可以參考下2024-01-01Android canvas畫(huà)圖操作之切割畫(huà)布實(shí)現(xiàn)方法(clipRect)
這篇文章主要介紹了Android canvas畫(huà)圖操作之切割畫(huà)布實(shí)現(xiàn)方法,通過(guò)clipRect方法實(shí)現(xiàn)canvas畫(huà)布的切割操作,需要的朋友可以參考下2016-10-10