Android 自定义控件(一)
本文用一个简单的例子来说明一下自定义控件的步骤实现,自定义控件有几种实现类型,分别为继承自view完全自定义,继承现有的
控件实现特定效果,继承viewgroup实现布局类等;
本文研究的是继承自view完全自定义控件、下面继承view来实现一个简单的ImageView
步骤:
1、继承自view创建自定义控件
2、如果有需要的自定义view属性,在values/attrs.xml中定义属性集
3、在xml中引入命名控件、设置属性
4、在代码中读取xml中的属性,初始化视图
5、测量视图大小
6、绘制视图内容
示例代码如下
首先继承自view创建自定义控件
package com.jiao.simpleimageview.view; import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.PixelFormat;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.View; import com.jiao.simpleimageview.R; /**
* Created by jiaocg on 2016/3/22.
*/
public class SimpleImageView extends View {
private Paint mBitmapPaint;
private Drawable mDrawable;
private int mWidth;
private int mHight; public SimpleImageView(Context context) {
this(context, null);
} public SimpleImageView(Context context, AttributeSet attrs) {
super(context, attrs); //根据属性初始化
initAttrs(attrs);
mBitmapPaint = new Paint();
mBitmapPaint.setAntiAlias(true);//抗锯齿
} //读取xml中定义的属性 初始化视图
private void initAttrs(AttributeSet attrs) {
if (attrs != null) { TypedArray array = null;
//获取我们在attr文件中定义的属性集合
array = getContext().obtainStyledAttributes(attrs, R.styleable.SimpleImageView);
//根据图片id获取到drawable
mDrawable = array.getDrawable(R.styleable.SimpleImageView_src);
measureDrawable();
}
} //测量视图大小
private void measureDrawable() { if (mDrawable == null)
throw new RuntimeException("Drawable不能为空"); mWidth = mDrawable.getIntrinsicWidth();
mHight = mDrawable.getIntrinsicHeight();
} //测量视图大小
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
setMeasuredDimension(mWidth, mHight);
} //绘制视图内容
@Override
protected void onDraw(Canvas canvas) {
if (mDrawable == null) {
return;
}
canvas.drawBitmap(drawableToBitmap(mDrawable), getLeft(), getTop(), mBitmapPaint);
} // drawable 转换成bitmap
private Bitmap drawableToBitmap(Drawable drawable) {
int width = mWidth;
int height = mHight;
Bitmap.Config config = drawable.getOpacity() != PixelFormat.OPAQUE ? Bitmap.Config.ARGB_8888 : Bitmap.Config.RGB_565;// 取drawable的颜色格式
Bitmap bitmap = Bitmap.createBitmap(width, height, config);// 建立对应bitmap
Canvas canvas = new Canvas(bitmap);// 建立对应bitmap的画布
drawable.setBounds(0, 0, width, height);
drawable.draw(canvas);// 把drawable内容画到画布中
return bitmap;
}
}
定义在values/arrt.xml中的属性代码
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="SimpleImageView"> <attr name="src" format="integer" />
</declare-styleable> </resources>
只定义了一个src的整形属性
使用我们自定义的ImageView控件
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:img="http://schemas.android.com/apk/res/com.jiao.simpleimageview"
android:layout_width="match_parent"
android:layout_height="match_parent"> <com.jiao.simpleimageview.view.SimpleImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
img:src="@mipmap/main_pic"> </com.jiao.simpleimageview.view.SimpleImageView> </RelativeLayout>
注意:在使用自定义属性时,我们需要将该属性所在的命名控件引入到xml中,命名控件实际上就是该工程的包名,如上述代码标亮部分
xmlns:名字="http://schemas.android.com/apk/res/应用包名" 运行效果如下:
以上是简单的实现了一个ImageView控件的功能,但是还不够完善,因为控件的大小等于图片的实际大小,我们应该
让控件更灵活可以实现match_parent、warp_content、或者用户指定宽高,要想实现这样的功能我们先来理解一个概念
我们自定义的控件在绘制的时候回调用OnMeasure()方法,该方法接受两个参数:widthMeasureSpec和heightMeasureSpec
这两个值用来确定视图的大小和模式,MeasureSpec的值是由specSize和specMode共同组成,其中specSize是大小specMode是
规格,下面说一下specMode的三种规格:
1、EXACTLY:match_parent模式,父视图希望子视图的大小应该是由specSize来决定的,可以是任意大小或者match_parent
2、AT_MOST:warp_content模式,子视图最多只能是specSize指定的大小,并且肯定不能超过specSize的大小
3、UNSPECIFIED:没有任何限制,可以任意设置,一般不用
通过以上的分析我们可以知道,在我们自定义控件测量的时候,我们就可以通过这两个参数:widthMeasureSpec和heightMeasureSpec
来得知控件的大小和规格因此我们只需要在代码中进行判断就可以更灵活的控制控件的大小,具体代码如下:
只贴出了关键代码,就是在以上代码中进行了修改,只修改了OnMeasure()方法中的逻辑
//测量视图大小
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// setMeasuredDimension(mWidth, mHight); //根据widthMeasureSpec的值来获取控件的显示模式和宽度
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int widthSize = MeasureSpec.getSize(widthMeasureSpec); //根据heightMeasureSpec的值来获取控件的显示模式和高度
int hightMode = MeasureSpec.getMode(heightMeasureSpec);
int hightSize = MeasureSpec.getSize(heightMeasureSpec); setMeasuredDimension(measureWidth(widthMode, widthSize), measureHight(hightMode, hightSize));
} private int measureWidth(int mode, int width) {
switch (mode) {
case MeasureSpec.UNSPECIFIED://未定义模式 一般不用
case MeasureSpec.AT_MOST://warp_content模式
break;
case MeasureSpec.EXACTLY://match_parent模式或指定大小时的模式
mWidth = width;
break;
} return mWidth;
} private int measureHight(int mode, int hight) {
switch (mode) {
case MeasureSpec.UNSPECIFIED://未定义模式 一般不用
case MeasureSpec.AT_MOST://warp_parent模式
break;
case MeasureSpec.EXACTLY://match_parent模式或指定大小时的模式
mHight = hight;
break;
}
return mHight;
}
首先我们通过OnMeasure方法中的两个参数来获取控件的大小和规格,然后我们根据大小和规格知道用户想要什么样
大小的控件,通过measureWidth和measureHight两个方法根据控件的规格,从而设置控件的大小;
以下分别是warp_content 120*180 match_parent的三种效果示意图:



