Android自定义View
相信大家在实际开发过程中或多或少都会有遇到基础控件满足不了自己的需求,这是我们就需要通过自定义view来满足自己的开发。
在自定义view的过程中我们大部分只需要重写onMeasure(),onDraw()这个两个方法,onMeasure用来测量我们所需要绘制view的大小,onDraw用来绘制当前的view。
在绘制view之前我梦首先需要向了解些在绘制过程中需要用到的工具:Paint(画笔),Canvas(画板);
paint可以帮我们绘制出不同颜色,效果的view
paint.setAntiAlias(true);//设置抗锯齿
paint.setColor(Color.parseColor("#ff0000"));//设置画笔颜色
paint.setStrokeWidth(12);//设置画笔宽度
paint.setStyle(Paint.Style.FILL_AND_STROKE);//设置模式 FILL(填充模式),STROKE(描边),FILL_AND_STROKE(填充并且描边)
如果想要了解更详细的paint内容,可以看下凯哥的自定义 View 1-2 Paint 详解
Canvas可以帮助我们绘制不同形状的view
绘制一条直线
public void drawLine(float startX, float startY, float stopX, float stopY,
@NonNull Paint paint) {
//绘制一个圆
public void drawCircle(float cx, float cy, float radius, @NonNull Paint paint) {
super.drawCircle(cx, cy, radius, paint);
}
API给我们提供了很多绘制不同图形的方法我就不一一介绍。
onMeasure测量
我们掌握了这些工具之后,是时候开启我们的绘制之旅了。为了在绘制是能够绘制出我们理想的view的大小。我首先需要进行测量,然后设置我们view 的大小。
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {}
在测量大小的过程我们中需要注意,这两个参数貌似是我们所需要的宽高,但实际上这两个参数是我们需要的宽高信息。它不仅仅只包含宽高信息,还有测量模式。
//测量出来宽度
MeasureSpec.getSize(widthMeasureSpec);
//测量模式
MeasureSpec.getMode(widthMeasureSpec);
测量模式包含:UNSPECIFIED(父容器没有对当前View有任何限制,当前View可以任意取尺寸),EXACTLY(当前的尺寸就是当前View应该取的尺寸),AT_MOST(当前尺寸是当前View能取的最大尺寸)
我们需要通过测量模式来最终确定自己的宽高。下面是我定义的获取宽高的方法。
private int getSize(int measureSpec) {
int size = MeasureSpec.getSize(measureSpec);
int model = MeasureSpec.getMode(measureSpec);
switch (model) {
case MeasureSpec.UNSPECIFIED:
//如果测量模式为没有限定宽高,我们则给他match_parent
size = ViewGroup.LayoutParams.MATCH_PARENT;
break;
case MeasureSpec.AT_MOST:
//如果测量模式为取最大值,我们则给他wrap_content
size = ViewGroup.LayoutParams.WRAP_CONTENT;
break;
case MeasureSpec.EXACTLY:
//如果测量模式为固定宽高,则就给他测量出来的值
size = size;
break;
}
return size;
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
mWidth = getSize(widthMeasureSpec);
mHeight = getSize(heightMeasureSpec);
//测量完宽高后,将宽高的值设置进去
setMeasuredDimension(mWidth, mHeight);
}
到此就完成了我们的测量操作了,到这里我们就可以确定自己view的大小。
我们可以直接使用我们自定义的view来看下我们view的大小了。
//这里为了能够方便的看到view的大小,给他加了一个背景
<com.example.yuan.customview.customview.MyView
android:layout_width="200dp"
android:layout_height="100dp"
android:background="@color/colorAccent" />
效果如下:
onDraw(绘制)
在绘制之前,我们需要先确定好绘制的区域,这是我们就需要了解绘制是他的坐标是多少。在手机的坐标体系和我们数学中的坐标体系有点不一样。
如下图所示:
为了方便大家理解将运行的效果看下:
图中蓝色区域是view的大小,红线是我们绘制得直线。
有一点需要注意的地方是在自定义view的时候至少需要两个构造方法
下面贴下这个源码:
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
public class MyView extends View {
private Paint paint;//画笔
private int mWidth;
private int mHeight;
public MyView(Context context) {
super(context);
init();
}
public MyView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
init();
}
//做一些初始化操作
private void init() {
paint = new Paint();
paint.setAntiAlias(true);//设置抗锯齿
paint.setColor(Color.parseColor("#ff0000"));//设置画笔颜色
paint.setStrokeWidth(12);//设置画笔宽度
paint.setStyle(Paint.Style.FILL_AND_STROKE);//设置模式 FILL(填充模式),STROKE(描边),FILL_AND_STROKE(填充并且描边)
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
mWidth = getSize(widthMeasureSpec);
mHeight = getSize(heightMeasureSpec);
//测量完宽高后,将宽高的值设置进去
setMeasuredDimension(mWidth, mHeight);
}
private int getSize(int measureSpec) {
int size = MeasureSpec.getSize(measureSpec);
int model = MeasureSpec.getMode(measureSpec);
switch (model) {
case MeasureSpec.UNSPECIFIED:
//如果测量模式为没有限定宽高,我们则给他match_parent
size = ViewGroup.LayoutParams.MATCH_PARENT;
break;
case MeasureSpec.AT_MOST:
//如果测量模式为取最大值,我们则给他wrap_content
size = ViewGroup.LayoutParams.WRAP_CONTENT;
break;
case MeasureSpec.EXACTLY:
//如果测量模式为固定宽高,则就给他测量出来的值
size = size;
break;
}
return size;
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawLine(0,0,mWidth,mHeight,paint);
}
}
布局文件
<android.support.constraint.ConstraintLayout 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">
<com.example.yuan.customview.customview.MyView
android:layout_width="200dp"
android:layout_height="100dp"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
android:background="@color/colorPrimaryDark"/>
</android.support.constraint.ConstraintLayout>
到了这里大家是不是觉得自定义view也不是想象中的那么难呢?