Android高级UI --- canvas

news2024/11/13 8:59:14

前言

我们先来聊聊,在我们生活中如何绘制一张如下的图。

我们需要两样东西来绘制:

  1. 一张纸(Android 中的 canvas):用来承载我们绘制的内容。
  2. 一支笔(Android 中的 paint):负责绘制内容的轨迹。

有了这两样,我们就能在现实的场景中开始绘制了。

1、绘图坐标系

在 Android 的体系中,我们所谓的 “笔Paint” 和 “纸Canvas” 都是由App持有的,所以我们在绘制时就出现一个问题:我们怎么“告诉”App,确定我们想要绘制图形的落笔点?当然需要一个坐标系来进行交流。

这个 坐标系 便是我们经常所说的 绘图坐标系。初始状态下,Canvas的左上角为原点,此时我们想画图中的红点,就非常的容易,只需要“告诉” App 在坐标(200,500)处画一个红点,这就达到了画图的效果了。所以我们可以明确的一点是 我们所有的画图坐标都是根据原点进行确定。

所以我们可以移动原点,达到整体坐标点的移动,例如还是画刚才的红点,我们可以先将原点水平移动100,垂直移动400。然后在进行绘制,这时红点的坐标就变为(100,100),具体如下图所示。

经过上面的简单讲述,我们可以知道,绘图过程中,我们的绘图坐标永远是跟随当前的原点,而画布的原点可以进行移动。

2、视图坐标系

理论上 Canvas 这张纸是没有边界的,但是我们的手机屏幕是有界的。我们可以理解为我们透过一个方形的洞(手机屏幕)看一张巨画(Canvas)。

又存在一个问题了,因为刚才的移动,我们是移动的原点,也就是说我们的画布是静止不动的,只是落笔点一直在变动,这就导致我们绘制的图对于用户来说是看不全的,所以我们需要进行移动 方形的洞 来查看这幅画。

可以通过移动 Screen框来查看这幅画,而这里又出现了一个坐标系,这一坐标系则为 视图坐标系,通过 scrollerTo 和 scrollerBy 进行移动该Screen框,正数则往正半轴,负数则往负半轴。

3、小结

自定义控件中存在两个坐标系需要明确,用一句话总结如下:

  1. 绘图坐标系:决定我们的绘制的坐标
  2. 视图坐标系:决定我们所看到的画布范围

=========================================================================

介绍Paint

绘制的基本形状由Canvas确定,但绘制出来的颜色,具体效果则由Paint确定

例子:

mPaint.setStyle(Paint.Style.FILL);  //设置画笔模式为填充

画笔有三种模式,如下:

STROKE                //描边
FILL                  //填充
FILL_AND_STROKE       //描边加填充

区分三者效果我们做如下实验:

Paint paint = new Paint();
paint.setColor(Color.BLUE);
paint.setStrokeWidth(40);     //为了实验效果明显,特地设置描边宽度非常大

// 描边
paint.setStyle(Paint.Style.STROKE);
canvas.drawCircle(200,200,100,paint);

// 填充
paint.setStyle(Paint.Style.FILL);
canvas.drawCircle(200,500,100,paint);

// 描边加填充
paint.setStyle(Paint.Style.FILL_AND_STROKE);
canvas.drawCircle(200, 800, 100, paint);

效果:

Canvas常用方法表

