flutter对比Android绘制流程,【分析】Flutter 滑动对比图

本文仅做分析。项目作者见 github

GitHub 源地址:  Before After

先上预览图:

abc3d8f014439ac52904216b083f476a.png

原理分析图:

5848f8c681c4da3c5e9571e535f78411.png

源码共两个文件:rect_clipper.dart

custom_widget.dart

custom_widget.dart 是控件的主要实现。

rect_clipper.dart 是对不同方向 (裁剪)的实现。继承于 CustomClipper

rect_clipper.dart:SizedImage

/// 使用 [SizedBox] 来限制图像大小

class SizedImage extends StatelessWidget {

/// 传入的 WIDGET

final Widget _image;

/// 用作 [SizedBox] 的宽高,以限制 [_image] 的大小

final double _height, _width, _imageCornerRadius;

const SizedImage(

this._image, this._height, this._width, this._imageCornerRadius,

{Key key})

: super(key: key);

@override

Widget build(BuildContext context) {

// 裁剪

return ClipRRect(

borderRadius: BorderRadius.circular(_imageCornerRadius),

// 固定宽高

child: SizedBox(

height: _height,

width: _width,

child: _image,

),

);

}

}复制代码

这里使用 SizedBox 来限制传入的 widget 宽高。

rect_clipper.dart: CustomThumbShape

class CustomThumbShape extends SliderComponentShape {

/// 滑块半径

final double _thumbRadius;

/// 滑块颜色

final Color _thumbColor;

CustomThumbShape(this._thumbRadius, this._thumbColor);

@override

Size getPreferredSize(bool isEnabled, bool isDiscrete) {

return Size.fromRadius(_thumbRadius);

}

@override

void paint(PaintingContext context, Offset center,

{Animation activationAnimation,

Animation enableAnimation,

bool isDiscrete,

TextPainter labelPainter,

RenderBox parentBox,

SliderThemeData sliderTheme,

TextDirection textDirection,

double value}) {

final Canvas canvas = context.canvas;

// 内圈

final Paint paint = Paint()

// 抗锯齿

..isAntiAlias = true

// 描边宽度

..strokeWidth = 4.0

..color = _thumbColor

..style = PaintingStyle.fill;

// 外圈

final Paint paintStroke = Paint()

..isAntiAlias = true

..strokeWidth = 4.0

..color = _thumbColor

..style = PaintingStyle.stroke;

canvas.drawCircle(

center,

_thumbRadius,

paintStroke,

);

canvas.drawCircle(

center,

_thumbRadius - 6,

paint,

);

// 画出一条"直线"

canvas.drawRect(

Rect.fromCenter(

center: center, width: 4.0, height: parentBox.size.height),

paint);

}

}

复制代码

CustomThumbShape 就是这个(绿圈内):

bdf1e980a192b8d6d0677ec50e00530c.png

至于 CustomThumbShape 用在何处下面解释。

rect_clipper.dart:BeforeAfter,_BeforeAfter

class BeforeAfter extends StatefulWidget {

/// image1

final Widget beforeImage;

// image2

final Widget afterImage;

/// 图像宽高

final double imageHeight;

final double imageWidth;

/// 图像四角裁剪半径

final double imageCornerRadius;

/// 拖动指示器颜色

final Color thumbColor;

/// 指示器半径

final double thumbRadius;

/// 点击指示器的背景颜色

final Color overlayColor;

/// 拖动方向

final bool isVertical;

const BeforeAfter({

Key key,

@required this.beforeImage,

@required this.afterImage,

this.imageHeight,

this.imageWidth,

this.imageCornerRadius = 8.0,

this.thumbColor = Colors.white,

this.thumbRadius = 16.0,

this.overlayColor,

this.isVertical = false,

}) : assert(beforeImage != null),

assert(afterImage != null),

super(key: key);

@override

_BeforeAfterState createState() => _BeforeAfterState();

}

