Android中,所有的界面布局都是View来的,各种ImageView 、TextView、LinearLayout等等都是继承View而来的。
1、继承View,至少提供一个构造函数
2、定义自定义属性:
a)在你的view资源标签下定义自设的属性 res/values/attr.xml
b)在你的xml layout中指定属性
c)运行时,获取指定属性
d)把获取的属性应用到View上面
添加自定义的属性
declare-styeable farmat属性有
1.reference:引用资源ID
2.color:颜色值
3.boolean:布尔值
4.dimension:尺寸值
5.float:浮点值
6.integer:整型值
7.string:字符串
8.fraction:百分数
9.enum:枚举值
10.flag:位或运算
3、应用自定义属性
a)TypeArray ta = context.obtainStyleAttrbutes()
b)ta.get….
c)TypeArray 对象是一个共享资源,必须在使用完进行回收
TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.CommonRelativeLayout, defStyleAttr, 0);
mBackground = ta.getColor(R.styleable.CommonRelativeLayout_layout__background, mBackground);
paddingLeft = ta.getDimensionPixelSize(R.styleable.CommonRelativeLayout_layout_padding_left, paddingLeft);
paddingRight = ta.getDimensionPixelSize(R.styleable.CommonRelativeLayout_layout_padding_right, paddingRight);
mTitle = ta.getString(R.styleable.CommonRelativeLayout_layout_title);
mTitleSize = (float) ta.getDimensionPixelSize(R.styleable.CommonRelativeLayout_layout_title_size,
(int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 16, context.getResources().getDisplayMetrics()));
mTitleColor = ta.getColor(R.styleable.CommonRelativeLayout_layout_title_color, mTitleColor);
mInfo = ta.getString(R.styleable.CommonRelativeLayout_layout_sub_title);
mInfoSize = (float) ta.getDimensionPixelSize(R.styleable.CommonRelativeLayout_layout_sub_title_size,
(int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 14, context.getResources().getDisplayMetrics()));
mInfoColor = ta.getColor(R.styleable.CommonRelativeLayout_layout_sub_title_color, mInfoColor);
mShowArrow = ta.getBoolean(R.styleable.CommonRelativeLayout_show_arrow, mShowArrow);
ta.recycle();
4、添加属性和事件
a)通过getter和setter 暴露一些需要被用的属性
b)View 发生变化时需要Invalidate通知系统对这个view进行reView,如果需要改变View的组件大小,需要用到requestLayout方法
/**
* @param title 暴露title属性,可以给外部设置
*/
public void setTitle(String title){
this.mTitle = title;
invalidate();
}
5、创建绘图对象
a)绘制什么由Canvas处理
canvas.draw.....
b)如何绘制由Paint处理
titlePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
titlePaint.setTextSize(mTitleSize);
titlePaint.setColor(mTitleColor);
Rect rect = new Rect();
// title标题文本高度
titlePaint.getTextBounds(mTitle, 0, mTitle.length(), rect);
titleTextHeight = rect.height();
6、在实际场景上应用
布局文件中使用
onMeasure(int widthMeasureSpec, int heightMeasureSpec)方法中
可以获取view的父控件的大小,对于计算view更加准确
传入的widthMeasureSpec和heightMeasureSpec不是一般的尺寸数值,而是将模式和尺寸组合在一起的数值。
通过int mode = MeasureSpec.getMode(widthMeasureSpec)得到模式
int size =MeasureSpec.getSize(widthMeasureSpec)得到尺寸。
mode共有三种情况,取值分别为MeasureSpec.UNSPECIFIED, MeasureSpec.EXACTLY, MeasureSpec.AT_MOST。
MeasureSpec.EXACTLY:是精确尺寸,当我们将控件的layout_width或layout_height指定为具体数值时如andorid:layout_width=”50dp”,或者为FILL_PARENT,都是控件大小已经确定的情况,都是精确尺寸。
MeasureSpec.AT_MOST:是最大尺寸,当控件的layout_width或layout_height指定为WRAP_CONTENT时,控件大小一般随着控件的子空间或内容进行变化,此时控件尺寸只要不超过父控件允许的最大尺寸即可。因此,此时的mode是AT_MOST,size给出了父控件允许的最大尺寸。
MeasureSpec.UNSPECIFIED:是未指定尺寸,这种情况不多,一般都是父控件是AdapterView,通过measure方法传入的模式。
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
int width;
int height ;
if (widthMode == MeasureSpec.EXACTLY){ //精准模式
width = widthSize;
} else{
width = getMeasuredWidth();
}
if (heightMode == MeasureSpec.EXACTLY){
height = heightSize;
}else {
height = titleTextHeight + infoTextHeight +getPaddingTop()+getPaddingBottom();
}
viewHeight = height;
paddingHeight = (viewHeight-titleTextHeight-infoTextHeight)/2;
setMeasuredDimension(width,height);
//view第一次被赋值大小或者view大小被改变时,会被执行
onSizeChanged(int w, int h, int oldw, int oldh)
在onDraw()方法中画出来,故不宜放耗时过多的计算放在这里,不然会显得卡顿
canvas.drawRect(0, 0, getMeasuredWidth(), viewHeight, canvasPaint);
canvas.drawText(mTitle, paddingLeft, viewHeight/2-paddingHeight/4, titlePaint);
canvas.drawText(mInfo, paddingLeft, viewHeight/2+infoTextHeight+paddingHeight/4, infoPaint);
canvas.drawBitmap(arrow,getMeasuredWidth()-arrow.getWidth()-paddingRight,viewHeight/2-arrow.getHeight()/2,arrowPaint);
demo地址:https://github.com/azhansy/CommonRelativeLayoutDemo
参考:
https://developer.android.com/training/custom-views/create-view.html
http://www.jianshu.com/p/84cee705b0d3