步骤
- 自定义属性
- 重写ondraw()
- 重写onMeasure()
带着问题看代码
- 在不重写onMeasure方法时, wrap_content与match_parent对布局影响的区别
- 测量之前怎么去获取View的大小
- setMeasuredDimension(…)方法的作用
效果图
自定义属性
布局文件
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:test="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="simplifyreader.nobita.com.customview.MainActivity">
<simplifyreader.nobita.com.customview.MyView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
test:backColor="#ff0"
test:text="这里"
test:textColor="#f00"
test:textSize="50sp"/>
</RelativeLayout>
分析:
1、 添加xmlns:test=”http://schemas.android.com/apk/res-auto”,其实test为自定义属性前缀
attrs文件
在values文件目录下创建attrs.xml文件
<resources>
<declare-styleable name="MyView">
<attr name="textColor" format="color"/>
<attr name="text" format="string"/>
<attr name="backColor" format="color"/>
<attr name="textSize" format="dimension"/>
</declare-styleable>
</resources>
自定义View代码
在代码中有关键注释
public class MyView extends View {
Paint mPaint;
Paint mBackPaint;
String mText;
int mTextColor;
float mTextSize;
int defalutTextColor = Color.RED;
float defalutTextSize = Color.RED;
int mBackColor;
int defalutBackColor = Color.BLACK;
private Rect mBound;
public MyView(Context context) {
super(context);
}
public MyView(Context context, AttributeSet attrs) {
super(context, attrs);
mPaint = new Paint();
mBackPaint = new Paint();
//获取xml文件中自定义属性集合
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.MyView);
mText = a.getString(R.styleable.MyView_text);
mTextColor = a.getColor(R.styleable.MyView_textColor, defalutTextColor);
mBackColor = a.getColor(R.styleable.MyView_backColor, defalutBackColor);
mTextSize = a.getDimension(R.styleable.MyView_textSize, 36);
a.recycle();
mPaint.setColor(mTextColor);
mPaint.setTextSize(mTextSize);
mBackPaint.setColor(mBackColor);
//获取mText的长宽,并封装进mBound
mBound = new Rect();
mPaint.getTextBounds(mText, 0, mText.length(), mBound);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
int width;
int height;
if (widthMode == MeasureSpec.EXACTLY) {
width = widthSize;
} else {
width = mBound.width() + getPaddingLeft() + getPaddingRight();
}
if (heightMode == MeasureSpec.EXACTLY) {
height = heightSize;
} else {
height = mBound.height() + getPaddingBottom() + getPaddingTop();
}
//必须调用,设置该View的长宽
setMeasuredDimension(width, height);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//绘制背景
canvas.drawRect(0, 0, getMeasuredWidth(), getMeasuredHeight(), mBackPaint);
//绘制文本,第二个和第三个参数为x_y坐标(文本的左下角)
canvas.drawText(mText, getWidth() / 2 - mBound.width() / 2, getHeight() / 2 + mBound.height() / 2, mPaint);
}
}