Flutter绘图组件之CustomPaint使用详解
作者:岛上码农 发布时间:2021-12-13 01:26:06
简介
在有些场景中,我们会需要绘制一些高度定制化的组件,比如 UI 设计师给我们出了个难题 —— 弄一个奇形怪状的边框。看在 UI 设计师是一个漂亮小姐姐的份上,又不好意思说这个做不了(那样也很没面子)。这个时候我们就不能直接使用 Flutter 自带的那些组件了,而是需要手动绘制组件,那就会需要用到 CuntomPaint
组件。CustomPaint
组件和前端的 Canvas
差不多,允许我们在一个画布上绘制各种元素,包括点、线、矩形、圆弧、文字、图片等等。
CustomPaint 介绍
CustomPaint
是一个 Widget,其中有三个重要的参数:
CustomPaint(
child: childWidget(),
foregroundPainter: foregroundPainter(),
painter: backgroundPainter(),
)
child
:CustomPaint
的子组件;
painter
和 foregroundPainter
:都是 CustomPainter
类,用于定义 canvas
绘制的内容。区别在于,首先是执行 painter
的绘制指令。然后是在背景上渲染 child
子组件。最后,foregroundPainter
的内容会绘制在 child
上一层。
CustomPainter
提供了一个paint绘图方法供我们绘制图形,该方法携带canvas
和size
两个参数,其中 canvas
是画布,size
是画布大小。canvas
提供了很多绘制图形的方法,比如绘制路径、矩形、圆形和线条等等。
CustomPainter 示例
有了上面的基础概念后,我们来一个简单的示例来演示三个参数的层级关系。我们在backgroundPainter
上绘制一个蓝色的正方形,然后传入一个原型图片组件作为 child
,最后是在 foregroundPainter
上绘制一个半透明的红色圆形遮住一部分图片。最终实现效果如下图,这样我们可以很好地了解三个元素的关系。
完整代码如下:
import 'dart:ui';
import 'package:flutter/material.dart';
class BasicPaintPage extends StatelessWidget {
const BasicPaintPage({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return CustomPaint(
child: Center(
child: ClipOval(
child: Image.asset(
'images/beauty.jpeg',
width: 200,
height: 200,
fit: BoxFit.fitWidth,
),
),
),
painter: BackgroundPainter(),
foregroundPainter: ForegroundPainter(),
);
}
}
class BackgroundPainter extends CustomPainter {
@override
void paint(Canvas canvas, Size size) {
canvas.drawColor(Color(0xFFF1F1F1), BlendMode.color);
var center = size / 2;
var paint = Paint()..color = Color(0xFF2080E5);
paint.strokeWidth = 2.0;
canvas.drawRect(
Rect.fromLTWH(center.width - 120, center.height - 120, 240, 240),
paint,
);
}
@override
bool shouldRepaint(covariant CustomPainter oldDelegate) {
return false;
}
}
class ForegroundPainter extends CustomPainter {
@override
void paint(Canvas canvas, Size size) {
var center = size / 2;
var paint = Paint()..color = Color(0x80F53010);
paint.strokeWidth = 2.0;
canvas.drawCircle(
Offset(center.width, center.height),
100,
paint,
);
}
@override
bool shouldRepaint(covariant CustomPainter oldDelegate) {
return false;
}
}
其中在背景绘制中我们制定了canvas 的背景色,即下面这行代码:
canvas.drawColor(Color(0xFFF1F1F1), BlendMode.color);
其他代码就相对好理解了,BackgroundPainter
绘制了一个蓝色正方形,child
是一个居中的圆形图片,而 ForegroundPainter
则是在中间绘制了一个和圆形图片同等大小的,半透明的红色圆圈。于是就得到了我们想要的效果。
来源:https://juejin.cn/post/7072330519811194917


猜你喜欢
- 前言最近学习java,接触到了回调机制(CallBack)。初识时感觉比较混乱,而且在网上搜索到的相关的讲解,要么一言带过,要么说的比较单纯
- 不过在实际的工作中,很少会直接用到它。通常都是用的spring-quartz组件,直接通过配置,让spring框架来自动装配如下就是spri
- mybatis-spring:@MapperScan注解在demo: springboot+mybatis的示例中,dao层接口使用了注解@
- 本文主要讲述运行时类型、对象、线程栈和托管堆之间的相互关系,静态方法、实例方法和虚方法的区别,以及内存的分配和回收。线程栈:在一个进程中可能
- 一、前言 网上有许多的多线程断点续传操作,但总是写的很云里雾里,或者
- 本文实例讲述了Android7.0上某些PopuWindow出现显示位置不正确问题的解决方法。分享给大家供大家参考,具体如下:情景描述:在a
- 1、在build.gradle(Module)里引入依赖,然后重构(sync Now):android { ...
- 内存分配方式简介在C++中,内存分成5个区,他们分别是堆、栈、自由存储区、全局/静态存储区和常量存储区。栈:在执行函数时,函数内局部变量的存
- No ‘Access-Control-Allow-Origin‘ header is present
- [LeetCode] 144. Binary Tree Preorder Traversal 二叉树的先序遍历Given a binary
- BroadcastReceiver(广播 * ),在Android开发中,BroadcastReceiver的应用场景非常多,属于Andro
- 异常算术异常类:ArithmeticExecption空指针异常类:NullPointerException类型强制转换异常:ClassCa
- 本文通过老王和小王买车,引出设计模式中的结构型设计之桥接模式,接着说明设计型模式的概念和代码实现,为了加深理解,会说明适配器设计模式在JDB
- 观察者模式是软件设计模式中的一种,使用也比较普遍,尤其是在GUI编程中。关于设计模式的文章,网络上写的都比较多,而且很多文章写的也不错,虽然
- 本文实例讲述了C#画图之饼图折线图的实现方法,是C#程序设计中非常实用的技巧。分享给大家供大家参考。具体方法分析如下:显示图像的控件定义如下
- 最近一直在使用邮件发送功能,老是遇到问题,后面才找到,原来并不是程序问题引起的,我吧问题整出来, javax.mail.SendFailed
- 本文汇总了常用的DateTime日期类型格式化显示方法,方便读者在使用的时候参考借鉴一下。具体如下所示:1.绑定时格式化日期方法:<A
- Android的文件存储,有I/O流的方式存储,与java一样,还有一种Android自己的SharePreferences存储方法。下面看
- spring boot 使用profile来分区配置很多时候,我们项目在开发环境和生成环境的环境配置是不一样的,例如,数据库配置,在开发的时
- 目录介绍Version 1 - 非线程安全Version 2 - 简单的线程安全Version 4 - 不完全懒汉式,但不加锁的线程安全Ve