目录
1.继承View重写onDraw方法
2.继承View重写onMeasure方法
3.添加自定义属性
4.完整代码:
1.继承View重写onDraw方法
解决问题:直接继承自View和ViewGroup的控件,padding是默认无法生效的,需要自己处理。
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
final int paddingLeft=getPaddingLeft();
final int paddingRight=getPaddingRight();
final int paddingTop=getPaddingTop();
final int paddingBottom=getPaddingBottom();
int width=getWidth()-paddingLeft-paddingRight;
int height=getHeight()-paddingBottom-paddingTop;
int radius=Math.min(width,height)/2;
canvas.drawCircle(paddingLeft+width/2,paddingTop+height/2,radius,mPaint);
}
中心思想就是在绘制的时候考虑到View四周的空白即可。
2.继承View重写onMeasure方法
解决问题:直接继承自View的控件,如果不对wrap_content做特殊处理,那么使用wrap_content就相当于使用match_parent。
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int widthSpecMode=MeasureSpec.getMode(widthMeasureSpec);
int widthSpecSize=MeasureSpec.getSize(widthMeasureSpec);
int heightSpecMode=MeasureSpec.getMode(heightMeasureSpec);
int heightSpecSize=MeasureSpec.getSize(heightMeasureSpec);
if(widthSpecMode==MeasureSpec.AT_MOST&&heightSpecSize==MeasureSpec.AT_MOST){
setMeasuredDimension(200,200);
}else if(widthSpecMode==MeasureSpec.AT_MOST){
setMeasuredDimension(200,heightSpecSize);
} else if (heightSpecMode==MeasureSpec.AT_MOST) {
setMeasuredDimension(widthSpecSize,200);
}
}
3.添加自定义属性
第一步:在values目录下面创建自定义属性的XML,比如attrs.xml,文件内容如下:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="CircleView">
<attr name="circle_color" format="color"/>
</declare-styleable>
</resources>
在XML中声明了一个自定义属性集合“CircleView”,在这个集合里面可以有很大自定义属性,这里只定义了一个格式为“Color”的属性“circle_color”,这里的格式color指的是颜色。
第二步:在View的构造方法中解析自定义属性的值并做出相应的处理。
public CircleView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
TypedArray a=context.obtainStyledAttributes(attrs,R.styleable.CircleView);
mColor=a.getColor(R.styleable.CircleView_circle_color,Color.RED);
a.recycle();
init();
}
首先加载自定义属性集合CircleView,接着解析CircleView属性集合中的circle_color属性,它的id为R.styleable.CircleView_circle_color。如果在使用时没有指定circle_color这个属性,那么就会选择红色作为默认的颜色值,解析完自定义属性后,通过recycle方法来释放资源,这样CircleView中所做的工作就完成了。
第三步:在布局文件中使用自定义属性
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity"
android:background="#ffffff"
android:orientation="vertical">
<com.example.myview.CircleView
android:id="@+id/circleView1"
android:layout_width="wrap_content"
android:layout_height="100dp"
android:background="#000000"
android:layout_margin="20dp"
android:padding="20dp"
app:circle_color="@color/green"
/>
</LinearLayout>
运行:
4.完整代码
CircleView类:
public class CircleView extends View {
private int mColor= Color.RED;
private Paint mPaint=new Paint(Paint.ANTI_ALIAS_FLAG);
public CircleView(Context context) {
super(context);
init();
}
public CircleView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
TypedArray a=context.obtainStyledAttributes(attrs,R.styleable.CircleView);
mColor=a.getColor(R.styleable.CircleView_circle_color,Color.RED);
a.recycle();
init();
}
public CircleView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
private void init(){
mPaint.setColor(mColor);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int widthSpecMode=MeasureSpec.getMode(widthMeasureSpec);
int widthSpecSize=MeasureSpec.getSize(widthMeasureSpec);
int heightSpecMode=MeasureSpec.getMode(heightMeasureSpec);
int heightSpecSize=MeasureSpec.getSize(heightMeasureSpec);
if(widthSpecMode==MeasureSpec.AT_MOST&&heightSpecSize==MeasureSpec.AT_MOST){
setMeasuredDimension(200,200);
}else if(widthSpecMode==MeasureSpec.AT_MOST){
setMeasuredDimension(200,heightSpecSize);
} else if (heightSpecMode==MeasureSpec.AT_MOST) {
setMeasuredDimension(widthSpecSize,200);
}
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
final int paddingLeft=getPaddingLeft();
final int paddingRight=getPaddingRight();
final int paddingTop=getPaddingTop();
final int paddingBottom=getPaddingBottom();
int width=getWidth()-paddingLeft-paddingRight;
int height=getHeight()-paddingBottom-paddingTop;
int radius=Math.min(width,height)/2;
canvas.drawCircle(paddingLeft+width/2,paddingTop+height/2,radius,mPaint);
}
}
布局文件:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity"
android:background="#ffffff"
android:orientation="vertical">
<com.example.myview.CircleView
android:id="@+id/circleView1"
android:layout_width="wrap_content"
android:layout_height="100dp"
android:background="#000000"
android:layout_margin="20dp"
android:padding="20dp"
app:circle_color="@color/green"
/>
</LinearLayout>