操作类型相关API备注
绘制颜色drawColor, drawRGB, drawARGB使用单一颜色填充整个画布
绘制基本形状drawPoint, drawPoints, drawLine, drawLines, drawRect, drawRoundRect, drawOval, drawCircle, drawArc依次为 点、线、矩形、圆角矩形、椭圆、圆、圆弧
绘制图片drawBitmap, drawPicture绘制位图和图片
绘制文本drawText, drawPosText, drawTextOnPath依次为 绘制文字、绘制文字时指定每个文字位置、根据路径绘制文字
绘制路径drawPath绘制路径,绘制贝塞尔曲线时也需要用到该函数
顶点操作drawVertices, drawBitmapMesh通过对顶点操作可以使图像形变,drawVertices直接对画布作用、 drawBitmapMesh只对绘制的Bitmap作用
画布剪裁clipPath, clipRect设置画布的显示区域
画布快照save, restore, saveLayerXxx, restoreToCount, getSaveCount依次为 保存当前状态、 回滚到上一次保存的状态、 保存图层状态、 回滚到指定状态、 获取保存次数
画布变换translate, scale, rotate, skew依次为 位移、缩放、 旋转、错切
Matrix(矩阵)getMatrix, setMatrix, concat实际上画布的位移,缩放等操作的都是图像矩阵Matrix, 只不过Matrix比较难以理解和使用,故封装了一些常用的方法。

canvas绘制基本图形

绘制颜色:

绘制颜色是填充整个画布,常用于绘制底色。

canvas.drawColor(Color.BLUE); //绘制蓝色

创建画笔:

要想绘制内容,首先需要先创建一个画笔,如下:

// 1.创建一个画笔
private Paint mPaint = new Paint();

// 2.初始化画笔
private void initPaint() {
    mPaint.setColor(Color.BLACK);       //设置画笔颜色
    mPaint.setStyle(Paint.Style.FILL);  //设置画笔模式为填充
    mPaint.setStrokeWidth(10f);         //设置画笔宽度为10px
}

// 3.在构造函数中初始化
public SloopView(Context context, AttributeSet attrs) {
   super(context, attrs);
   initPaint();
}

在创建完画笔之后,就可以在Canvas中绘制各种内容了。

绘制点:

可以绘制一个点,也可以绘制一组点,如下:

canvas.drawPoint(200, 200, mPaint);     //在坐标(200,200)位置绘制一个点
canvas.drawPoints(new float[]{          //绘制一组点,坐标位置由float数组指定
      500,500,
      500,600,
      500,700
},mPaint);

坐标原点默认在左上角,水平向右为x轴增大方向,竖直向下为y轴增大方向。

绘制直线:

绘制直线需要两个点,初始点和结束点,同样绘制直线也可以绘制一条或者绘制一组:

// 在坐标(300,300)(500,600)之间绘制一条直线
canvas.drawLine(300,300,500,600,mPaint);  
// 绘制一组线 每四数字(两个点的坐标)确定一条线 
canvas.drawLines(new float[]{             
    100,200,200,200,
    100,300,200,300
},mPaint);

绘制矩形:

我们都知道,确定一个矩形最少需要四个数据,就是对角线的两个点的坐标值,这里一般采用左上角和右下角的两个点的坐标。

关于绘制矩形,Canvas提供了三种重载方法,第一种就是提供四个数值(矩形左上角和右下角两个点的坐标)来确定一个矩形进行绘制。 其余两种是先将矩形封装为Rect或RectF(实际上仍然是用两个坐标点来确定的矩形),然后传递给Canvas绘制,如下:

// 第一种
canvas.drawRect(100,100,800,400,mPaint);

// 第二种
Rect rect = new Rect(100,100,800,400);
canvas.drawRect(rect,mPaint);

// 第三种
RectF rectF = new RectF(100,100,800,400);
canvas.drawRect(rectF,mPaint);

为什么会有Rect和RectF两种?两者有什么区别吗?

两者最大的区别就是精度不同,Rect是int(整形)的,而RectF是float(单精度浮点型)的。除了精度不同,两种提供的方法也稍微存在差别。

绘制圆角矩形:

绘制圆角矩形也提供了两种重载方式,如下:

// 第一种
RectF rectF = new RectF(100,100,800,400);
canvas.drawRoundRect(rectF,30,30,mPaint);

// 第二种
canvas.drawRoundRect(100,100,800,400,30,30,mPaint);

 上面两种方法绘制效果也是一样的,但鉴于第二种方法在API21的时候才添加上,所以我们一般使用的都是第一种。

