自定义View学习总结(一)

1.为什么会引入自定义view

现有的控件不满足我们的需求,或者项目中频繁用到一种需要我们自定义的控件,把它封装起来提高复用性。

2.自定义view的使用
2.1 自定义控件的绘制流程:
1,准备工作:(加载阶段)
2,规划大小:(测量阶段)
3,绘制位置:(布局阶段)
4,画:(绘制阶段)

1.定义一个类继承View或View的子类

public class MyView extends View {
  ...
}

2.重写构造方法

//当需要new当前视图的时候需要重写这个构造
public MyView(Context context) {
//一般处理为让其调用含有两个参数的构造方法
    this(context, null);
}
//当需要将自定义View声明在xml文件中使用的时候需要重写这个构造方法
public MyView(Context context, AttributeSet attrs) {
//一般处理为调用第三个构造
    this(context, attrs, 0);
}
//当需要将自定义View声明在xml文件中,并且当前控件需要自定义主题样式的时候.重写这个构造方法
public MyView(Context context, AttributeSet attrs, int defStyleAttr) {
    super(context, attrs, defStyleAttr);
//做初始化操作
    init();
}

构造方法一般用于数据的初始化加载
开发中也存在只重写两个参数的构造方法的情况,但这样做就不能再去直接new控件了.

3.重写onMeasure
onMeasure在自定义view中有时候不用重写,因为如果是自定义view的话在xml声明中给定的是确定的数值或者match_parent时不用重写该方法,但是如果给定的数值时wrap_content的时候就需要重写了,因为此时view不知道采用哪个大小。但是在自定义ViewGroup的时候要重写onMeasure方法。

onMeasure()方法:用于测量控件,如果控件还有子控件,则会递归测量子控件
如果是ViewGroup,默认只会测量自身控件

MeasureSpec:是由父布局和子控件共同决定的,是一个组合值,用于控件的宽高
MeasureSpec是一个32位int值
MeasureSpec是由两部分组成:
mode:控件尺寸的模式,前两位
size:控件的尺寸,后三十位

其中mode分为三种:
1,UNSPECIFIED:数值为0<<30
未限定实际宽高,这种情况较少,例如:ScrollView对于其子视图的高度的限定
2,EXACTLY:数值为1<<30
明确的尺寸,例如:xxdp,MATCH_PARENT
3,AT_MOST:数值为2<<30
至多为多少,例如WRAP_CONTENT,若控件本身没有默认尺寸,则系统会尽可能的把空间赋予控件,为MATCH_PARENT

常用api

setMeasureDimension(width,height):设置控件的最终尺寸
MeasureSpec spec=  MeasureSpec.makeMeasureSpec(size,mode);用于指定MeasureSpec
MeasureSpec.getSize(measureSpec);通过MeasureSpec获取size
MeasureSpec.getMode(measureSpec);通过MeasureSpec获取mode
getSuggestedMinimumWidth():获得背景图的宽度,如果没有背景,则返回值为0

4.onDraw 绘制
onDraw里面只有一个参数Canvas canvas,这个参数是用来绘制自定义View的,这个方法里面还有一个重要的变量,Paint paint,这个变量是用来给设置画笔的

(Paint画笔相关api)

//给Paint设置颜色
paint.setColor(Color.RED);
//用此Paint绘制出的图形没有锯齿,但会损耗性能
paint.setAntiAlias(true);
//设置Paint样式(不填充),如:绘制一个空心圆,则设置如下样式
paint.setStyle(Paint.Style.STROKE);

绘制线,矩形,圆角矩形,圆形,环形,弧形等
相关api:

//定义一个点,包含x和y坐标
PointF point= new PointF(x, y);

//绘制一个圆
参数1,2:圆心坐标
//参数3:半径
//参数4:画笔
canvas.drawCircle(x, y, radius, paint);

//绘制直线
//参数1,2:起点的x,y坐标
//参数3,4:起点的x,y坐标
canvas.drawLine(x1, y1,x2,y2, paint);

//定义一个矩形
//参数1:矩形的左边相对于屏幕左边缘的距离
//参数2:矩形的上边相对于屏幕上边缘的距离
//参数3:矩形的右边相对于屏幕左边缘的距离
//参数4:矩形的下边相对于屏幕上边缘的距离
RectF rect= new RectF(l, t, r, b);

//绘制弧形
//参数1:绘制弧形依赖的矩形,绘制出的弧形会与此矩形内切
//参数2:弧形的起始角度
//参数3:弧形的弧度
canvas.drawArc(rect, startAngle,sweepAngle
, false, paint);

//绘制一个矩形
canvas.drawRect(rect,paint);

//绘制一个点
//参数1,2:绘制的点的x,y坐标
canvas.drawPoint(x,y,paint);

//绘制多个点的x,y坐标
float[] pts = {x1, y1, x2, y2, x3,y3...};
//参数2:从pts集合中的哪个元素开始绘制(从哪里开始,哪里就作为x坐标,后面是y坐标,依此类推)
//参数3:包含pts集合中共几个元素
canvas.drawPoints(pts,offset,count,paint);
canvas.drawRoundRect(rectF,30f,30f,paint);

canvas的变换处理:
Android中的坐标系:默认是以屏幕左上角为原点,x方向向右为+,y方向向下为正
绘制界面是基于坐标系绘制的
若调用了canvas的translate或rotate方法相当于对坐标系进行了平移和旋转,基于旋转后的坐标系进行绘制工作.

2.5.Canvas的其他处理
注:canvas在做下列处理前必须先调用save方法处理后要调用restore方法

1,平移
canvas.translate(100,0);
2,旋转
canvas.rotate(300);
3,缩放
canvas.scale(0.2f,0.2f);
canvas的平移和旋转可以看成是对绘制坐标系进行的平移或旋转
3.自定义ViewGroup

自定义ViewGroup除了要进行上面的操作外还需要有一步,重写onLayout方法

onLayout方法就是主要为了摆放ViewGroup内部的子视图
onLayout方法参数四个参数:l,t,r,b:分别为系统赋予ViewGroup的左上右下的值

2,常用api:

addView():向当前控件添加子视图
getChildCount():获取当前控件的孩子视图的个数
getChildAt():通过指定的位置获取对应的子视图
layout():用于对子视图的摆放处理,可以根据实际需求传入对应的l,t,r,b

For example

@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
//获取子视图总数
    int childCount = getChildCount();
//遍历所有的子视图
    for (int i = 0; i < childCount; i++) {
//获取某个子视图
        View child = getChildAt(i);
//将这个子视图摆放到当前空间的某个位置
//1,横向摆放
    child.layout(30*i,0,30*(i+1),30);
//2,纵向摆放
    //child.layout(0,30*i,30,30*(i+1));
}
//按照倒三角形形状摆放
int top = 0;
int childIndex = 0;
for (int i = 2; i >= 0; i--) {
    for (int j = 0; j <= i; j++) {
        View child = getChildAt(childIndex);
        child.layout(30 * j, top, 30 * (j + 1), top + 30);
        childIndex++;
    }
    top += 30;
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 218,525评论 6 507
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,203评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,862评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,728评论 1 294
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,743评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,590评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,330评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,244评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,693评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,885评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,001评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,723评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,343评论 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,919评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,042评论 1 270
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,191评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,955评论 2 355

推荐阅读更多精彩内容