Android Flutter立体旋转
岛上码农 人气:0前言
之前我们提到了 CustomPaint er
的 Paint
可以使用渐变(GradientShader
)来填充绘制的图形,本篇我们来介绍使用图片填充,并且配合动画实现“立体”旋转效果,之所以给“立体”加上引号,是因为实际是通过填充图片自身的光影效果旋转后看起来像是立体效果一样。下面是实现的效果图。
ImageShader 简介
ImageShader
的定义如下,我们来看看各个参数的用途。
image
:用于填充的图像,是Image
类,注意这个Image
类定义在dart:ui
库中,并不是我们用于构建图像组件的Widget
下面的Image
类。tmx
:图形在 x 轴的处理方式,即当被填充的宽度与图片宽度不匹配时,在横轴方向如何填充。tmy
:图形在y 轴的处理方式,即当被填充的高度与图片高度不匹配时,在纵轴方向如何填充。matrix4
:对填充图像的三维空间的平移、旋转等变换操作。filterQuality
:当图片尺寸和被填充图形的尺寸不一致时,采样的质量,有高(high
)、中 (medium
)、低(low
)三类。
ImageShader( Image image, TileMode tmx, TileMode tmy, Float64List matrix4, { FilterQuality? filterQuality, } )
tmx
和 tmy
是 TileMode
枚举,有以下几种取值:
clamp
:图片不能完整填充图形时,使用最接近图形边缘的颜色进行填充,其实就是边缘的延伸。比如同时这是 tmx 和 tmy 都为 TileMode.clamp
的时候的效果图如下。
repeated
:这个好理解,就是在各自方向重复。
decal
:就是这个方向不做任何处理,使用透明填充,比如我们将上面的 tmy
改成 decal
,就只会在 x 轴重复了。
mirror
:顾名思义,就是镜像填充,下面是 tmx
为 mirror
,tmy
为 repeated
的效果图。
构建 ui.Image对象
要使用 ImageShader
,我们首先要从图片资源中构建ui.Image
对象。这需要将图片文件按ByteData
二进制方式读取,在将二进制文件解码成为 ui.Image
对象。这个操作是异步的,因此在操作没完成前不能使用图像资源,我们设置了一个isImageLoaded
布尔值标识图像是否加载完成。
final ByteData data = await rootBundle.load('images/beauty.jpg'); fillImage = await loadImage(Uint8List.view(data.buffer)); Future<ui.Image> loadImage(Uint8List img) async { final Completer<ui.Image> completer = Completer(); ui.decodeImageFromList(img, (ui.Image img) { setState(() { isImageLoaded = true; }); return completer.complete(img); }); return completer.future; }
使用 ImageShader 填充形状
使用 ImageShader
填充和 GradientShader
类似,按我们上面说的参数构建一个 ImageShader
对象就可以了,代码如下。注意,Paint
对象的填充方式必须是 fill
,如果是空心的话是看不到效果的。
@override void paint(Canvas canvas, Size size) { var paint = Paint(); paint.style = PaintingStyle.fill; paint.shader = ImageShader( image, TileMode.mirror, TileMode.repeated, Matrix4.identity().storage, filterQuality: FilterQuality.high, ); canvas.drawRect(Rect.fromLTRB(0, 0, size.width, size.height), paint); }
立体旋转效果实现
立体效果需要利用填充图像的光影效果,因此我们需要找一张图片,比如明暗不同,或色彩不同的,这样旋转起来就会感觉是立体的。旋转的话使用 Matrix4的旋转变换就行。同时,为了让旋转过程展示的图像不固定,我们旋转的时候可以通过Matrix4的平移显示不同图形的区域。下面是我们用于测试的两张图片。
实现的代码如下所示,其中animationValue
是动画过程中 Animation
对象的值,我们的动画时长设置为10秒。这里我们绘制的其实是一个圆形,只是因为填充图像在不停的旋转,且展示的图像不同就看起来有了立体效果。
void paint(Canvas canvas, Size size) { var paint = Paint(); paint.style = PaintingStyle.fill; paint.shader = ImageShader( image, TileMode.mirror, TileMode.mirror, (Matrix4.identity() ..translate(5 * animationValue, 5 * animationValue) ..scaled(0.5) ..rotateZ(2 * pi * animationValue)) .storage, filterQuality: FilterQuality.high, ); Offset center = Offset(size.width / 2, size.height / 2); canvas.drawCircle(center, 200, paint); }
下图是换了星球图片的运行效果,大家也可以调整 ImageShader
的参数看看其他参数的效果。
总结
源码已经提交至:绘图相关源码,文件名为:image_shader_demo.dart
。本篇介绍了 Flutter 绘图使用 ImageShader
填充图形,并且利用 Matrix4
的三维变换加上动画实现了立体旋转的动画效果。随着对 Flutter 绘图的深入,我们会发现绘图覆盖的面非常广,也能够实现更多有趣的效果。
加载全部内容