美文网首页
Android自定义View

Android自定义View

作者: 你大爷终归是你大爷 | 来源:发表于2020-05-24 23:14 被阅读0次

xml创建自定义View

一、创建View的属性

在values中创建attrs.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="TestView">
        <attr name="test_boolean" format="boolean"></attr>
        <attr name="test_string" format="string"></attr>
        <attr name="test_integer" format="integer"></attr>
        <attr name="test_emum" format="enum">
            <enum name="top" value="1"></enum>
            <enum name="bottom" value="2"></enum>
        </attr>
        <attr name="test_dimension" format="dimension"></attr>
    </declare-styleable>
</resources>

二、创建View类

package com.example.testcustomview;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.os.Bundle;
import android.os.Parcelable;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;

import androidx.annotation.Nullable;

public class TestView extends View {
    private static final String TAG = "TestView";

    private boolean booleanTest;
    private int integerTest;
    private String stringTest = "TestString";
    private int enumTest;
    private float dimensionTest;
    private Paint mPaint;

    public TestView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        initPant();
        TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.TestView);
        booleanTest = typedArray.getBoolean(R.styleable.TestView_test_boolean, false);
        int count = typedArray.getIndexCount();
        for (int i=0;i<count;i++) {
            int index = typedArray.getIndex(i);
            switch (index) {
                case R.styleable.TestView_test_boolean:
                    booleanTest = typedArray.getBoolean(R.styleable.TestView_test_boolean,false);
                    break;
                case R.styleable.TestView_test_integer:
                    integerTest = typedArray.getInteger(R.styleable.TestView_test_integer,0);
                    break;
                case R.styleable.TestView_test_string:
                    stringTest = typedArray.getString(R.styleable.TestView_test_string);
                    break;
                case R.styleable.TestView_test_emum:
                    enumTest = typedArray.getInt(R.styleable.TestView_test_emum,1);
                    break;
                case R.styleable.TestView_test_dimension:
                    dimensionTest = typedArray.getDimension(R.styleable.TestView_test_dimension,0);
                    break;
            }
        }
        Log.d(TAG, "TestView() called with: context = [" + context + "], attrs = [" + attrs + "]");
        Log.d(TAG, "TestView: \n  booleanTest:"+booleanTest +
                "\n  integerTest:"+integerTest +
                "\n  stringTest:"+stringTest +
                "\n  enumTest:"+enumTest +
                "\n  dimensionTest:"+dimensionTest);

        //回收
        typedArray.recycle();
    }

    private void initPant() {
        mPaint = new Paint();
        mPaint.setStyle(Paint.Style.STROKE);
        mPaint.setStrokeWidth(6);
        mPaint.setColor(0xFFFF0000);
        mPaint.setAntiAlias(true);
    }

    //测量
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec,heightMeasureSpec);
        //本控件宽
        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        int widthSize = MeasureSpec.getSize(widthMeasureSpec);
        int width = 0;
        // MeasureSpec.EXACTLY 确定宽高
        if (widthMode == MeasureSpec.EXACTLY) {
            width = widthSize;
        } else {
            int needWidth = measureWidth() + getPaddingLeft() + getPaddingRight();
            // MeasureSpec.AT_MOST 不错过给定宽度
            if (widthMode == MeasureSpec.AT_MOST) {
                width = Math.min(needWidth,widthSize);
            } else { //MeasureSpec.UNSPECIFIED 按照计算宽度
                width = needWidth;
            }
        }

        //本控件高
        int heightMode = MeasureSpec.getMode(heightMeasureSpec);
        int heightSize = MeasureSpec.getSize(heightMeasureSpec);
        int height = 0;
        if (heightMode == MeasureSpec.EXACTLY) {
            height = heightSize;
        } else {
            int needHeight = measureHight() + getPaddingTop() + getPaddingBottom();
            if (heightMode == MeasureSpec.AT_MOST) {
                height = Math.min(needHeight,heightSize);
            } else {
                height = needHeight;
            }
        }
        setMeasuredDimension(width,height);
    }

    private int measureHight() {
        return 0;
    }

    private int measureWidth() {
        return 0;
    }

    //绘制
    @Override
    protected void onDraw(Canvas canvas) {
        mPaint.setStyle(Paint.Style.STROKE);
        mPaint.setStrokeWidth(6);
        canvas.drawCircle(getWidth()/2,getHeight()/2,getWidth()/2-mPaint.getStrokeWidth(),mPaint);
        mPaint.setStrokeWidth(1);
        //横线
        canvas.drawLine(0,getHeight()/2,getWidth(),getHeight()/2,mPaint);
        //竖线
        canvas.drawLine(getWidth()/2,0,getWidth()/2,getHeight(),mPaint);

        mPaint.setTextSize(96);
        mPaint.setStyle(Paint.Style.FILL);
        canvas.drawText(stringTest,0,getHeight(),mPaint);
    }

    //触发事件
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        stringTest = "8888";
        invalidate();
        return true;
    }

    private static final String INSTANCE = "instance";
    private static final String KEY_TEXT = "key_text";

    //点击后stringTest改为8888,为保存状态用下面两个方法
    //保存数据状态
    @Nullable
    @Override
    protected Parcelable onSaveInstanceState() {
        Bundle bundle = new Bundle();
        bundle.putString(KEY_TEXT,stringTest);
        //保存父View的状态
        bundle.putParcelable(INSTANCE,super.onSaveInstanceState());
        return bundle;
    }

    //获取状态
    @Override
    protected void onRestoreInstanceState(Parcelable state) {
        if (state instanceof Bundle) {
            Bundle bundle = (Bundle) state;
            Parcelable parcelable = bundle.getParcelable(INSTANCE);
            super.onRestoreInstanceState(parcelable);
            stringTest = bundle.getString(KEY_TEXT);
            return;
        }
        super.onRestoreInstanceState(state);
    }
}

三、在activity_main.xml中加入View

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    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.testcustomview.TestView
        android:id="@+id/mainView"
        android:layout_width="300dp"
        android:layout_height="300dp"
        android:layout_centerInParent="true"
        android:background="@color/colorPrimaryDark"
        app:test_boolean="true"
        app:test_integer="1"
        app:test_string="abcgjef"
        app:test_dimension="100dp"
        app:test_emum="bottom">

    </com.example.testcustomview.TestView>

</RelativeLayout>

相关文章

网友评论

      本文标题:Android自定义View

      本文链接:https://www.haomeiwen.com/subject/nvisahtx.html