android 自定义view控件,Android 自定义View——自定义View控件

Android给我们提供了大量的View控件,但这还是远远满足不了我们的要求,有时候开发所需要的控件形式是在Android提供的控件中是不存在,这就需要我们自己去定义一个。那么如何自定义控件?

学习自定义控件,首先要先掌握Canvas类的使用。

Canvas

Canvas, 我们称之为“画布“,主要适用于绘制View的。

Canvas中提供了大量绘制图形的方法:

绘制扇形:

drawArc(RectF oval, float startAngle, float sweepAngle, boolean useCenter, Paint paint):

第一个参数RectF对象,指定扇形的区域;第二个参数是起始角度;第三个参数是旋转角度,顺时针旋转;第四个参数是是否填充,true为填充,false为不填充,也就是为一条弧线;第五个参数是绘制图形的画笔对象Paint。

RectF:

通过RectF(float left, float top, float right, float bottom)构造器创建RectF对象,我们通过下图理解各个参数的含义,RectF对象指代的就是一个矩形区域。我们通过这四个参数构建矩形区域。

a2cd59bafb7e283558993907f83a21db.png

Paint:

是绘制所有图形所用到的一个画笔,我们在稍后讲解。

drawArc(float left, float top, float right, float bottom, float startAngle, float sweepAngle, boolean useCenter, Paint paint)

这个是将扇形区域左,上,右,下边的坐标直接输入,而不是通过RectF对象。其他参数同上。

绘制圆形:

drawCircle(float cx, float cy, float radius, Paint paint)

第一、二个参数是指圆形的x, y坐标; 第三个参数是半径; 第四个参数是画笔Paint对象。

绘制直线:

drawLine(float startX, float startY, float stopX, float stopY, Paint paint)

两点确定一条直线,第一、二参数是起始点的坐标;第三、四参数是结束点的坐标;第五个参数画笔Paint对象。

drawLines(float[] pts, Paint paint)

多个点确定一条直线,第一个参数是点的数组;第二个参数是画笔Paint对象。

drawLines(float[] pts, int offset, int count, Paint paint)

绘制椭圆:

drawOval(float left, float top, float right, float bottom, Paint paint)

前四个参数是椭圆的左,上,右,下边的坐标,第五个是画笔Paint对象。

drawOval(RectF oval, Paint paint)

第一个参数是RectF对象, 第二个参数是画笔Paint对象。

绘制矩形:

drawRect(RectF rect, Paint paint)

第一个参数是RectF对象, 第二个参数是画笔Paint对象。

绘制点:

drawPoint(float x, float y, Paint paint)

第一、二个参数点的坐标,第三个参数为Paint对象。

渲染文本:

drawText(String text, float x, floaty, Paint paint)

drawText(CharSequence text, int start, int end, float x, float y, Paint paint)

drawText(char[] text, int index, int count, float x, float y, Paint paint)

drawText(String text, int start, int end, float x, float y, Paint paint)

Canvas中还给我们提供了很多绘制其他图形的方法,这里我们不在一一列举。我们来看一下Paint”画笔“。

Paint

Paint是用于绘制的画笔,Canvas就像是我们的画纸,我们需要笔才可以完成一整幅图。Paint中为我们提供了很多设置的方法(我们这里只列举常用的方法):

setARGB(int a, int r, int g, int b)

设置 Paint对象颜色,参数一为alpha透明值

setAlpha(int a)

设置alpha不透明度,范围为0~255

setAntiAlias(boolean aa)

是否抗锯齿,这个一般是都要设置的。

setColor(int color)

设置颜色,这里Android内部定义的有Color类包含了一些常见颜色定义

setTextScaleX(float scaleX)

设置文本缩放倍数,1.0f为原始

setTextSize(float textSize)

设置字体大小

setUnderlineText(booleanunderlineText)

设置下划线

setStrokeCap(Paint.Cap cap)

当画笔样式为STROKE或FILL_OR_STROKE时,设置笔刷的图形样式,如圆形样式 Cap.ROUND,或方形样式Cap.SQUARE

setSrokeJoin(Paint.Join join)

设置绘制时各图形的结合方式,如平滑效果等

自定义View

现在我们来使用Canvas类自定义一个View控件。自定义控件步骤如下:

