Hongyang自定义View学习笔记总结
Hongyang原文地址:http://blog.csdn.net/lmj623565791/article/details/24252901
- 自定义View的属性
- 在View的构造方法中获得我们自定的属性
- 重写onDraw和onMesure方法
1、自定义View的属性,首先在res/values/文件夹下建立一个attrs.xml ,
<?xml version="1.0" encoding="utf-8"?>
<resources>
<attr name="titleText" format="string"/>
<attr name="titleTextColor" format="color"/>
<attr name="titleTextSize" format="dimension"/>
<declare-styleable name="CustomTitleView">
<attr name="titleText"/>
<attr name="titleTextColor"/>
<attr name="titleTextSize"/>
</declare-styleable>
</resources>
attr属性的意思,attribute的缩写;format定义属性类型;attr不依赖styleable,styleable只是为了方便attr的使用。我们自己定义的属性也可不放在styleable中,可以直接定义一些属性
attr和styleable的关系
attr不依赖styleable,styleable只是为了方便attr的使用。我们自己定义的属性也可不放在styleable中,可以直接定义一些属性而不使用styleable:
<attr name="titleText" format="string"/>
<attr name="titleTextColor" format="color"/>
<attr name="titleTextSize" format="dimension"/>
此时定义一个attr就会在R文件中生成一个Id,如果需要获取这些属性时必须调用如下代码:
/**
* 获取我们所定义的自定义属性
*/
int[] custom_attrs = {R.attr.titleText,
R.attr.titleTextColor,
R.attr.titleTextSize};
TypedArray typedArray = context.obtainStyledAttributes(set,custom_attrs);
如果定义一个styleable,我们可以在R文件中自动生成一个int[],数组里面的int就是定义在styleable里面的attr的id。所以我们在获取属性的时候就可以直接使用styleable数组来获取一系列的属性会比较方便一点。
<declare-styleable name="CustomTitleView">
<attr name="titleText"/>
<attr name="titleTextColor"/>
<attr name="titleTextSize"/>
</declare-styleable>
</resources>
获取:
/**
* 获取我们所定义的自定义属性
*/
TypedArray array = context.getTheme().obtainStyledAttributes(attrs,
R.styleable.CustomTitleView, defStyleAttr, 0);
定义一个declare-styleable,在获取属性的时候为我们自动提供了一个属性数值。此外,我觉得使用declare-styleable的方式有利于我们我们把相关的属性组织起来,有一个分组的概念,属性的使用范围更加明确。
在布局中声明自定义的View
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:custom="http://schemas.android.com/apk/res-auto"
android:id="@+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.example.duxinwu.myview.MainActivity">
<com.example.duxinwu.myview.CustomTextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
/>
</RelativeLayout>
注意:一定要引入xmlns:custom=”http://schemas.android.com/apk/res-auto”
之前在Hongyang博客中是这样引入xmlns:custom=”http://schemas.android.com/apk/res/com.example.customview01但是你会发现在Android Studio中报错,Gradle使用res-auto
自动导入代替了com.example.customview01
使得我们编写代码更加方便。
其中custom是自己定义的,你也可以根据自己的喜好定义
2.在View的构造方法中获得我们自定的属性
public CustomTextView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
/**
* 获取我们所定义的自定义属性
*/
TypedArray array = context.getTheme().obtainStyledAttributes(attrs,
R.styleable.CustomTitleView, defStyleAttr, 0);
int n = array.getIndexCount();
for (int i = 0; i < n; i++) {
int attr = array.getIndex(i);
switch (attr) {
case R.styleable.CustomTitleView_titleText:
mTitleText = array.getString(attr);
break;
case R.styleable.CustomTitleView_titleTextColor:
mTitleTextColor=array.getColor(attr, Color.BLACK);
break;
case R.styleable.CustomTitleView_titleTextSize:
mTitleTextSize=array.getDimensionPixelSize(attr,
(int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP,16,
getResources().getDisplayMetrics()));
break;
default:
break;
}
}
array.recycle();
initView();
}
private void initView() {
/**
* 获取绘制文本的宽和高
*/
mPaint=new Paint();
mPaint.setTextSize(mTitleTextSize);
mBound=new Rect();
mPaint.getTextBounds(mTitleText,0,mTitleText.length(),mBound);
this.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View view) {
mTitleText=randomText();
postInvalidate();
}
});
}
- TypedArray:存储了从
obtainStyledAttributes(AttributeSet, int[], int, int) or obtainAttributes(AttributeSet, int[])
检索出值。确保在使用结束后调用recycle()方法回收。其实是用来简化我们的工作的,如果布局中的属性的值是引用类型(比如:@dimen/dp100),如果使用AttributeSet去获得最终的像素值,那么需要第一步拿到id,第二步再去解析id。而TypedArray正是帮我们简化了这个过程 - obtainStyledAttributes:获取样式属性
3.重写onDraw和onMesure方法
onDraw方法:
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
mPaint.setColor(Color.YELLOW);
canvas.drawRect(0,0,getMeasuredWidth(),getMeasuredHeight(),mPaint);
mPaint.setColor(mTitleTextColor);
canvas.drawText(mTitleText,getWidth()/2-mBound.width()/2,getHeight()/2+mBound.height()/2,mPaint);
}
onMesure方法:
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
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 {
float textWidth=mBound.width();
int desired= (int) (getPaddingLeft()+mBound.width()+getPaddingRight());
width=desired;
}
if (heightMode==MeasureSpec.EXACTLY){
height=heightSize;
}else{
float textHeight=mBound.height();
int desired= (int) (getPaddingTop()+mBound.height()+getPaddingBottom());
height=desired;
}
setMeasuredDimension(width,height);
}