绘制椭圆:

相对于绘制圆角矩形,绘制椭圆就简单的多了,因为他只需要一个矩形作为参数:

// 第一种
RectF rectF = new RectF(100,100,800,400);
canvas.drawOval(rectF,mPaint);

// 第二种
canvas.drawOval(100,100,800,400,mPaint);

同样,以上两种方法效果完全一样,但一般使用第一种。

绘制圆:

绘制圆形也比较简单, 如下:

canvas.drawCircle(500,500,400,mPaint);  // 绘制一个圆心坐标在(500,500),半径为400 的圆。

绘制圆形有四个参数,前两个是圆心坐标,第三个是半径,最后一个是画笔。

绘制圆弧:

先看方法:

// 第一种
public void drawArc(@NonNull RectF oval, float startAngle, float sweepAngle, boolean useCenter, @NonNull Paint paint){}
    
// 第二种
public void drawArc(float left, float top, float right, float bottom, float startAngle,
            float sweepAngle, boolean useCenter, @NonNull Paint paint) {}

从上面可以看出,相比于绘制椭圆,绘制圆弧还多了三个参数:

startAngle  // 开始角度
sweepAngle  // 扫过角度
useCenter   // 是否使用中心

来前两个参数(startAngle, sweepAngel)的作用,就是确定角度的起始位置和扫过角度。

useCenter   使用了中心点之后绘制出来类似于一个扇形,而不使用中心点则是圆弧起始点和结束点之间的连线加上圆弧围成的图形。

绘制不规则多边形

使用Path类来绘制不规则多边形。

例子:

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Path;
import android.util.AttributeSet;
import android.view.View;
 
public class CustomPolygonView extends View {
 
    private Path polygonPath = new Path();
    private Paint polygonPaint = new Paint();
 
    public CustomPolygonView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }
 
    private void init() {
        polygonPaint.setAntiAlias(true);
        polygonPaint.setColor(0xFF0000FF); // 蓝色填充
        polygonPaint.setStyle(Paint.Style.FILL); // 设置填充样式
    }
 
    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
 
        // 创建不规则多边形路径
        polygonPath.reset();
        polygonPath.moveTo(100, 50); // 第一个顶点
        polygonPath.lineTo(200, 50); // 第二个顶点
        polygonPath.lineTo(150, 100); // 第三个顶点
        polygonPath.lineTo(100, 150); // 第四个顶点
        polygonPath.close(); // 首尾连接关闭路径
 
        // 绘制多边形
        canvas.drawPath(polygonPath, polygonPaint);
    }
}

我们创建了一个自定义View,在其onDraw方法中使用Path绘制了一个有四个顶点的不规则多边形。您可以通过调整polygonPath的顶点来创建不同形状的多边形。

绘制一串点路径虚线

要使用Canvas绘制一串点路径上的虚线,可以使用PaintsetPathEffect方法,并提供一个DashPathEffect对象。

例子:

import android.graphics.Canvas;
import android.graphics.DashPathEffect;
import android.graphics.Paint;
import android.graphics.Path;
import android.view.View;
 
public class DashedLineView extends View {
 
    private Paint paint;
    private Path path;
 
    public DashedLineView(Context context) {
        super(context);
        init();
    }
 
    private void init() {
        paint = new Paint();
        paint.setColor(Color.BLACK);
        paint.setStrokeWidth(5f);
        paint.setStyle(Paint.Style.STROKE);
        // 设置虚线效果,参数分别为:“点的间隔”,“点的长度”,“总的长度”
        paint.setPathEffect(new DashPathEffect(new float[]{10f, 5f}, 0f));
 
        path = new Path();
    }
 
    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        // 定义路径,这里以一个简单的直线为例
        path.reset();
        path.moveTo(10, 10);
        path.lineTo(300, 10);
 
        // 绘制虚线
        canvas.drawPath(path, paint);
    }
}