1. 自定义View,首先定义一个MyView类继承View类。

2. 重写View的两个构造器。

View是包含四个构造器的,我们必须重写MyWidgetView(Context context, AttributeSet attrs)构造器,因为该构造器的第二个参数是与xml布局文件相联系的,如果没有重写该构造器,将不能在布局中使用该控件。这里我们重写他的两个构造器:

public MyView(Context context) {

super(context);

}

public MyView(Context context, AttributeSet attrs) {

super(context, attrs);

}

3. 重写onMeasure(int widthMeasureSpec, int heightMeasureSpec)方法,定义控件的尺寸:宽度和高度。在布局中使用该控件时会会传入控件的尺寸,只有当传入尺寸之后且调用onMesure之后,控件才会有宽度和高度。

@Override

protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

super.onMeasure(widthMeasureSpec, heightMeasureSpec);

width = getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec);

height = getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec);

setMeasuredDimension(width, height);//设置宽和高

}

重写onDraw(Canvas canvas)方法,我们在该方法中定义绘制View,当我们在Activity或其他地方使该控件时, UI主线程会调用onDraw方法绘制。

@Override

protected void onDraw(Canvas canvas) {

super.onDraw(canvas);

}

onDraw(Canvas canvas)方法中传入了一个Canvas对象,我们在定义控件时,使用Canvas绘制。

绘制时钟

这里我们通过绘制一个时钟来巩固一下自定义控件以及Canvas类的使用。

1. 定义一个MyView继承View。

2. 重写MyView(Context context, AttributeSet attrs)构造器。

3. 在重写onMeasureh和onDraw方法。

4. 在onDraw方法中绘制。

大体步骤就是这样,我们先贴代码,逐步讲解:

public class MyView extends View {

private int width;//设置高

private int height;//设置高

private Paint mPaintLine;//定义一个绘制直线的画笔

private Paint mPaintSecondLine;//定义一个绘制直线的画笔

private Paint mPaintInterCircle;//定义一个绘制圆的画笔

private Paint mPaintOutSideCircle;//定义一个绘制圆的画笔

private Paint mPaintText;//定义一个绘制文字的画笔

private Calendar mCalendar;//创建一个时间类

private static final int NEED_INVALIDATE=0X6666;

//操作UI主线程

private Handler handler = new Handler() {

@Override

public void handleMessage(Message msg) {

super.handleMessage(msg);

switch (msg.what){

case NEED_INVALIDATE:

//跟新时间

mCalendar=Calendar.getInstance();

invalidate();

sendEmptyMessageDelayed(NEED_INVALIDATE,1000);

break;

}

}

};

public MyView(Context context) {

super(context);

}

public MyView(Context context, AttributeSet attrs) {

super(context, attrs);

//初始化画直线的画笔

mPaintLine = new Paint();

mPaintLine.setAntiAlias(true);//消除锯齿

mPaintLine.setColor(Color.GRAY);//设置画笔颜色

mPaintLine.setStyle(Paint.Style.STROKE);//设置为空心

mPaintLine.setStrokeWidth(10);//设置宽度

// 初始化秒针的画笔

mPaintSecondLine = new Paint();

mPaintSecondLine.setAntiAlias(true);//消除锯齿

mPaintSecondLine.setColor(Color.GRAY);//设置画笔颜色

mPaintSecondLine.setStyle(Paint.Style.STROKE);//设置为空心

mPaintSecondLine.setStrokeWidth(7);//设置宽度

//初始化内圆的画笔

mPaintInterCircle = new Paint();

mPaintInterCircle.setAntiAlias(true);//消除锯齿

mPaintInterCircle.setColor(Color.BLACK);

mPaintInterCircle.setStyle(Paint.Style.STROKE);//设置为空心

mPaintInterCircle.setStrokeWidth(5);

//初始化外圆的画笔

mPaintOutSideCircle = new Paint();

mPaintOutSideCircle.setAntiAlias(true);//消除锯齿

mPaintOutSideCircle.setColor(Color.BLACK);

mPaintOutSideCircle.setStyle(Paint.Style.STROKE);//设置为空心

mPaintOutSideCircle.setStrokeWidth(10);

//绘制文字的画笔

mPaintText = new Paint();

mPaintText.setAntiAlias(true);//消除锯齿

mPaintText.setColor(Color.GRAY);

mPaintText.setStyle(Paint.Style.STROKE);//设置为空心

mPaintText.setTextAlign(Paint.Align.CENTER);

mPaintText.setTextSize(40);

mPaintText.setStrokeWidth(6);

//初始化日历

mCalendar = Calendar.getInstance();

//发送一个消息给UI主线程

handler.sendEmptyMessageDelayed(NEED_INVALIDATE,2000);

}

@Override

protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

super.onMeasure(widthMeasureSpec, heightMeasureSpec);

width = getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec);

height = getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec);

setMeasuredDimension(width, height);//设置宽和高

}

@Override

protected void onDraw(Canvas canvas) {

super.onDraw(canvas);

// 主线程自动调用

canvas.drawCircle(width / 2, height / 2, 300, mPaintInterCircle);

canvas.drawCircle(width / 2, height / 2, 320, mPaintOutSideCircle);

for(int i=1; i<=12;i++){

canvas.save();//保存当前状态

canvas.rotate(360 / 12 * i, width / 2, height / 2);

canvas.drawLine(width / 2, height / 2 - 300, width / 2, height / 2 - 270, mPaintLine);

canvas.drawText("" + i, width / 2, height / 2 - 240, mPaintText);

canvas.restore();//回到save()方法保存的状态

}

//绘制分针

int minute= mCalendar.get(Calendar.MINUTE);

float minuteDegree = minute/60f*360;

canvas.save();

canvas.rotate(minuteDegree, width / 2, height / 2);

canvas.drawLine(width / 2, height / 2 - 200, width / 2, height / 2 + 40, mPaintLine);

canvas.restore();

//绘制时针

int hour= mCalendar.get(Calendar.HOUR);

float hourDegree = (hour*60+minute)//(12f*60)*360;

canvas.save();

canvas.rotate(hourDegree, width / 2, height / 2);

canvas.drawLine(width / 2, height / 2 - 170, width / 2, height / 2 + 30, mPaintLine);

canvas.restore();

//绘制秒针

int second = mCalendar.get(Calendar.SECOND);

float secondDegree = second*6;//一秒是6度。

canvas.save();

canvas.rotate(secondDegree, width / 2, height / 2);

canvas.drawLine(width / 2, height / 2 - 220, width / 2, height / 2 + 50, mPaintSecondLine);

canvas.restore();

}

}

绘制两个圆形嵌套这个很简单,不用多说。然后绘制刻度,是使用了Canvas画布的旋转,这个很好理解,我们在画画的时候,有时候要画一些比较难的角度,我们都是将画板旋转而不是我们自己换角度。在绘制时钟时,我们要绘制时钟每个时间的刻度,我们可以将要绘制刻度的位置旋转到竖直方向,然后绘制。

for(int i=1; i<=12;i++){

canvas.save();//保存当前状态

canvas.rotate(360 / 12 * i, width / 2, height / 2);

canvas.drawLine(width / 2, height / 2 - 300, width / 2, height / 2 - 270, mPaintLine);

canvas.drawText("" + i, width / 2, height / 2 - 240, mPaintText);

canvas.restore();//回到save()方法保存的状态

}

然后绘制时针,分针和秒针,他们都是绘制一条线。然后通过获取当前的时间将这条线指向对得时间点,也就是偏转对得角度。这里的偏转我们依然使用画布的偏转。

以上完成后,我们的时钟就差不多完成了,但是,我们发现我们的表并没有走。实现我们绘制的时钟转动的方式就是然我们的时钟每一秒onDraw一次,这样我们的时钟正常了。onDraw是UI主线程不断调用重绘界面的,因此我们需要使用到Handler,通过发送一个消息给Handler对象,让Handler对象在每一秒重绘一次MyView控件。这里重绘不能调用onDraw()方法额,而要调用的是invalidate()方法,invalidate()方法中调用了onDraw()方法。

//操作UI主线程

private Handler handler = new Handler() {

@Override

public void handleMessage(Message msg) {

super.handleMessage(msg);

switch (msg.what){

case NEED_INVALIDATE:

//跟新时间

mCalendar=Calendar.getInstance();

invalidate();

sendEmptyMessageDelayed(NEED_INVALIDATE,1000);

break;

}

}

};

