总的来说自定义控件可以理解为重写创造并绘制一个控件,所以就要涉及到它的大小,位置,以及它的其他样式。在此博客中我只针对继承自View的自定义控件
一.测量 public final void measure(int widthMeasureSpec, int heightMeasureSpec)
protected final void setMeasuredDimension(int measuredWidth, int measuredHeight)
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
measure调用onMeasure,onMeasure测量宽度、高度然后调用setMeasureDimension保存测量结果,measure,setMeasureDimension是final类型,view的子类不需要重写,onMeasure在view的子类中重写。即在重写的onMeasure()方法的最后setMeasuredDimension()为控件设置大小
关于MeasureSpec:
(1) UPSPECIFIED :未指定模式,父容器对于子容器没有任何限制,子容器想要多大就多大,通常在绘制自定义View时才会用
(2) EXACTLY:精确值模式,父容器已经为子容器设置了尺寸,子容器应当服从这些边界,不论子容器想要多大的空间,当控件的layout_width和layout_height属性指定为具体数值或match_parent时为该模式。
(3) AT_MOST:最大值模式,子容器可以是声明大小内的任意大小,当空间的宽高设置为wrap_content时为该模式
public void layout(int l, int t, int r, int b)
protected boolean setFrame(int left, int top, int right, int bottom)
protected void onLayout(boolean changed, int left, int top, int right, int bottom)
layout通过调用setFrame(l,t,r,b),l,t,r,b即子视图在父视图中的具体位置,onLayout一般只会在自定义ViewGroup中才会使用
3.)绘制-draw过程主要用于利用前两步得到的参数,将视图显示在屏幕上,到这里也就完成了整个的视图绘制工作。
public void draw(Canvas canvas)
protected void onDraw(Canvas canvas)
通过调用draw函数进行视图绘制,在View类中onDraw函数是个空函数,最终的绘制需求需要在自定义的onDraw函数中进行实现,比如ImageView完成图片的绘制,如果自定义ViewGroup这个函数则不需要重载。
————————————————
版权声明:本文为CSDN博主「中流击水浪遏飞舟」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/yuanheng19930119/article/details/88055225
自定义控件
package com.example.coustomapplication;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import androidx.annotation.Nullable;
public class SimpleView extends View {
private final static String TAG = SimpleView.class.getSimpleName();
//画笔
private Paint mPaint;
private RectF oval;
//事件处理
private EventHandle mEventHandle;
//鼠标按下位置
private int startX,startY;
//按下鼠标时控件的位置
private int startLeft,startTop;
//状态栏高度
int statusHeight = 0;
//背景颜色
int backgroundColor=Color.GRAY;
int progressColor=Color.RED;
int textColor=Color.WHITE;
int textSize=30;
int circleRadius=2048;
int progress=120;//进度
//定义一个接口对象listerner
private OnItemSelectListener listener;
//获得接口对象的方法。
public void setOnItemSelectListener(OnItemSelectListener listener) {
this.listener = listener;
}
//定义一个接口
public interface OnItemSelectListener{
public void onItemSelect();
}
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()){
case MotionEvent.ACTION_MOVE:
case MotionEvent.ACTION_DOWN:
float x=event.getX();
float y = event.getY();
//当屏幕被点击后,将参数传入。
if(listener!=null){
listener.onItemSelect();
}
invalidate();
return true;
case MotionEvent.ACTION_UP:
invalidate();
return true;
}
return super.onTouchEvent(event);
}
public SimpleView(Context context) {
super(context);
init();
}
public SimpleView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
initParameter(context,attrs);
init();
}
public SimpleView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initParameter(context,attrs);
init();
}
private void init(){
mPaint = new Paint();
//设置是否使用抗锯齿功能,会消耗较大资源,绘制图形速度会变慢。
mPaint.setAntiAlias(true);
mPaint.setTextSize(textSize);
oval=new RectF();
mEventHandle=null;
startY=startX=0;
int resourceId = this.getResources().getIdentifier("status_bar_height", "dimen", "android");
if (resourceId > 0) {
statusHeight = this.getResources().getDimensionPixelSize(resourceId);
}
}
private void initParameter(Context context, AttributeSet attrs)
{
TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.SimpleView);
if (typedArray != null) {
backgroundColor = typedArray.getColor(R.styleable.SimpleView_percent_background_color, Color.GRAY);
progressColor = typedArray.getColor(R.styleable.SimpleView_percent_progress_color, Color.RED);
circleRadius = (int)typedArray.getDimension(R.styleable.SimpleView_percent_circle_radius, 2048);
progress = typedArray.getInt(R.styleable.SimpleView_percent_circle_progress, 120);
textColor=typedArray.getColor(R.styleable.SimpleView_percent_text_color,Color.WHITE);
textSize=(int)typedArray.getDimension(R.styleable.SimpleView_percent_text_size,30);
if(progress>360)
progress=360;
if(progress<0)
progress=0;
typedArray.recycle();
}
}
@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);
Log.e(TAG, "onMeasure--widthMode-->" + widthMode);
switch (widthMode) {
case MeasureSpec.EXACTLY:
//精确值模式,当控件的layout_width和layout_height属性指定为具体数值或match_parent时。
break;
case MeasureSpec.AT_MOST:
//最大值模式,当空间的宽高设置为wrap_content时。
break;
case MeasureSpec.UNSPECIFIED:
//未指定模式,View想多大就多大,通常在绘制自定义View时才会用。
break;
}
//取最小边为控件的宽高的最小值
int minWidth=widthSize>heightSize?heightSize:widthSize;
setMeasuredDimension(minWidth,minWidth);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
mPaint.setColor(backgroundColor);
// FILL填充, STROKE描边,FILL_AND_STROKE填充和描边
mPaint.setStyle(Paint.Style.FILL_AND_STROKE);
int with = getWidth();
int height = getHeight();
Log.e(TAG, "onDraw---->" + with + "*" + height);
float radius = with / 2-5;
//如果设置的半径比较合理,就去设置的半径
if(circleRadius
attrs文件
XML文件
主活动
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
public class MainActivity extends AppCompatActivity {
private SimpleView simpleView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
simpleView = findViewById(R.id.sv_a);
simpleView.setOnItemSelectListener(new SimpleView.OnItemSelectListener() {
@Override
public void onItemSelect() {
Log.d("gaoqiang", "onItemSelect: ");
}
});
}
}