Android 自定义控件(一)的更多相关文章
- Android自定义控件之自定义ViewGroup实现标签云
前言: 前面几篇讲了自定义控件绘制原理Android自定义控件之基本原理(一),自定义属性Android自定义控件之自定义属性(二),自定义组合控件Android自定义控件之自定义组合控件(三),常言 ...
- Android自定义控件之自定义组合控件
前言: 前两篇介绍了自定义控件的基础原理Android自定义控件之基本原理(一).自定义属性Android自定义控件之自定义属性(二).今天重点介绍一下如何通过自定义组合控件来提高布局的复用,降低开发 ...
- Android自定义控件之自定义属性
前言: 上篇介绍了自定义控件的基本要求以及绘制的基本原理,本篇文章主要介绍如何给自定义控件自定义一些属性.本篇文章将继续以上篇文章自定义圆形百分比为例进行讲解.有关原理知识请参考Android自定义控 ...
- Android自定义控件之基本原理
前言: 在日常的Android开发中会经常和控件打交道,有时Android提供的控件未必能满足业务的需求,这个时候就需要我们实现自定义一些控件,今天先大致了解一下自定义控件的要求和实现的基本原理. 自 ...
- Android自定义控件1
概述 Android已经为我们提供了大量的View供我们使用,但是可能有时候这些组件不能满足我们的需求,这时候就需要自定义控件了.自定义控件对于初学者总是感觉是一种复杂的技术.因为里面涉及到的知识点会 ...
- 一起来学习Android自定义控件1
概述 Android已经为我们提供了大量的View供我们使用,但是可能有时候这些组件不能满足我们的需求,这时候就需要自定义控件了.自定义控件对于初学者总是感觉是一种复杂的技术.因为里面涉及到的知识点会 ...
- [Xamarin.Android] 自定义控件
[Xamarin.Android] 自定义控件 前言 软件项目开发的过程中,免不了遇到一些无法使用内建控件就能满足的客户需求,例如:时速表.折线图...等等.这时开发人员可以透过自定义控件的方式,为项 ...
- android自定义控件实现TextView按下后字体颜色改变
今天跟大家分享一下Android自定义控件入门,先介绍一个简单的效果TextView,按下改变字体颜色,后期慢慢扩展更强大的功能 直接看图片 第一张是按下后截的图,功能很简单, ...
- android 自定义控件(初篇)
android 自定义控件 在写UI当中很多时候会用到自定义的控件,其实自定义控件就像是定义一个类进行调用就OK了.有些相关的感念可以查看API 下面就用个简单的例子来说明自定义控件: public ...
- Android自定义控件:进度条的四种实现方式(Progress Wheel的解析)
最近一直在学习自定义控件,搜了许多大牛们Blog里分享的小教程,也上GitHub找了一些类似的控件进行学习.发现读起来都不太好懂,就想写这么一篇东西作为学习笔记吧. 一.控件介绍: 进度条在App中非 ...
随机推荐
- 让sublime实现js控制台(前提是安装了nodejs)
步骤: 1.找到tools-->build system-->new build system 2.输入 { "cmd": ["D://nodejs/node ...
- win10 设置 计算机/此电脑/我的电脑 图标到桌面上
桌面上右键--个性化 选择右边的 主题选项 然后点击 桌面图标设置 勾选计算机 图标 需要什么图标就勾选哪个就行了 然后点击 确定 这样就可以了
- AES加密类
代码: using System; using System.IO; using System.Security.Cryptography; using System.Text; namespace ...
- SQL_递归查询(复杂查询示例)
需求: 一篇文章里有很多评论,每个评论又有很多回复评论,要求: 页面将文章展示出来,且文章的主评论按照评论时间分页展示,回复评论的评论完全展示在每个主评论下面,且按照回复时间排序 最终查询结果SQL查 ...
- java的if else语句入门
条件语句,是程序中根据条件是否成立进行选择执行的一类语句,这类语句在实际使用中,难点在于如何准确的抽象条件.例如实现程序登录功能时,如果用户名和密码正确,则进入系统,否则弹出“密码错误”这样的提示框等 ...
- 15天玩转redis —— 第六篇 有序集合类型
今天我们说一下Redis中最后一个数据类型 “有序集合类型”,回首之前学过的几个数据结构,不知道你会不会由衷感叹,开源的世界真好,写这 些代码的好心人真的要一生平安哈,不管我们想没想的到的东西,在这个 ...
- UML - 类图
在UML类图中,有以下几种常见关系: 泛化 - Generalization "is-a",继承关系,表示一般与特殊的关系: 子类(接口)特化父类(接口)的所有特征和行为,是对象之 ...
- Nhibernate的第一个实例
第一个NhIbernate程序 1.目的: a) 链接到oracle数据库 b) 增删改 c) 基本查询.sql查询 d) 视图查询 e) 使用存储过程 f) 多表查询.级联查询 g) 级联增删改 2 ...
- Java List双击事件
1. 定义一个MouseListener: 2. 在mouseListener中增加mouseClicked事件: 3. 由MouseEvent的getSource()获得List对象: 4. 由Li ...
- Delphi 收藏
日前整理仓库,翻出了一些 Delphi 产品,以前购买的 Delphi 都有实体产品,包含说明书.光碟片.还有一些广告文宣,而且相当厚实,版本的演进,从外包装也能感受到,到目前的 XE5 版,只剩一个 ...