这样我们的时钟也转动了……

4607d1ef9c16438bdd219c31042b9319.gif

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

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

相关文章

解读容器的 2020:寻找云原生的下一站

简介&#xff1a; “云原生”到底是什么&#xff1f;它就是容器和 Kubernetes 吗&#xff1f;虚拟机是云原生的吗&#xff1f;…… 2020 年注定是不凡的。它在阴霾中开始&#xff0c;在惊叹中结束&#xff0c;也让未来变得更加扑朔迷离。那么&#xff0c;容器与云原生的 2020 年…

如何用好云的弹性

简介&#xff1a; 如何用好云的弹性 1. 弹性为什么这么重要 做好弹性让IT能力轻松跟上用户的业务发展&#xff0c;做到多、快、好、省。 多&#xff1a;选择多&#xff0c;可以全球建站、机型选择也多、配套云服务也多。 快&#xff1a;部署快&#xff0c;自建IDC的建设时长以…

android笔试添加自定义服务,Android之Listview(item为单选题)自定义adapter,像考试时前面的10几道单选题的实现...

用于展现重复性的东西&#xff0c;Listview比较好用&#xff0c;看了别人的自定义Adapter(item是EditText&#xff0c;能够很好地获取到每一个item的EditText值)。又由于在做项目的需要&#xff0c;故特制了一个item包含RadioGroup的Listview的自定义Adapter。主要功能&#xf…

实现工具自由!开源的桌面工具箱

来源: HelloGitHubRubick,因为开源所有更自由在一切开始之前&#xff0c;首先要致敬 uTools&#xff01;如果没有它就没有 Rubick。大家好&#xff0c;我是“拉比克”&#xff08;Rubick&#xff09;项目的作者木偶。我做的 Rubick 是一款基于 Electron 的开源桌面工具箱&#…

测试一年多,上线就崩溃!微服务到底应该怎么测试?

简介&#xff1a; 只有了解风险&#xff0c;才能及时应对&#xff0c;保障服务高可用。 不久前&#xff0c;也就是11月16日&#xff0c;澳大利亚交易所&#xff08;Australian Securities Exchange, ASX&#xff09;上线了一个新的交易系统&#xff0c;但因为出现故障而被迫关闭…

阿里云熊鹰:基于融合、协同系统的边缘云原生架构演进和实践

简介&#xff1a; 云原生和边缘计算是近两年都非常火的技术话题了&#xff0c;在第十届云计算标准和应用大会上&#xff0c;阿里云高级技术专家熊鹰分享了《基于融合、协同系统的边缘云原生架构演进和实践》&#xff0c;希望通过介绍现在阿里云在边缘计算和边缘云原生这些技术领…

漫画:什么是 “建造者模式” ?

作者&#xff1a;东风玖哥来源&#xff1a; 程序员小灰————— 第二天 —————————————————首先&#xff0c;我们来定义一个Product类&#xff1a;public class Product {ArrayList<String> parts new ArrayList<String>();public void add(S…

阿里云云效何勉:云原生是“精益实践”的最佳助力

简介&#xff1a; 1月15日&#xff0c;国内知名“精益产品开发”研究和实践者、阿里云云效资深技术专家何勉在阿里云《云计算情报局》线上直播栏目中&#xff0c;分享其对研发新模式的最新思考&#xff0c;提出“下一代精益开发方法”&#xff0c;助力企业在研发效能上提升10倍…

开发效率提升15倍!批流融合实时平台在好未来的应用实践

简介&#xff1a; 本文由好未来资深数据平台工程师毛祥溢分享&#xff0c;主要介绍批流融合在教育行业的实践。内容包括两部分&#xff0c;第一部分是好未来在做实时平台中的几点思考&#xff0c;第二部分主要分享教育行业中特有数据分析场景。 1.背景介绍 好未来介绍 好未来是…

那些公司都配不上我,所以我选择创业

【CSDN 编者按】她&#xff0c;一个89年的农村姑娘&#xff0c;从种蘑菇到卖煤球&#xff0c;再到敲代码做云原生&#xff0c;成为企业创始人&#xff0c;一路走来她都经历了哪些困难与挑战&#xff0c;对于新生代程序员又有哪些建议&#xff1f;让我们一起来看看她是怎么说的。…

