一步一步學自定義View(1.簡單入門)

1、自定義View

android中可能遇到很多需求要求自定義view,一般github上都有各種各樣的酷炫效果自定義view,特別是儀表盤,柱狀圖,餅狀圖都有,但還是不免遇到一些特別的需求,自定義樣式難以修改開源庫,因此還是需要自己來實現。接下來記錄自己一點一點學習自定義view的過程。接下來主要實現這樣的效果(簡單的實現畫圓,和簡單的動畫效果)
項目目錄結構
這裏寫圖片描述 這裏寫圖片描述

2、自定義view中構造方法

構造方法用來初始化view,一般的定義的view比如圓的寬,高,圓的顏色等,都是在我們xml文件中配置的,因此,我們必須重寫帶有AttributeSet的構造方法

   /**
     * 當需要在xml中聲明此控件,則需要實現此構造函數
     * 並且在構造函數中把自定義的屬性與控件的數據成員連接起來
     *
     * @param context
     * @param attrs
     */
    public View1(Context context, AttributeSet attrs) {
        super(context, attrs);
        //如果xml文件中沒有文件,則使用後面默認值;
        paintOut = new Paint();
        paintIn=new Paint();
        //從attrs讀取屬性
        TypedArray typedArray = context.obtainStyledAttributes(attrs,
                R.styleable.MyView1);
        this.cicle_in_color = typedArray.getColor(R.styleable.MyView1_cicle_in_color, Color.BLACK);
        this.cicle_in_radius = typedArray.getDimension(R.styleable.MyView1_cicle_in_radius, 100);
        this.cicle_in_StrokeWidth = typedArray.getDimension(R.styleable.MyView1_cicle_in_StrokeWidth, 5);

        this.cicle_out_color = typedArray.getColor(R.styleable.MyView1_cicle_out_color, Color.BLACK);
        this.cicle_out_radius = typedArray.getDimension(R.styleable.MyView1_cicle_out_radius, 30);
        this.cicle_out_StrokeWidth = typedArray.getDimension(R.styleable.MyView1_cicle_out_StrokeWidth, 5);

        //打開抗鋸齒
        paintOut.setAntiAlias(true);
        //設置xml文件中的屬性
        paintOut.setColor(cicle_out_color);
        paintOut.setStyle(Paint.Style.STROKE);
        paintOut.setStrokeWidth(cicle_out_StrokeWidth);


        paintIn.setColor(cicle_in_color);
        paintIn.setStyle(Paint.Style.STROKE);
        paintIn.setStrokeWidth(cicle_in_StrokeWidth);
        //回收TypedArray,以便後面重用
        typedArray.recycle();
    }

3、在xml文件中配置自定義view的屬性、

在values下新建attrs.xml文件

<?xml version="1.0" encoding="utf-8"?>
<resources>
    //自定義屬性名,定義公共屬性
    <attr name="textSize" format="dimension"></attr>
    <attr name="textTitle" format="string"></attr>
    <attr name="textColor" format="color"></attr>
    <attr name="cicle_color" format="color"></attr>
    <attr name="cicle_radius" format="dimension"></attr>
    <declare-styleable name="MyView1">
        <attr name="cicle_color"></attr>
        <attr name="cicle_out_color" format="color"></attr>
        <attr name="cicle_out_radius" format="dimension"></attr>
        <attr name="cicle_out_StrokeWidth" format="dimension"></attr>

        <attr name="cicle_in_color" format="color"></attr>
        <attr name="cicle_in_radius" format="dimension"></attr>
        <attr name="cicle_in_StrokeWidth" format="dimension"></attr>
    </declare-styleable>

    <declare-styleable name="MyView2">
        <attr name="textSize"></attr>
        <attr name="textTitle"></attr>
        <attr name="textColor"></attr>
        <attr name="cicle_color"></attr>
        <attr name="cicle_StrokeWidth" format="dimension"></attr>
        <attr name="cicle_radius"></attr>

    </declare-styleable>

</resources>

這樣,就可以在界面的xml文件中配置這些屬性,添加命名空間和聲明的屬性名稱
這裏寫圖片描述

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:custom="http://schemas.android.com/apk/res-auto"
    android:id="@+id/activity_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin">

    <view.viewActivity1.View1
        android:layout_width="100dp"
        android:layout_height="100dp"
        custom:cicle_in_StrokeWidth="5dp"
        custom:cicle_in_color="#00ff00"
        custom:cicle_in_radius="20dp"
        custom:cicle_out_StrokeWidth="5dp"
        custom:cicle_out_color="#ff0000"
        custom:cicle_out_radius="45dp"

        />

    <view.viewActivity1.View2
        android:id="@+id/view2"
        android:layout_width="100dp"
        android:layout_height="100dp"
        custom:cicle_StrokeWidth="5dp"
        custom:cicle_color="#0000ff" />
</LinearLayout>

4、自定義view的主要代碼,在代碼中做詳解

1、畫圓的主要代碼

package view.viewActivity1;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.View;

import com.example.cusotmerview.R;

/**
 * Created by yuxiaogang on 2017/2/23.
 */

public class View1 extends View {

    private Paint paintOut;
    private Paint paintIn;

    private int cicle_in_color;
    private float cicle_in_radius;
    private float cicle_in_StrokeWidth;

    private int cicle_out_color;
    private float cicle_out_radius;
    private float cicle_out_StrokeWidth;

    public View1(Context context) {
        super(context);
    }

