1.自定义view入门


1.继承自view

系统提供的view 如 TextView 、ImageView 都是继承自view的;

2.自定义一个TextView

通过自定义一个TextView 来熟悉继承自view 的自定义view的api用法

3.onMeasure

用来处理控件的大小

 	@Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    }
//获取宽高的模式
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int heightMode = MeasureSpec.getMode(heightMeasureSpec);    

//mode
//MeasureSpec.AT_MOST 指定了wrap_content
//MeasureSpec.EXACTLY 指定了确切的值 match_parent fill_parent
//MeasureSpec.UNSPECIFIED 尽可能的大 

4.onDraw

用于绘制

   @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
//        canvas.drawText();
    }

5.onTouchEvent

用于处理用户触摸事件

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                break;
            case MotionEvent.ACTION_MOVE:
                break;
            case MotionEvent.ACTION_UP:
                break;
        }

        return super.onTouchEvent(event);
    }

6.自定义属性

用来配置自定义控件的属性

<?xml version="1.0" encoding="utf-8"?>

    
    
        
        
        
        
        

        
        
            
            
            
        
    

在布局中使用


在自定义控件中获取

    public TextView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.TextView);
        mText = typedArray.getString(R.styleable.TextView_text);
        mTextSize = typedArray.getDimensionPixelSize(R.styleable.TextView_textSize, mTextSize);
        mTextColor = typedArray.getColor(R.styleable.TextView_textColor, mTextColor);
        typedArray.recycle();
    }

7.完整的代码

package com.nb.customview;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.util.Log;
import android.util.TypedValue;
import android.view.MotionEvent;
import android.view.View;
import android.widget.LinearLayout;

import androidx.annotation.Nullable;

/**
 * Created by DongKing on 2020/11/5
 * Version 1.0
 * Describe:自定义TextView
 */
class TextView extends View {

    private static final String TAG = "TextView";

    private String mText;
    private int mTextSize = 15;
    private int mTextColor = Color.BLACK;

    private Paint mPaint;

    //    在java 代码中new 的时候使用
    public TextView(Context context) {
        this(context, null);
    }

    //    在layout 中使用
    public TextView(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    //有style时使用
    public TextView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        //获取xml中设置的属性
        TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.TextView);
        mText = typedArray.getString(R.styleable.TextView_nbText);
        mTextSize = typedArray.getDimensionPixelSize(R.styleable.TextView_nbTextSize, sp2px(mTextSize));
        mTextColor = typedArray.getColor(R.styleable.TextView_nbTextColor, mTextColor);
        typedArray.recycle();

        //初始化画笔
        mPaint = new Paint();
        mPaint.setAntiAlias(true);
        mPaint.setTextSize(mTextSize);
        mPaint.setColor(mTextColor);

    }

    private int sp2px(int sp) {
        return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, sp,
                getResources().getDisplayMetrics());
    }

    /**
     * 指定宽高
     * 针对不同的情况
     *
     * @param widthMeasureSpec
     * @param heightMeasureSpec
     */
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);

        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        int heightMode = MeasureSpec.getMode(heightMeasureSpec);

        //1.如果指定大小
        int width = MeasureSpec.getSize(widthMeasureSpec);
        //2.wrap_content 计算获取值
        if (widthMode == MeasureSpec.AT_MOST) {
            Rect bounds = new Rect();
            mPaint.getTextBounds(mText, 0, mText.length(), bounds);
            width = bounds.width() + getPaddingLeft() + getPaddingRight();
        }

        int height = MeasureSpec.getSize(heightMeasureSpec);
        if (heightMode == MeasureSpec.AT_MOST) {
            Rect bounds = new Rect();
            mPaint.getTextBounds(mText, 0, mText.length(), bounds);
            height = bounds.height() + getPaddingTop() + getPaddingBottom();
        }
        //设置控件的宽高
        setMeasuredDimension(width, height);

    }

    /**
     * 用于绘制
     *
     * @param canvas
     */
    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        Paint.FontMetricsInt fontMetrics = mPaint.getFontMetricsInt();
        int dy = (fontMetrics.bottom - fontMetrics.top) / 2 - fontMetrics.bottom;
        int baseLine = getHeight() / 2 + dy;

        canvas.drawText(mText, getPaddingLeft(), baseLine, mPaint);
    }

}

<?xml version="1.0" encoding="utf-8"?>