網站首頁 編程語言 正文
前言
Flutter 的畫筆類 Paint
提供了很多圖形繪制的配置屬性,來供我們繪制更豐富多彩的圖形。前面幾篇我們介紹了 shader
屬性來繪制全屏漸變的聊天氣泡背景、漸變流動的邊框和毛玻璃效果的背景圖片,具體可以參考下面幾篇文章。
- 讓你的聊天氣泡豐富多彩!
- 手把手教你實現一個流動的漸變色邊框
- 利用光影變化構建立體旋轉效果
- Flutter 實現背景圖片毛玻璃效果
本篇我們引入一個 Paint
類新的屬性:maskFilter
,再結合之前的 shader
和動畫,看看能玩出什么花樣。
MaskFilter 類簡介
MaskFilter 類,顧名思義是遮罩過濾器,也就是在繪制過程中給圖像加一層遮罩效果,這個遮罩效果是通過某種變換函數實現的。Flutter 官方文檔的說明如下,可以看出其實就是對位圖的顏色處理。
A mask filter to apply to shapes as they are painted. A mask filter is a function that takes a bitmap of color pixels, and returns another bitmap of color pixels. 遮罩過濾器應用于要繪制的形狀,其實就是一個函數,接收一個彩色像素位圖,然后返回另一個彩色像素位圖。
在 Flutter 里面,目前只提供了一個 MaskFilter 的命名構造函數方式實例化,就是模糊效果。這個模糊效果和我們的圖片模糊有點類似,也是使用高斯模糊,只是多了一個模糊樣式參數。定義如下:
const MaskFilter.blur( this._style, this._sigma, )
關于這個方法的說明,為了便于理解,將官方的文檔翻譯如下:
Creates a mask filter that takes the shape being drawn and blurs it. This is commonly used to approximate shadows. The
style
argument controls the kind of effect to draw; Thesigma
argument controls the size of the effect. It is the standard deviation of the Gaussian blur to apply. The value must be greater than zero. The sigma corresponds to very roughly half the radius of the effect in pixels. A blur is an expensive operation and should therefore be used sparingly. The arguments must not be null. 創建一個遮罩過濾器將要繪制的形狀進行模糊處理。通常用于實現近似陰影的效果。style
參數控制繪制的效果類型 (BlurStyle
枚舉);sigma
參數控制效果的尺寸,實際就是使用的高斯模糊的標準差。sigma
的值必須大于0,這個值在像素上,大致是效果范圍的半徑值。模糊處理比較耗性能,因此要有節制地使用。
因為效果有點類似陰影,而且比較耗性能,因此如果僅僅是要繪制陰影的話,官方推薦是使用 Canvas 的 drawShadow
方法替代這個效果。
MaskFilter 的幾種效果對比
看文檔使用起來比較簡單,我們來看看 MaskFilter
的幾種不同的模糊樣式的區別。模糊樣式通過 style 參數控制,BlurStyle
枚舉取值有以下四種。
-
normal
:形狀內外都會做模糊處理,可以用于繪制圖形表面投影的陰影效果。 -
solid
:內部不模糊,外側模糊,會讓圖形看起來更明亮,類似熒光的效果。 -
outer
:外側模糊,內部沒有東西,適用于繪制半透明圖形的陰影。 -
inner
:外側不處理,內部模糊,看起來有種內發光的效果。
看文檔說明我們是體會不到具體的呈現效果的,我們繪制同一個圖形的不同效果對比看看。
outer
類型有點奇怪,中間掏空了,不過看上去還挺酷的。我畫了一個不模糊的疊加上去,發現組合后的效果就和 solid
模式一樣。
上面繪制的代碼如下。
@override void paint(Canvas canvas, Size size) { var paint = Paint(); paint.style = PaintingStyle.fill; var center = Offset(size.width / 2, size.height / 2); var radius = 80.0; paint.color = Colors.blue[400]!; paint.maskFilter = MaskFilter.blur(BlurStyle.outer, 20.0); canvas.drawCircle(center, radius, paint); }
光影流動
通過繪制的效果發現,其實 MaskFilter 實現的效果有點像設計師給的各種發光效果,比如內發光、外發光。這時候,配合動畫可以玩點有趣的東西了。
光影流動效果1
我們利用之前實現的全屏漸變色聊天氣泡中的效果,通過動畫控制一個圓形上下移動看看會有什么效果,感覺是一個彩色的光球在上升和下降。
上面效果的實現代碼如下,基本的邏輯如下:
- 整個繪圖范圍通過
shader
預填充,使得圓形移動過程的填充色漸變變化,和我們聊天氣泡中的效果一樣; - 通過
transform
動畫控制顏色旋轉,使得繪制的圓形的填充顏色旋轉,看起來會有立體感; - 通過 maskFilter,設置為 solid 模式讓圓形有熒光的效果;
- 通過動畫控制圓形上升和下降。
void _drawMovingCircle(Canvas canvas, Size size, Paint paint) { var radius = 80.0; paint.shader = LinearGradient( begin: Alignment.topCenter, end: Alignment.bottomCenter, colors: [ Colors.black87, Colors.purple, Colors.blue, Colors.green, Colors.yellow[500]!, Colors.orange, Colors.red[400]! ].reversed.toList(), tileMode: TileMode.clamp, transform: GradientRotation( animationValue * 2 * pi, ), ).createShader(Offset(0, 0) & size); paint.maskFilter = MaskFilter.blur(BlurStyle.solid, 20.0); canvas.drawCircle( Offset(size.width / 2, size.height * animationValue), radius, paint); }
光影流動效果2
上面的效果是一個圓形的,我們換成多個并排的矩形來看看,這種效果感覺整個填充區域的顏色在不停流動變幻,就好像有霓虹燈照耀的感覺。
上面效果的實現代碼如下,其實就是通過循環繪制了一排矩形,然后通過動畫控制上下移動位置。
void _drawMultiMovingRect(Canvas canvas, Size size, Paint paint) { paint.shader = LinearGradient( begin: Alignment.topCenter, end: Alignment.bottomCenter, colors: [ Colors.black87, Colors.purple, Colors.blue, Colors.green, Colors.yellow[500]!, Colors.orange, Colors.red[400]! ].reversed.toList(), tileMode: TileMode.clamp, transform: GradientRotation( animationValue * 2 * pi, ), ).createShader(Offset(0, 0) & size); paint.maskFilter = MaskFilter.blur(BlurStyle.solid, 20.0); var count = 10; for (var i = 0; i < count + 1; ++i) { canvas.drawRect( Offset(size.width / count * i, size.height * animationValue) & Size(size.width / count, size.width / count * 2), paint, ); } }
光影流動效果3
這一次我們使用 outer
類型的模糊效果,然后讓一串圓形沿屏幕對角線從收起到展開,再從展開到收起,效果如下所示,光束球發出來的時候,感覺就像是從左上角發了一個大招。
上面的實現代碼如下所示,就是通過控制圓形的中心位置實現對角線移動的,間距則是隨著動畫值的增加而拉大,因此會有發射的效果。
void _drawMultiMovingCircle(Canvas canvas, Size size, Paint paint) { paint.shader = LinearGradient( begin: Alignment.topCenter, end: Alignment.bottomCenter, colors: [ Colors.black87, Colors.purple, Colors.blue, Colors.green, Colors.yellow[500]!, Colors.orange, Colors.red[400]! ].reversed.toList(), tileMode: TileMode.clamp, transform: GradientRotation( animationValue * 2 * pi, ), ).createShader(Offset(0, 0) & size); paint.maskFilter = MaskFilter.blur(BlurStyle.outer, 20.0); var count = 10; for (var i = 0; i < count + 1; ++i) { canvas.drawCircle( Offset(size.width * i / count * animationValue, size.height * i / count * animationValue), size.width / count, paint, ); } }
光影流動效果4:光影沿貝塞爾曲線流動
我們來把圖形通過貝塞爾曲線控制繪制位置,來畫一組圖形,就能夠實現光影沿著貝塞爾曲線流動的效果了。這里我們沿著兩條首尾相接的貝塞爾曲線,繪制了一組正方形,看起來就像光影在一個閉合的圖形中來回穿梭一樣。
實現代碼和之前的類似,只是矩形的位置通過貝塞爾曲線生成,如下所示。
void _drawRectsUsingBezier(Canvas canvas, Size size, Paint paint) { paint.shader = LinearGradient( begin: Alignment.topCenter, end: Alignment.bottomCenter, colors: [ Colors.black87, Colors.purple, Colors.blue, Colors.green, Colors.yellow[500]!, Colors.orange, Colors.red[400]! ].reversed.toList(), tileMode: TileMode.clamp, transform: GradientRotation( animationValue * 2 * pi, ), ).createShader(Offset(0, 0) & size); paint.maskFilter = MaskFilter.blur(BlurStyle.outer, 2); final height = 120.0; var p0 = Offset(0, size.height / 2 + height); var p1 = Offset(size.width / 4, size.height / 2 - height); var p2 = Offset(size.width * 3 / 4, size.height / 2 + height); var p3 = Offset(size.width, size.height / 2 - height); var count = 150; var squareSize = 20.0; for (var t = 1; t <= count; t += 1) { var curvePoint = BezierUtil.get3OrderBezierPoint(p0, p1, p2, p3, t / count); canvas.drawRect( curvePoint & Size(squareSize, squareSize), paint, ); } for (var t = 1; t <= count; t += 1) { var curvePoint = BezierUtil.get3OrderBezierPoint(p3, p1, p2, p0, t / count); canvas.drawRect( curvePoint & Size(squareSize, squareSize), paint, ); } }
總結
本篇介紹了 Flutter 畫筆類 Painter
的 MaskFilter
的使用,MaskFilter
的應用效果就是讓形狀能有類似發光的效果。我們結合之前的幾篇文章用到的繪制效果完成了一場“光影秀”,視覺上看起來還是很美的。這也是開發過程中繪圖的樂趣之一,看著自己畫出來很美的效果也還是很有成就感的。
原文鏈接:https://juejin.cn/post/7115990446311997448
相關推薦
- 2022-11-09 django中的auth模塊與admin后臺管理方法_python
- 2022-01-11 slice、substring、substr比較
- 2022-01-13 macOS 升級后 nvm 安裝的 node 和 npm 出錯
- 2022-10-21 C#中匿名方法與委托的關系介紹_C#教程
- 2022-08-07 Qt使用QPainter實現自定義圓形進度條_C 語言
- 2022-09-03 ASP.NET實現Repeater控件的數據綁定_基礎知識
- 2022-07-13 Android?Studio實現簡單繪圖板_Android
- 2022-06-08 Spring Cloud Ribbon 負載均衡器
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支