DashPathEffect被设置为每10个点一个间隔,每个点5个单位长度,总长度为50个单位。这将导致虚线由5个黑点和5个空白点组成的序列。你可以根据需要调整DashPathEffect构造函数的参数来改变虚线的样式。

画布的操作:

相关操作简要介绍
save保存当前画布状态
restore回滚到上一次保存的状态
translate相对于当前位置位移
rotate旋转

tips:

自定义View流程梳理一遍(确定各个步骤应该做的事情):

步骤关键字作用
1构造函数初始化(初始化画笔Paint)
2onMeasure测量View的大小(暂时不用关心)
3onSizeChanged确定View大小(记录当前View的宽高)
4onLayout确定子View布局(无子View,不关心)
5onDraw实际绘制内容(绘制饼状图)
6提供接口提供接口(提供设置数据的接口)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2075693.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

SpringBoot3核心特性-Web开发

目录 传送门前言一、WebMvcAutoConfiguration原理1、生效条件2、效果3、WebMvcConfigurer接口4、静态资源规则源码5、EnableWebMvcConfiguration 源码6、为什么容器中放一个WebMvcConfigurer就能配置底层行为7、WebMvcConfigurationSupport 二、Web场景1、自动配置2、默认效果 …

自动化构建工具Gulp

第三方模块-Gulp 解释 基于node平台开发的前端构建工具 将机械化操作编写成任务,由一条命令来触发执行,提高开发效率 主要能做什么 项目上线:html、css、js文件的压缩合并语法转换:es6、less等语言的转化公共文件抽离修改文件…

替代液压比例放大器首选

比例阀放大器的选用应考虑诸多因素,如系统需求、放大器的兼容性、调节性、附加功能、安全特性、供应商支持和环境适应性等。 系统性能要求明确 压力与流量: 根据液压系统所需的压力和流量来确定放大器的性能指标,以确保比例阀能得到充分的功率支持。 …

2024/8/26 英语每日一段

Apple and Google have had nearly unchecked power over mobile apps in ways that raise prices for some of what you buy, block you from trying clever ideas, push app makers to do scuzzy things to make money, and impose Apple’s and Google’s wishes on all us.…

如何用Java SpringBoot+Vue开发高效OA办公管理系统

✍✍计算机毕业编程指导师 ⭐⭐个人介绍:自己非常喜欢研究技术问题!专业做Java、Python、微信小程序、安卓、大数据、爬虫、Golang、大屏等实战项目。 ⛽⛽实战项目:有源码或者技术上的问题欢迎在评论区一起讨论交流! ⚡⚡ Java、…

三品船舶PLM解决方案详情 三品PLM软件在船舶制造行业应用优势

自2024年起,船舶行业PLM(产品全生命周期管理)技术步入关键发展阶段。国产化工业软件领域积极倡导生态合作,推广统一技术底座下的合作开发模式,整合国内外成熟的工业软件技术与应用资源,旨在全面提升国内船舶…

【Bigtop】利用Bigtop3.2.0编译大数据组件RPM包

利用Bigtop3.2.0编译大数据组件RPM包 前言正文Mvn本地目录的修改FlinkKafkagrgit版本手动准备gradle的文件 前言 原文参考:Bigtop 从0开始 参考了上述的博文自己尝试了编译组件,过程还是遇到很多问题,一一记录,方便后人。 Bigt…

【方案】智慧排水系统解决方案(doc原件)