    /**
     * 當需要在xml中聲明此控件,則需要實現此構造函數
     * 並且在構造函數中把自定義的屬性與控件的數據成員連接起來
     *
     * @param context
     * @param attrs
     */
    public View1(Context context, AttributeSet attrs) {
        super(context, attrs);
        //如果xml文件中沒有文件,則使用後面默認值;
        paintOut = new Paint();
        paintIn=new Paint();
        //從attrs讀取屬性
        TypedArray typedArray = context.obtainStyledAttributes(attrs,
                R.styleable.MyView1);
        this.cicle_in_color = typedArray.getColor(R.styleable.MyView1_cicle_in_color, Color.BLACK);
        this.cicle_in_radius = typedArray.getDimension(R.styleable.MyView1_cicle_in_radius, 100);
        this.cicle_in_StrokeWidth = typedArray.getDimension(R.styleable.MyView1_cicle_in_StrokeWidth, 5);

        this.cicle_out_color = typedArray.getColor(R.styleable.MyView1_cicle_out_color, Color.BLACK);
        this.cicle_out_radius = typedArray.getDimension(R.styleable.MyView1_cicle_out_radius, 30);
        this.cicle_out_StrokeWidth = typedArray.getDimension(R.styleable.MyView1_cicle_out_StrokeWidth, 5);

        //打開抗鋸齒
        paintOut.setAntiAlias(true);
        //設置xml文件中的屬性
        paintOut.setColor(cicle_out_color);
        paintOut.setStyle(Paint.Style.STROKE);
        paintOut.setStrokeWidth(cicle_out_StrokeWidth);


        paintIn.setColor(cicle_in_color);
        paintIn.setStyle(Paint.Style.STROKE);
        paintIn.setStrokeWidth(cicle_in_StrokeWidth);
        //回收TypedArray,以便後面重用
        typedArray.recycle();
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        /**
         * 第一個參數:圓心x座標
         * 第二個參數:圓心y座標
         * 第三個參數:半徑
         * 第四個參數:paint畫筆
         */
        canvas.drawCircle(100, 100, cicle_out_radius, paintOut);
        canvas.drawCircle(100, 100, cicle_in_radius, paintIn);

    }
}

2、畫圓有動畫效果的代碼

package view.viewActivity1;

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

import com.example.cusotmerview.R;

/**
 * Created by yuxiaogang on 2017/2/23.
 */

public class View2 extends View {

    private Paint circlePaint;
    private RectF circleRect;

    private int cicle_out_color;
    private float cicle_out_radius;
    private float cicle_out_StrokeWidth;
    private int mCurrentPercent;

    public int getmTargetPercent() {
        return mTargetPercent;
    }

    public void setmTargetPercent(int mTargetPercent) {
        this.mTargetPercent = mTargetPercent;
    }

    private int mTargetPercent;
    private float mCurrentAngle;
    private float mStartSweepValue;

    public View2(Context context) {
        super(context);
    }

    /**
     * 當需要在xml中聲明此控件,則需要實現此構造函數
     * 並且在構造函數中把自定義的屬性與控件的數據成員連接起來
     *
     * @param context
     * @param attrs
     */
    public View2(Context context, AttributeSet attrs) {
        super(context, attrs);
        //如果xml文件中沒有文件,則使用後面默認值;
        circlePaint = new Paint();
        //從attrs讀取屬性
        TypedArray typedArray = context.obtainStyledAttributes(attrs,
                R.styleable.MyView2);
        this.cicle_out_color = typedArray.getColor(R.styleable.MyView2_cicle_color, Color.BLACK);
        this.cicle_out_radius = typedArray.getDimension(R.styleable.MyView2_cicle_radius, 30);
        this.cicle_out_StrokeWidth = typedArray.getDimension(R.styleable.MyView2_cicle_StrokeWidth, 5);
        //回收TypedArray,以便後面重用
        typedArray.recycle();
        init();
    }

    private void init() {
        mStartSweepValue = 180;
        //當前角度
        mCurrentAngle = 0;
        //當前百分比
        mCurrentPercent = 0;
        circleRect = new RectF(20, 20, getWidth() - 20, getWidth() - 20);
    }

    public void setNumber(int size) {
        mCurrentPercent = 0;
        mTargetPercent = size;
        mCurrentAngle = 0;
        postInvalidate();
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        //打開抗鋸齒
        circlePaint.setAntiAlias(true);
        //設置xml文件中的屬性
        circlePaint.setColor(cicle_out_color);
        circlePaint.setStyle(Paint.Style.STROKE);
        circlePaint.setStrokeWidth(cicle_out_StrokeWidth);
        // 通過上下左右4個邊的座標來表示一個矩形,畫圓就在這個矩形區域內;
        circleRect = new RectF(10, 10, getWidth() - 10, getWidth() - 10);
        /**
         * drawArc()
         * 第一個參數:圓弧外的輪廓區域
         * 第二個參數,圓弧開始的角度
         * 第三個參數,圓弧順時針掃過的角度
         * 第四個參數, 如果爲True時,在繪製圓弧時將圓心包括在內,通常用來繪製扇形
         * 第五個參數,畫布
         */
        canvas.drawArc(circleRect, mStartSweepValue, mCurrentAngle, false, circlePaint);
        if (mCurrentPercent < mTargetPercent) {
            //當前百分比+1
            mCurrentPercent += 2;
            //當前角度+360
            mCurrentAngle += 7.2;

            //每100ms重畫一次
            postInvalidateDelayed(100);
        }
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章