自定义View

为什么要自定义View?
因为Android系统内置的View无法实现我们的需求,所以要根据自己的实际的需求来自定义View


如何使用自定义View(流程)?

①自定义View的属性

②继承View(至少重写2个构造方法)

③重写的 onMeasure(测量当前View的尺寸)、onDraw(绘画)、onLayout(定位)、onTouchEvent(监听)方法


使用教程(可以分为2种,一种是不使用自定义的View属性 另一种就是使用自定义的View属性。)

①先说不使用自定义的View(构造方法至少写2个,我这块写了4个)

package com.example.dabin.www.day03_viewcircle;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.os.Build;
import android.support.annotation.RequiresApi;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;

/**
 * Created by Dabin on 2017/4/27.
 */

public class VirtualKeyView extends View {
    public VirtualKeyView(Context context) {
        super(context);
    }

    public VirtualKeyView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public VirtualKeyView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
    public VirtualKeyView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
    }

    //测量
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    }

    //绘制
    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

       //Paint 为画笔   Canvas为画布  

        Paint base = new Paint();       //最底部的圈
        Paint middle = new Paint();     //中间的圈
        Paint top = new Paint();        //最顶部的圈

        //选取屏幕中间
        float wi = canvas.getWidth() / 2;
        float he = canvas.getHeight() / 2;

        int baseR = dip2px(getContext(), 150); //设置底部圆半径
        int middleR = dip2px(getContext(), 80); //设置中间圈半径
        int topR = dip2px(getContext(), 50); //设置圆环宽度



        base.setARGB(255, 199, 33, 56);  //底部圈设置为红色
        middle.setColor(Color.WHITE);   //中间部圈设置为白色
        top.setColor(Color.BLUE);       //顶部圈设置为蓝色

        //画笔样式分三种: 1.Paint.Style.STROKE:描边    2.Paint.Style.FILL_AND_STROKE:描边并填充3.Paint.Style.FILL:填充
        //base.setStyle(Paint.Style.STROKE);  //给底部圈描边

        //设置描边的粗细,单位:像素px 注意:当setStrokeWidth(0)的时候描边宽度并不为0而是只占一个像素
        //base.setStrokeWidth(20);   //底部圈描边的粗细

        //设置画笔为抗齿锯
        base.setAntiAlias(true);
        middle.setAntiAlias(true);
        top.setAntiAlias(true);


        canvas.drawColor(Color.YELLOW);         //整体页面颜色
        canvas.drawCircle(wi, he, baseR, base);   //底部圈位置大小
        canvas.drawCircle(wi, he, middleR, middle);  //中间圈位置大小
        canvas.drawCircle(wi, he, topR, top);     //顶部圈位置大小

        canvas.drawText("X", wi, he, base);     //底部圈的字体
    }

    //定位
    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
        super.onLayout(changed, left, top, right, bottom);
    }

    //监听
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        return super.onTouchEvent(event);
    }

    //根据手机的分辨率从 dp 的单位 转成为 px(像素)
    public static int dip2px(Context context, float dpValue) {
        final float scale = context.getResources().getDisplayMetrics().density;
        return (int) (dpValue * scale + 0.5f);
    }

}

我这块直接在onDraw中进行一系列操作,Paint()为画笔, Canvas为画布,其中根据手机分辨率从dp单位转成为px,可以不用,在相应的位置上直接写上数也可以。

其中drawCircle为画圆、drawLine绘制直线、drawRect绘制矩形、drawBitmap绘制位图

效果如下:

android RoundedBackgroundSpan 设置间距_自定义


②使用View的属性(点击改变数字)

先在res/values下添加一个attrs.xml,在里面定义属性和声明样式

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <attr name="mText" format="string" />
    <attr name="mTextColor" format="color" />
    <attr name="mTextSize" format="dimension" />
    <declare-styleable name="MyView">
        <attr name="mText"/>
        <attr name="mTextColor"/>
        <attr name="mTextSize"/>
    </declare-styleable>
</resources>

接着在我们的布局文件中声明我们的自定义View

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    xmlns:dabin="http://schemas.android.com/apk/res-auto"
    android:id="@+id/activity_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="com.dabin.com.www.view.MainActivity">

    <com.example.dabin.www.day04_view.MyView
        android:layout_width="200dip"
        android:layout_height="100dip"
        android:textSize="20sp"
        dabin:mTextSize="25sp"
        dabin:mText="i love you"
        dabin:mTextColor ="#0000ff"
        android:background="#ff0000"/>

</RelativeLayout>

紧记一定要引入   xmlns:dabin="http://schemas.andoroid.com/apk/res-auto" 这句话,这是命名空间,dabin:mTextSize=”25sp“  这是对我们attrs.xml中声明属性的赋值。

接着看一下自定义View中的内容

package com.example.dabin.www.day04_view;

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.view.MotionEvent;
import android.view.View;

/**
 * Created by Dabin on 2017/9/28.
 */

public class MyView extends View {


    private String mText;// 文字
    private int mTextColor;// 颜色
    private int mTextSize; // 字体大小

    private Rect rect;
    private Paint paint;

    public MyView(Context context) {
        this(context, null);
    }

    public MyView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public MyView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);

        //获取自定义属性的值
        TypedArray a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.MyView, defStyleAttr, 0);

        mText = a.getString(R.styleable.MyView_mText); //获取attrs.xml中的字体
        mTextColor = a.getColor(R.styleable.MyView_mTextColor, Color.BLACK);//设置attrs.xml中的字体颜色
        mTextSize = (int) a.getDimension(R.styleable.MyView_mTextSize, 100);//设置attrs.xml中的字体大小

        a.recycle();  //注意回收

        paint = new Paint();
        paint.setTextSize(mTextSize); //设置字体大小
        paint.setColor(mTextColor);  //设置字体颜色

        //获得绘制文本的宽和高
        rect = new Rect();
        paint.getTextBounds(mText, 0, mText.length(), rect);
    }

    // 绘制
    @Override
    protected void onDraw(Canvas canvas) {
        canvas.drawText(mText, getWidth() / 2 - rect.width() / 2, getHeight() / 2 + rect.height() / 2, paint); //绘制文字
    }

    //监听
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()) {
            case MotionEvent.ACTION_MOVE:  //移动
                break;
            case MotionEvent.ACTION_DOWN:  //按下
                float a = (float) (Math.random() * 10000);  //生成一个随机数
                mText = "" + a;
                invalidate(); //更新视图
                break;
            case MotionEvent.ACTION_UP:  //抬起
                break;
        }
        //这句话不要修改
        return super.onTouchEvent(event);
    }
}

在构造方法中,获取自定义View的对象,然后对其进行赋值。

在onTouchEvent()监听方法中设置点击改变值。

效果如下:

android RoundedBackgroundSpan 设置间距_android_02


这些就是自定义View的一些简单使用。