一、项目建设目标 二、项目主要内容 三、项目建设方案 1.GIS管理子系统 (1) 数据管理和访问 (2) 地图操作功能 (3) 地图查询定位功能 (4) 其他功能 2.工程管理子系统 (1&…

免费分享!算法备案流程以及所需资料

免费分享!算法备案流程以及所需资料 在国内,随着《生成式人工智能服务管理暂行办法》的出台,这一规定明确指出,任何面向中国公众提供具备舆论影响力或社会动员潜力的生成式AI服务,都必须经过严格的算法备案程序。 这就…

有关于算法备案的五大误区

有关于算法备案的五大误区 在这个数据为王的时代,算法已然成为推动社会前进的隐形巨轮。从搜索框中的每一次点击,到购物车里的每一件商品推荐,再到朋友圈里刷屏的动态,算法的身影无处不在,悄无声息地编织着我们的数字生…

云HIS系统,利用云计算平台的技术优势,建立统一的健康档案和电子存储平台,实现医疗数据共享与交换

云HIS系统源码,医院信息管理系统源码,医疗云HIS源码 基于云计算技术的B/S架构的HIS系统,为医疗机构提供标准化的、信息化的、可共享的医疗信息管理系统,实现医患事务管理和临床诊疗管理等标准医疗管理信息系统的功能。系统利用云计…

项目经理都在用的五款项目管理工具(建议收藏)

在项目管理中,选择合适的工具对于确保项目成功至关重要。 以下是几款备受项目经理青睐的项目管理软件: 1、进度猫 进度猫是一款基于云端的项目管理工具,以其轻量级、直观和易操作的特点受到项目经理的青睐。它提供了丰富的功能和灵活的操…

如何安装和高级 AMP for WP

当 WordPress 是支持 AMP 的 WEB 站点时,主要通过两个插件支持 AMP。 一个是AMP插件。 这个插件也参与谷歌的开发,并被确认为AMP项目的官方插件。 我最初也安装了这个AMP插件,但我不知道是否能够共存的常规网站和AMP兼容网站,很难…

这只猴子一夜赚了15亿?

通过《黑神话》思考低代码平台的发展 《黑神话》的设计分析 《黑神话》作为一款大型3A游戏,其优化工作主要聚焦于提升游戏性能、增强画面表现以及提升玩家体验。这包括但不限于以下几个方面: 技术突破:游戏采用了前沿的技术手段&#xff0…

AppInventor2 文本输入框(TextBox)已支持文本变更事件,非常便于实时处理输入的内容

自 v2.70开始,文本输入框加入了文本变更事件: 效果如下: 文本事件.gif (99.17 KB, 下载次数: 3) 下载附件 昨天 19:57 上传 同理,密码输入框组件也是一样的。 原文:AppInventor2 文本输入框(TextBox&a…

用Python实现9大回归算法详解——08. 随机森林回归算法

1. 随机森林回归的基本概念 随机森林回归(Random Forest Regression)是一种集成学习方法,基于多棵决策树的组合来进行预测。它通过引入随机性来构建多棵独立的决策树,并将这些树的预测结果进行平均,从而提升模型的泛化…

streeapptest 工具编译看 + 测试rk3568

首先来了解一下 stressappteset 网上的资料 压力测试不就是 内存的接口测试吗? 网上找了些资料,基本没有这个工具对于 磁盘网络的测试。 我的理解,压力测试应该指的就是 CPU内存的测试吧。 然后是 关于这个 软件的编译。 首先是下载 git c…

避雷!Springer、Cell等出版社旗下17本SCI/SSCI被剔除,含3本on hold期刊!

2024年8月19日,科睿唯安本年度第八次更新Web of Science核心期刊目录。 图片来源:科睿唯安 与上次更新(2024年7月)相比,此次更新后的SCIE、SSCI期刊目录共17本期刊发生变动,详情如下: 图片来源…

用ComfyUI打造一键换装神器,轻松搭建本地工作流!

前言 最近快手推出了一个一键换装的模型,还原度还挺高的,效果也很不错,于是自己上手用ComfyUI也搭建了一套这样的工作流,练练手,搭建出来之后发现效果也还挺不错的,分享给大家: 我们先来看看快…

基于插件机制、SPI与事件驱动的系统设计

时间:2024年08月26日 作者:小蒋聊技术 邮箱:wei_wei10163.com 微信:wei_wei10 音频地址:https://xima.tv/1_F4V6FW?_sonic0 希望大家帮个忙!如果大家有工作机会,希望帮小蒋内推一下,小蒋希…