今天... 是一个非常重要的日子 - 女神节. 作为一名程序员, 如何向心仪的人低调而又不失逼格的表达祝福, 关系到我们后半生的幸福, 祝福的到位, 普通朋友加个字变成女朋友, 女朋友变成老婆, 如果已经是老婆了, 那么这个月的零花钱又能多好几百, 想想都激动.
回到现实, 作为程序员, 我们当然要独一无二, 要与众不同, 要突破天际, 要能体现我们的身份, 逼格满满, 因此我们要给女神开发一个天上地下, 唯吾独尊的 App 绝对是你不二的选择.
废话不多说, No 图 No 说话:
先来分析一波:
首先上面的效果是一直在绘制路径, 当绘制完花和叶子时在对其着色, 因此这里比较难是如何获取路径的点坐标, 只要有点的坐标了一个个的画出来也就实现了上面的效果.
那么现在的重点就是如何获取点坐标, 一种方法是人工一个一个的写, 然后调整, 这种方法工作量太大了, 作为程序员怎么能用这种方法呢? 怎么才可以让程序生成这些坐标呢?
想想我们在监听手势 (鼠标) 时是不是可以获取到当前点的坐标, 移动的时候也可以获取到一个移动的路径坐标, 因此我们只需要在屏幕上先加载想要的图片, 然后按照图片上的路径移动, 是不是就可以获取到我们想要的路径了啊.
对于任何语言来说都可以按照上面的思路来实现, 下面以目前非常火热的 Flutter 来实现这个功能.
好, 首先来加载一张图片, 然后监听其手势 (鼠标) 移动事件, 代码如下:
- Container(
- width: 400,
- height: 700,
- child: GestureDetector(
- onLongPressStart: (LongPressStartDetails details) {
- print('${details.localPosition},');
- },
- onLongPressMoveUpdate: (LongPressMoveUpdateDetails details) {
- print('${details.localPosition},');
- },
- onLongPressEnd: (LongPressEndDetails details) {
- print('${details.localPosition},');
- },
- child: Image.asset(
- 'images/123.png',
- fit: BoxFit.fill,
- ),
- ),
- )
这里要注意 2 点:
图片显示的大小最好和最终的画布一样大小, 这样得到的坐标不需要在转换.
图片的宽高比和画布的宽高比要一样.
我们把路径输出到控制台, 后台只需将这些坐标拷贝到应用程序即可, 将这些坐标定义为数组, 如下:
- static final List<Offset> flowerPoints = [
- Offset(182.0, 136.3),
- Offset(182.7, 135.3),
- Offset(183.0, 135.3),
- Offset(183.3, 135.3),
- ...
- )
点到路径获取到, 下面就是绘制了, 先绘制红色的花骨朵, 在 Flutter 中绘制路径需要继承 CustomPainter 类, 重写 paint 方法, 绘制路径及填充颜色代码如下:
- @override
- void paint(Canvas canvas, Size size) {
- // 将花变为红色
- if (flowerPaths.length>= RoseData.flowerPoints.length) {
- var path = Path();
- for (int i = 0; i <flowerPaths.length; i++) {
- if (i == 0) {
- path.moveTo(flowerPaths[i].dx, flowerPaths[i].dy);
- } else {
- path.lineTo(flowerPaths[i].dx, flowerPaths[i].dy);
- }
- }
- _paint.style = PaintingStyle.fill;
- _paint.color = _flowerColor;
- canvas.drawPath(path, _paint);
- }
- // 绘制线
- _paint.style = PaintingStyle.stroke;
- _paint.color = _strokeColor;
- canvas.drawPoints(PointMode.polygon, flowerPaths, _paint);
- }
这里要注意只有当当花骨朵所有的路径都绘制完之后才填充颜色, 而且要先填充颜色, 然后绘制路线, 不然路线会被填充颜色覆盖.
要想有绘制路径的效果, 需要将点依次增加, 增加动画控制器, 控制绘制路径, 代码如下:
- AnimationController _controller;
- Animation<num> _animation;
- @override
- void initState() {
- _controller = AnimationController(
- duration: Duration(seconds: 10), vsync: this)
- ..addListener(() {
- setState(() {
- _flowerPaths = RoseData.flowerPoints.sublist(0, _animation.value.floor());
- });
- });
- _animation = Tween(
- begin: 0.0,
- end: RoseData.flowerPoints.length)
- .animate(_controller);
- }
构建 UI 代码如下:
- @override
- Widget build(BuildContext context) {
- Container(
- width: 400,
- height: 700,
- child: CustomPaint(
- painter: RosePaint(_flowerPaths),
- ),
- )
- }
RosePaint 是自定义的 CustomPaint. 效果如下:
在最终的填充上发现有一部分没有填充上, 图中蓝色点为最后一个点, 所以需要在增加 2 个点, 绿色和黄色位置的点, 把未填充区域填充上.
填充点代码如下:
- static final List<Offset> flowerPoints = [
- Offset(182.0, 136.3),
- Offset(182.7, 135.3),
- ...
- Offset(179.3, 301.7),
- Offset(237.7, 144.7),
- ];
在绘制线的时候需要将这 2 个点去掉:
- if (flowerPaths.length>= RoseData.flowerPoints.length) {
- var path = Path();
- for (int i = 0; i < flowerPaths.length; i++) {
- if (i == 0) {
- path.moveTo(flowerPaths[i].dx, flowerPaths[i].dy);
- } else {
- path.lineTo(flowerPaths[i].dx, flowerPaths[i].dy);
- }
- }
- _paint.style = PaintingStyle.fill;
- _paint.color = _flowerColor;
- canvas.drawPath(path, _paint);
- }
- // 绘制线
- _paint.style = PaintingStyle.stroke;
- _paint.color = _strokeColor;
- // 去掉最后 2 个点, 最后 2 个点为了绘制红色
- var points = flowerPaths.sublist(0, max(0, flowerPaths.length - 2));
- canvas.drawPoints(PointMode.polygon, points, _paint);
花骨朵就好了, 其他的叶子和部位也是一样的画法, 这里就不在介绍了, 由于代码比较多, 就不全贴在这里了, 如果需要可以加我微信.
今天的文章对大家是否有帮助? 如果有, 请在文章底部留言和点赞, 以表示对我的支持, 你们的留言, 点赞和转发关注是我持续更新的动力!
来源: https://www.cnblogs.com/mengqd/p/12443270.html