class _BeforeAfterState extends State {

/// 裁剪程度

double _clipFactor = 0.5;

@override

Widget build(BuildContext context) {

return Stack(

alignment: Alignment.center,

children: [

// AFTER

Padding(

padding: widget.isVertical

? const EdgeInsets.symmetric(vertical: 24.0)

: const EdgeInsets.symmetric(horizontal: 24.0),

child: SizedImage(

widget.afterImage,

widget.imageHeight,

widget.imageWidth,

widget.imageCornerRadius,

),

),

/// BEFORE

Padding(

padding: widget.isVertical

? const EdgeInsets.symmetric(vertical: 24.0)

: const EdgeInsets.symmetric(horizontal: 24.0),

child: ClipPath(

clipper: widget.isVertical

? RectClipperVertical(_clipFactor)

: RectClipper(_clipFactor),

child: SizedImage(

widget.beforeImage,

widget.imageHeight,

widget.imageWidth,

widget.imageCornerRadius,

),

),

),

Positioned.fill(

child: SliderTheme(

data: SliderThemeData(

// slider 宽度调整为 0

trackHeight: 0,

overlayColor: widget.overlayColor,

thumbShape:

CustomThumbShape(widget.thumbRadius, widget.thumbColor),

),

child: widget.isVertical

? RotatedBox(

quarterTurns: 1,

child: Slider(

value: _clipFactor,

onChanged: (double factor) =>

setState(() => this._clipFactor = factor),

),

)

: Slider(

value: _clipFactor,

onChanged: (double factor) =>

setState(() => this._clipFactor = factor),

),

),

),

],

);

}

}复制代码

从中我们可以看出两张图片置于 Stack中,底部图片用 SizedImage进行限制大小,顶部图片通用限制大小后被 ClipPath包裹,ClipPath顾名思义,用于裁剪 widget

我们根据是否垂直来使用不同的 clipper。什么是垂直,见下图:

c3fc211fb580d147c2e605909b80c499.png

我们可以看到 RectClipper传入了一个值,_clipFactor,此值用于控制裁剪的程度(裁剪的百分比),后面又具体解释。

custom_widget.dart:RectClipper

class RectClipper extends CustomClipper {

final double clipFactor;

RectClipper(this.clipFactor);

@override

Path getClip(Size size) {

Path path = Path();

path.lineTo(size.width * clipFactor, 0.0);

path.lineTo(size.width * clipFactor, size.height);

path.lineTo(0.0, size.height);

path.close();

return path;

}

@override

bool shouldReclip(CustomClipper oldClipper) => true;

}

复制代码

这里代码用一张图解释:

f07466aae4bdb8e24bd24e1e95a9e082.png

clipFactor取值 0 ~ 1 。

至于这三行代码,我们继续用图表示:

path.lineTo(size.width * clipFactor, 0);

path.lineTo(size.width * clipFactor, size.height);

path.lineTo(0.0, size.height);复制代码

fcf539af835eee24922ffccc7ab59e0d.png

下面具体说一下  CustomThumbShape

Positioned.fill(

child: SliderTheme(

data: SliderThemeData(

// slider 宽度调整为 0

trackHeight: 0,

overlayColor: widget.overlayColor,

thumbShape:

CustomThumbShape(widget.thumbRadius, widget.thumbColor),

),

child: widget.isVertical

? RotatedBox(

quarterTurns: 1,

child: Slider(

value: _clipFactor,

onChanged: (double factor) =>

setState(() => this._clipFactor = factor),

),

)

: Slider(

value: _clipFactor,

onChanged: (double factor) =>

setState(() => this._clipFactor = factor),

),

),

),复制代码

使用 SliderTheme 加上 SliderThemeData创造一个自定义 slider, trackHeight: 0, 把 slider 进度条调整为 0 。

2d92ee6f3c297da9b31662db2c75bc2b.png

上图是不调整 trackHeight的效果。

然后通过判断是否为垂直,来决定是否使用 RotatedBox旋转 Slider。

以上就是 Before After 的分析笔记。

b739ec46bb5c46d9c0aa4ce35ba1ea56.png

关于找一找教程网

本站文章仅代表作者观点,不代表本站立场,所有文章非营利性免费分享。

本站提供了软件编程、网站开发技术、服务器运维、人工智能等等IT技术文章,希望广大程序员努力学习,让我们用科技改变世界。

[【分析】Flutter 滑动对比图]http://www.zyiz.net/tech/detail-134790.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值