天天看點

自定義控件(一) 一個比例餅狀圖

自定義控件(一) 一個比例餅狀圖

前言:看了很多鴻洋的文章,感覺受益匪淺,正巧 今天在android聊天群裡看到有這個需求,發現和鴻洋的這篇部落格(http://blog.csdn.net/lmj623565791/article/details/24500107)很類似,正好我項目也不忙,我就自己實作了一下。

前期分析:外面的圓環就是根據比例把圓弧畫出來就可以了,裡邊的文字和圖檔,剛看時我是想也畫出來,但是後來考慮如果裡邊的東西以後改變了,修改起來也是很麻煩的,于是我就改成勇相對布局嵌套一下,我想這樣也是更好實作,擴充性也比較好。

一,首先分析一下這個圖

這個圖外邊圓環中圓弧的比例需要傳遞過來,顔色也需要指定,和外環的寬度也要指定,比例和顔色應該用集合的形式傳遞,而圓環的寬度可以用自定義屬性。

-----------------------------------------------------------------------------------------------------

1.自定義屬性

<resources>

    <attr name="strokeWidth" format="dimension" />

    <declare-styleable name="RoundChatView">
        <attr name="strokeWidth" />
    </declare-styleable>

</resources>      

2.擷取我們自定義的屬性

TypedArray a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.RoundChatView, defStyleAttr, 0);
int n = a.getIndexCount();
for (int i = 0; i < n; i++) {
    int attr = a.getIndex(i);
    switch (attr) {
        case R.styleable.RoundChatView_strokeWidth:  // 圓環寬度
            mStrokeWidth = a.getDimensionPixelSize(attr, (int) TypedValue.applyDimension(
                    TypedValue.COMPLEX_UNIT_PX, 20, getResources().getDisplayMetrics()));
            break;

    }

}      

3.重寫onDraw()方法

@Override
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    mWidth = getWidth();

    mPaint.setColor(Color.RED);
    mPaint.setStyle(Paint.Style.STROKE);
    mPaint.setStrokeWidth(mStrokeWidth); // 設定圓環的寬度

    int centre = mWidth / 2; // 擷取圓心的x坐标
    int radius = centre - mStrokeWidth / 2;// 半徑
    RectF oval = new RectF(centre - radius, centre - radius, centre + radius, centre + radius); // 用于定義的圓弧的形狀和大小的界限

    // 畫圓環
    for (int i = 0; i < mCount; i++) {
        float degree = mDegree.get(i);
        lastDegree += degree;
        mPaint.setColor(i > mColor.length ? mColor[i - mColor.length] : mColor[i]);  // 循環取顔色值
        canvas.drawArc(oval, -90 - lastDegree, degree, false, mPaint); // 根據角度畫圓弧
    }
}      

4.在布局中使用

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:custom="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    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.aijie.viewandgroupapp.MainActivity">

    <com.aijie.viewandgroupapp.view.RoundChatView
        android:id="@+id/roundChat"
        android:layout_width="300dp"
        android:layout_height="300dp"
        android:layout_centerInParent="true"
        custom:strokeWidth="50dp" />

    <LinearLayout
        android:layout_width="150dp"
        android:layout_height="150dp"
        android:layout_centerInParent="true"
        android:gravity="center_horizontal"
        android:orientation="vertical">

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="20dp"
            android:text="總支出"
            android:textColor="#666666"
            android:textSize="17sp" />

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="20dp"
            android:text="12120.00"
            android:textColor="#666666"
            android:textSize="26sp"
            android:textStyle="bold" />

        <ImageView
            android:layout_width="30dp"
            android:layout_height="30dp"
            android:layout_marginTop="25dp"
            android:src="@drawable/icon_center" />
    </LinearLayout>
</RelativeLayout>      

5.在代碼中設定

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    act = this;
    roundChat = (RoundChatView) findViewById(R.id.roundChat);
    List<Float> ratioList = new ArrayList<Float>();
    ratioList.add(0.2f);
    ratioList.add(0.1f);
    ratioList.add(0.35f);
    ratioList.add(0.2f);
    ratioList.add(0.15f);
    // 設定餅狀圖的比例
    roundChat.setCount(5, ratioList);
}      

6.最終效果圖

自定義控件(一) 一個比例餅狀圖

基本實作效果,具體的顔色控制可以再優化。

這個附上這個自定義控件的源碼:

package com.aijie.viewandgroupapp.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.RectF;
import android.util.AttributeSet;
import android.util.Log;
import android.util.TypedValue;
import android.view.View;

import com.aijie.viewandgroupapp.R;

import java.util.ArrayList;
import java.util.List;

/**
 * Created by Administrator on 2016/7/8 0008.
 * 餅狀圖
 */
public class RoundChatView extends View {

    private Context mContext;
    /**
     * 控件的寬度
     */
    private int mWidth;

    /**
     * 圓環的寬度
     */
    private int mStrokeWidth;

    /**
     * 畫筆
     */
    private Paint mPaint;
    /**
     * 一共多少份
     */
    private int mCount = 0;
    /**
     * 每份所占的比例
     */
    private List<Float> mList = new ArrayList<Float>();
    /**
     * 餅狀圖每塊的顔色
     */
    private int[] mColor = {Color.RED, Color.BLUE, Color.YELLOW, Color.GREEN, Color.BLUE};
    /**
     * 存儲沒份所占的角度
     */
    private List<Float> mDegree = new ArrayList<>();

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

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

    public RoundChatView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        mContext = context;
        mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);

        // 擷取自定義的屬性
        TypedArray a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.RoundChatView, defStyleAttr, 0);
        int n = a.getIndexCount();
        for (int i = 0; i < n; i++) {
            int attr = a.getIndex(i);
            switch (attr) {
                case R.styleable.RoundChatView_strokeWidth:  // 圓環寬度
                    mStrokeWidth = a.getDimensionPixelSize(attr, (int) TypedValue.applyDimension(
                            TypedValue.COMPLEX_UNIT_PX, 20, getResources().getDisplayMetrics()));
                    break;

            }

        }
    }

    private void initData(Context context) {
        // 計算角度
        if (mList.size() > 0) {
            for (int i = 0; i < mList.size(); i++) {
                Float ratio = mList.get(i);
                Float degree = 360 * ratio;
                mDegree.add(degree);
            }
        }
    }

    /**
     * 設定份數和所占比例
     *
     * @param count
     * @param list
     */
    public void setCount(int count, List<Float> list) {
        this.mCount = count;
        this.mList = list;
        initData(mContext);
    }

    private int lastDegree = 0;  //已經畫過的角度

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        mWidth = getWidth();

        mPaint.setColor(Color.RED);
        mPaint.setStyle(Paint.Style.STROKE);
        mPaint.setStrokeWidth(mStrokeWidth); // 設定圓環的寬度

        int centre = mWidth / 2; // 擷取圓心的x坐标
        int radius = centre - mStrokeWidth / 2;// 半徑
        RectF oval = new RectF(centre - radius, centre - radius, centre + radius, centre + radius); // 用于定義的圓弧的形狀和大小的界限

        // 畫圓環
        for (int i = 0; i < mCount; i++) {
            float degree = mDegree.get(i);
            Log.i("aijie", "角度==" + degree);
            lastDegree += degree;
            mPaint.setColor(i > mColor.length ? mColor[i - mColor.length] : mColor[i]);  // 循環取顔色值
            canvas.drawArc(oval, -90 - lastDegree, degree, false, mPaint); // 根據角度畫圓弧
        }
    }
}