直接继承 View 重写 onDraw 方法.
这种方法主要用于实现一些不规则的效果.一般需要重写onDraw方法.
注意点 :
- 需要自己支持 wrap_content 属性.
- 需要自己支持 padding 属性.
- 添加自定义属性 .
1. 重写onMeasure处理wrap_content .
处理wrap_content代码
// 默认尺寸.
private int mWidht = 200;
private int mHeight = 200;
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// 默认设置View尺寸但是wrap_content会失效
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
// 获取尺寸.
int widthSpecMode = MeasureSpec.getMode(widthMeasureSpec);
int heightSpecMode = MeasureSpec.getMode(heightMeasureSpec);
int widthSpecSize = MeasureSpec.getSize(widthMeasureSpec);
int heightSpecSize = MeasureSpec.getSize(heightMeasureSpec);
// 对于使用wrap_content 使用默认尺寸.
if (widthSpecMode == MeasureSpec.AT_MOST && heightSpecMode == MeasureSpec.AT_MOST){
setMeasuredDimension(mWidht,mHeight);
}else if (widthSpecMode == MeasureSpec.AT_MOST){
setMeasuredDimension(mWidht,heightSpecSize);
}else if (heightSpecSize == MeasureSpec.AT_MOST){
setMeasuredDimension(widthSpecSize,mHeight);
}
}
2. 在onDraw方法中处理失效Padding问题.
处理代码 :
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
// 处理padding.
final int paddingLeft = getPaddingLeft();
final int paddingRight = getPaddingRight();
final int paddingTop = getPaddingTop();
final int paddingBottom = getPaddingBottom();
// 可用尺寸需要在总尺寸中减去padding值
int w = getWidth() - paddingLeft - paddingRight;
int h = getHeight() - paddingTop - paddingBottom;
int radius = Math.min(w,h)/2;
canvas.drawCircle(getWidth() / 2, getHeight() / 2,radius,mPaint);
}
3. 添加自定义属性.
3.1 在 values 目录下创建自定义属性XML文件.比如 : attrs.circle_view.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="CircleView">
<!-- 自定义颜色属性 -->
<attr name="circle_color" format="color"/>
</declare-styleable>
</resources>
3.2 在View的构造方法中解析自定义属性值并做相应处理
public CircleView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
// 解析自定义属性值.
TypedArray a = context.obtainStyledAttributes(attrs,R.styleable.CircleView);
mColor = a.getColor(R.styleable.CircleView_circle_color,Color.RED);
a.recycle();
init();
}
3.3 在布局文件中使用自定义属性.
使用自定义文件注意点 :
- 需要在布局文件中添加 schemeas 声明 : xmlns:app="http://schemas.android.com/apk/res-auto"
在这个声明中app是自定义属性前缀,自定义属性前缀必须和这里的一样.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
android:id="@+id/activity_main"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#fff"
android:orientation="vertical"
tools:context="com.blx.pkcs.customview01.MainActivity">
<com.blx.pkcs.customview01.CircleView
android:id="@+id/circle_view_1"
android:layout_width="wrap_content"
android:layout_margin="5dp"
app:circle_color="#0BB"
android:padding="10dp"
android:layout_height="100dp"
android:background="#000"
android:text="Hello World!"/>
</LinearLayout>
4. CircleView.java 完整代码
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.View;
/**
* 自定义View 绘制圆形.
* Created by WSJ on 2016/12/15.
*/
public class CircleView extends View {
private int mColor = Color.RED;
private Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
public CircleView(Context context) {
this(context,null);
}
public CircleView(Context context, AttributeSet attrs) {
this(context, attrs,0);
}
public CircleView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
// 解析自定义属性值.
TypedArray a = context.obtainStyledAttributes(attrs,R.styleable.CircleView);
mColor = a.getColor(R.styleable.CircleView_circle_color,Color.RED);
a.recycle();
init();
}
private void init() {
mPaint.setColor(mColor);
}
/**
* 在这个方法中处理padding失效问题.
*/
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
// 处理padding.
final int paddingLeft = getPaddingLeft();
final int paddingRight = getPaddingRight();
final int paddingTop = getPaddingTop();
final int paddingBottom = getPaddingBottom();
int w = getWidth() - paddingLeft - paddingRight;
int h = getHeight() - paddingTop - paddingBottom;
int radius = Math.min(w,h)/2;
canvas.drawCircle(getWidth() / 2, getHeight() / 2,radius,mPaint);
}
// 默认尺寸.
private int mWidht = 200;
private int mHeight = 200;
/**
* 在这个方法中处理wrap_content失效问题.
*/
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
// 处理Wrap_content 方式.
int widthSpecMode = MeasureSpec.getMode(widthMeasureSpec);
int heightSpecMode = MeasureSpec.getMode(heightMeasureSpec);
int widthSpecSize = MeasureSpec.getSize(widthMeasureSpec);
int heightSpecSize = MeasureSpec.getSize(heightMeasureSpec);
if (widthSpecMode == MeasureSpec.AT_MOST && heightSpecMode == MeasureSpec.AT_MOST){
setMeasuredDimension(mWidht,mHeight);
}else if (widthSpecMode == MeasureSpec.AT_MOST){
setMeasuredDimension(mWidht,heightSpecSize);
}else if (heightSpecSize == MeasureSpec.AT_MOST){
setMeasuredDimension(widthSpecSize,mHeight);
}
}
}
备注 : Android 开发艺术探索 - 读书笔记