温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

Flutter如何给控件实现微光特效

发布时间:2021-08-23 12:34:54 来源:亿速云 阅读:332 作者:小新 栏目:开发技术

这篇文章主要介绍了Flutter如何给控件实现微光特效,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。

效果图

Flutter如何给控件实现微光特效

使用方法

Shimmer(   baseColor: const Color(0x08ffffff), // 背景颜色   highlightColor: Colors.white, // 高光的颜色   loop: 2, // 闪烁循环次数,不传默认一直循环   child: Image.asset('assets/images/watermelon.png',width: 325, height: 260, fit: BoxFit.contain), )

实现原理

① 特效控件分为两层:底层显示调用方传入的控件;上层覆盖一层渐变着色器。

② 启动动画,根据动画的进度,对渐变着色器的区域进行绘制,当区域变大变小时,着色器高光的地方也在相应进行偏移。

③ 同时着色器不能超出底层控件的绘制范围,底层控件的形状是不规则的,渐变层不能超出底层控件的layer对象。这样才能实现完全贴合 底层控件形状 的微光闪烁。

控件分层显示

@override   Widget build(BuildContext context) {     return Stack(       children: [         // 底层控件         widget.child,         // 覆盖闪烁微光         AnimatedBuilder(           animation: _controller,           child: widget.child,           builder: (BuildContext context, Widget? child) => _Shimmer(             child: child,             percent: _controller.value,             direction: widget.direction,             gradient: widget.gradient,           ),         )       ],     );

开启动画

  late AnimationController _controller;   int _count = 0;   @override   void initState() {     super.initState();     _controller = AnimationController(vsync: this, duration: widget.duration)       ..addStatusListener((AnimationStatus status) {         if (status != AnimationStatus.completed) {           return;         }         _count++;         if (widget.loop != 0 && _count < widget.loop) {           _controller.forward(from: 0.0);         }       });     if (widget.loop == 0) {       _controller.repeat();     } else {       _controller.forward();     }   }

重点:着色器该如何绘制,又该如何通过AnimationController的进度进行偏移?由于着色器不能超出底层控件的绘制范围,所以必须拿到底层控件的绘制上下文【即 PaintingContext】,调用其pushLayer方法,让引擎把着色器绘制上去。

需要用到PaintingContext,自然就需要去管理RenderObject,所以着色器的编写使用RenderProxyBox进行计算并绘制出layer对象,计算的过程根据上面的AnimationController的进度进行计算。

class _ShimmerFilter extends RenderProxyBox {   ShimmerDirection _direction;   Gradient _gradient;   double _percent;   _ShimmerFilter(this._percent, this._direction, this._gradient);   @override   ShaderMaskLayer? get layer => super.layer as ShaderMaskLayer?;   set percent(double newValue) {     if (newValue != _percent) {       _percent = newValue;       markNeedsPaint();     }   }   set gradient(Gradient newValue) {     if (newValue != _gradient) {       _gradient = newValue;       markNeedsPaint();     }   }   set direction(ShimmerDirection newDirection) {     if (newDirection != _direction) {       _direction = newDirection;       markNeedsLayout();     }   }   @override   void paint(PaintingContext context, Offset offset) {     if (child != null) {       final double width = child!.size.width;       final double height = child!.size.height;       Rect rect;       double dx, dy;       if (_direction == ShimmerDirection.rtl) {         dx = _offset(width, -width, _percent);         dy = 0.0;         rect = Rect.fromLTWH(dx - width, dy, 3 * width, height);       } else if (_direction == ShimmerDirection.ttb) {         dx = 0.0;         dy = _offset(-height, height, _percent);         rect = Rect.fromLTWH(dx, dy - height, width, 3 * height);       } else if (_direction == ShimmerDirection.btt) {         dx = 0.0;         dy = _offset(height, -height, _percent);         rect = Rect.fromLTWH(dx, dy - height, width, 3 * height);       } else {         dx = _offset(-width, width, _percent);         dy = 0.0;         rect = Rect.fromLTWH(dx - width, dy, 3 * width, height);       }       layer ??= ShaderMaskLayer();       layer!         ..shader = _gradient.createShader(rect)         ..maskRect = offset & size         ..blendMode = BlendMode.srcIn;       context.pushLayer(layer!, super.paint, offset);     } else {       layer = null;     }   }   double _offset(double start, double end, double percent) {     return start + (end - start) * percent;   } }

Render对象绘制出来后,需要封装成widget使用,由于是单一组件,用SingleChildRenderObjectWidget即可。

class _Shimmer extends SingleChildRenderObjectWidget {   @override   _ShimmerFilter createRenderObject(BuildContext context) {     return _ShimmerFilter(percent, direction, gradient);   }   @override   void updateRenderObject(BuildContext context, _ShimmerFilter shimmer) {     shimmer.percent = percent;     shimmer.gradient = gradient;     shimmer.direction = direction;   } }

感谢你能够认真阅读完这篇文章,希望小编分享的“Flutter如何给控件实现微光特效”这篇文章对大家有帮助,同时也希望大家多多支持亿速云,关注亿速云行业资讯频道,更多相关知识等着你来学习!

向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

AI