如何跑通第一个 SQL 作业

简介&#xff1a; 本文由阿里巴巴技术专家周凯波&#xff08;宝牛&#xff09;分享&#xff0c;主要介绍如何跑通第一个SQL。 一、SQL的基本概念 1.SQL 分类 SQL分为四类&#xff0c;分别是数据查询语言&#xff08;DQL&#xff09;、数据操纵语言&#xff08;DML&#xff09…

云原生DevOps的5步升级路径

简介&#xff1a; 究竟什么是云原生DevOps呢&#xff1f;我们认为&#xff1a;云原生DevOps是充分利用云原生基础设施&#xff0c;基于微服务/无服务架构体系和开源标准&#xff0c;语言和框架无关&#xff0c;具备持续交付和智能自运维能力&#xff0c;从而做到比传统DevOps更…

数据创新的四个陷阱

简介&#xff1a; 数据的重要性在当今已经无需在多言&#xff0c;所有的企业都意识到数据的重要性&#xff0c;都希望利用数据来驱动业务的发展。但是&#xff0c;很多企业信息化管理者依然存在对于数据智能&#xff0c;数据驱动的一些误解&#xff0c;这些误解会让企业的数据利…

Parallels 发布 Desktop 17版本,支持 Windows 11 和 macOS Monterey

Parallels Desktop 17 亮点速揽&#xff1a;性能提升&#xff0c;对图像效果加以改进、增强了 Windows 游戏体验&#xff0c;同时是全球首个在搭载 Apple M1 芯片的 Mac 上运行的 macOS Monterey 虚拟机&#xff0c;带来更为无缝的跨平台工作体验。 编辑 | 宋慧 头图 | Paralle…

如何将实时计算 Flink 与自身环境打通

简介&#xff1a; 如何使用实时计算 Flink 搞定数据处理难题&#xff1f;实时计算 Flink 客训练营产品、技术专家齐上阵&#xff0c;从 Flink的发展、 Flink 的技术原理、应用场景及行业案例&#xff0c;到开源Flink功能介绍和实时计算 Flink 优势详解&#xff0c;现场实操&…

一文知晓浪潮云海OS在SPEC Cloud测试中的调优实践!

日前&#xff0c;SPEC&#xff08;Standard Performance Evaluation Corporation&#xff0c;即国际标准性能评测组织&#xff09;公布了最新 Cloud IaaS 2018 Benchmark 测试成绩&#xff0c;在同规模测试场景下浪潮数据核心产品浪潮云海OS再次刷新世界纪录&#xff0c;性能得…

阿里云 EMR Delta Lake 在流利说数据接入中的架构和实践

简介&#xff1a; 为了消灭数据孤岛&#xff0c;企业往往会把各个组织的数据都接入到数据湖以提供统一的查询或分析。本文将介绍流利说当前数据接入的整个过程&#xff0c;期间遇到的挑战&#xff0c;以及delta在数据接入中产生的价值。 背景 流利说目前的离线计算任务中&…

怎么提升写代码的能力

简介&#xff1a; 对于程序员而言&#xff0c;我始终认为代码是展现能力的关键&#xff0c;一个优秀程序员写的代码&#xff0c;和一个普通程序员写的代码是很容易看出差别的&#xff0c;代码作为程序员的硬实力和名片的展示&#xff0c;怎么提升写代码的能力始终是一个关键的话…

发力LPWAN 升哲打磨数智城市物联网通信之“芯”

8月上旬&#xff0c;随着多项物联网芯片与通信领域技术发明专利证书的下发&#xff0c;升哲科技&#xff08;SENSORO&#xff09;已在低功耗广域物联网&#xff08;LPWAN&#xff09;及相关领域拥有近百项独家专利&#xff0c;突破国外专利封锁实现国产、自主、可控。这些专利技…

android studio证件照代码,Android 修图(换证件照背景,污点修复)

背景前段时间的一个周末&#xff0c;一个女生让我帮她换一下他的证件照背景&#xff0c;我又没带电脑。我又不好意思拒接&#xff0c;怎么办呢&#xff1f;应用商店下载一个证件照换背景的APP&#xff0c;瞬间换完&#xff0c;我正准备保存时&#xff0c;跳出来一个支付框&…