简单的饼状图

先上效果图
简单的饼状图_第1张图片
注:绿边是自定义的,可以随意修改。如果需要修改,参见 PieChart 文件中的 TODO 说明
1、把代码复制到自己的项目中,用到的布局资源、源码在附录中。因为需要几个文件,因此,建议放到一个文件夹下。因为不会上传文件,只能把代码复制出来放到附录里。
2、布局代码:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout  xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" >

    <LinearLayout  android:id="@+id/pie" android:layout_width="match_parent" android:layout_height="180dp" android:background="#FFFFFF" android:orientation="horizontal">

        <com.example.lenovo.demo.view.cakeview.PieChart  android:id="@+id/piechart" android:layout_width="140dp" android:layout_height="140dp" android:layout_gravity="center_vertical" android:layout_marginLeft="10dp"/>

        <ListView  android:id="@+id/listView_plan_detail" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_gravity="center_vertical" android:layout_marginLeft="10dp" android:divider="@null" android:listSelector="#00000000">
        </ListView>
    </LinearLayout>
</LinearLayout>

3、实现代码:
为了方便管理颜色,写了个全局变量,实际使用,可以根据自己的方式写。如果也要写全局变量,注意颜色数组长度,防止角标越界

package com.example.lenovo.demo;

public class PARAM {
    // 颜色
    public static final int[] COLORS = new int[]{0xfff5be63, 0xfff4a21a, 0xff9bcade, 0xff11a0c2, 0xff007aa1,0xffef7417};
}

主代码:

package com.example.lenovo.demo;

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ListView;
import android.widget.TextView;

import com.example.lenovo.demo.view.cakeview.PieChart;
import com.example.lenovo.demo.view.cakeview.TitleValueEntity;

import java.util.ArrayList;

public class MainActivity extends AppCompatActivity {

    private ArrayList<TitleValueEntity> listData;
    private PieChart pie_chart;
    private ListView listView;
    private MyAdapter adapter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        pie_chart = (PieChart) findViewById(R.id.piechart);
        listView = (ListView) findViewById(R.id.listView_plan_detail);

        listData = new ArrayList<TitleValueEntity>();

        initView();

        adapter = new MyAdapter();
        listView.setAdapter(adapter);
        pie_chart.setData(listData);
        pie_chart.invalidate();
    }

    private void initView() {
        listData.add(new TitleValueEntity("未分配", 10, 0, "code-1"));
        listData.add(new TitleValueEntity("游戏", 35, 0, "code-2"));
        listData.add(new TitleValueEntity("购物", 30, 0, "code-3"));
        listData.add(new TitleValueEntity("旅游", 5, 0, "code-4"));
        listData.add(new TitleValueEntity("吃饭", 20, 0, "code-5"));
    }

    class MyAdapter extends BaseAdapter {

        @Override
        public int getCount() {
            return listData.size();
        }

        @Override
        public Object getItem(int position) {
            return listData.get(position);
        }

        @Override
        public long getItemId(int position) {
            return position;
        }

        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            View view = LayoutInflater.from(MainActivity.this).inflate(R.layout.item_piechat, null);
            TextView tv = (TextView) view.findViewById(R.id.tv_pie_data);
            view.findViewById(R.id.color).setBackgroundColor(PARAM.COLORS[position]);
            TitleValueEntity item = listData.get(position);
            String title = item.getTitle();
            String code = item.getCode();
            tv.setText(title + code + ": "
                    + item.getValue() + "%");
            return view;
        }
    }
}

注:上面的code-1这些值,可以为空,这里为了有扩展性,先加上了。

附录:
1、建议的工程结构图
简单的饼状图_第2张图片

2、PieChart:用于显示饼状图


package com.example.lenovo.demo.view.cakeview;

import android.animation.PropertyValuesHolder;
import android.animation.ValueAnimator;
import android.animation.ValueAnimator.AnimatorUpdateListener;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Paint.Style;
import android.graphics.Point;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.view.animation.DecelerateInterpolator;

import com.example.lenovo.demo.PARAM;

import java.util.List;

public class PieChart extends RoundChart {

    protected List<TitleValueEntity> data;
    private ValueAnimator cakeValueAnimator;
    private float curAngle;

    private float obj2Float(Object o) {
        return ((Number) o).floatValue();
    }

    public PieChart(Context context) {
        super(context);
        PropertyValuesHolder angleValues = PropertyValuesHolder.ofFloat(
                "angle", 0f, 360f);
        cakeValueAnimator = ValueAnimator.ofPropertyValuesHolder(angleValues);
        cakeValueAnimator.addUpdateListener(new AnimatorUpdateListener() {

            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                float mAngle = obj2Float(animation.getAnimatedValue("angle"));
                curAngle = mAngle;
            }
        });
        cakeValueAnimator.setDuration(1500);
        cakeValueAnimator.setRepeatCount(0);
        cakeValueAnimator.setInterpolator(new DecelerateInterpolator());
        cakeValueAnimator.setRepeatMode(ValueAnimator.RESTART);
    }

    public PieChart(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }

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

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

        int rect = super.getWidth() > super.getHeight() ? super.getHeight()
                : super.getWidth();

        longitudeLength = (int) ((rect / 2f) * 0.90);

        position = new Point((int) (getWidth() / 2f), (int) (getHeight() / 2f));

        drawCircle(canvas);

        drawData(canvas);
    }

    protected void drawCircle(Canvas canvas) {

        Paint mPaintCircleBorder = new Paint();
        mPaintCircleBorder.setStyle(Style.STROKE);
        mPaintCircleBorder.setStrokeWidth(1);
        mPaintCircleBorder.setAntiAlias(true);

        //TODO 这个颜色是设置饼状图最外面的圆环颜色。这里为了显示明显,设置成绿色
        mPaintCircleBorder.setColor(0xff00ff00);

        mPaintCircleBorder.setStyle(Style.FILL);
        canvas.drawCircle(position.x, position.y, longitudeLength + 15,
                mPaintCircleBorder);
        mPaintCircleBorder.setStyle(Style.STROKE);
        mPaintCircleBorder.setColor(circleBorderColor);
        canvas.drawCircle(position.x, position.y, longitudeLength,
                mPaintCircleBorder);
    }

    protected void drawData(Canvas canvas) {
        if (null != data) {
            float sum = 0;
            for (int i = 0; i < data.size(); i++) {
                sum = sum + data.get(i).getValue();
            }

            Paint mPaintFill = new Paint();
            mPaintFill.setStyle(Style.FILL);
            mPaintFill.setAntiAlias(true);

            Paint mPaintBorder = new Paint();
            mPaintBorder.setStyle(Style.STROKE);
            mPaintBorder.setColor(longitudeColor);
            mPaintBorder.setAntiAlias(true);

            int offset = -90;
            for (int j = 0; j < data.size(); j++) {
                TitleValueEntity e = data.get(j);
                if (e.getValue() == 0)
                    continue;
                mPaintFill.setColor(PARAM.COLORS[j]);

                RectF oval = new RectF(position.x - longitudeLength, position.y
                        - longitudeLength, position.x + longitudeLength, position.y
                        + longitudeLength);
                int sweep = Math.round(e.getValue() / sum * 360f);
                canvas.drawArc(oval, offset, sweep, true, mPaintFill);
                canvas.drawArc(oval, offset, sweep, true, mPaintBorder);
                offset = offset + sweep;
            }
        }
    }

    public List<TitleValueEntity> getData() {
        return data;
    }

    public void setData(List<TitleValueEntity> data) {
        this.data = data;
    }
}

3、AbstractChart

package com.example.lenovo.demo.view.cakeview;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Paint.Style;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.view.View;

/** * 所有图表对象的基类 */
public abstract class AbstractChart extends View {

    /** * 默认控件是否显示边框 */
    public static final boolean DEFAULT_DISPLAY_BORDER = Boolean.FALSE;

    /** * 默认经线刻度字体颜色 */
    public static final int DEFAULT_BORDER_COLOR = Color.LTGRAY;

    public static final float DEFAULT_BORDER_WIDTH = 1f;

    /** * 控件是否显示边框 */
    protected boolean displayBorder = DEFAULT_DISPLAY_BORDER;

    /** * 图边框的颜色 */
    protected int borderColor = DEFAULT_BORDER_COLOR;
    protected float borderWidth = DEFAULT_BORDER_WIDTH;
    public AbstractChart(Context context) {
        super(context);
    }

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

    public AbstractChart(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        if (this.displayBorder) {
            drawBorder(canvas);
        }
    }

    /** * 绘制边框 */
    protected void drawBorder(Canvas canvas) {
        Paint mPaint = new Paint();
        mPaint.setColor(borderColor);
        mPaint.setStrokeWidth(borderWidth);
        mPaint.setStyle(Style.STROKE);
        // draw a rectangle
        canvas.drawRect(borderWidth / 2, borderWidth / 2, super.getWidth()
                - borderWidth / 2, super.getHeight() - borderWidth / 2, mPaint);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        setMeasuredDimension(measureWidth(widthMeasureSpec),
                measureHeight(heightMeasureSpec));
    }

    @Override
    protected void onFocusChanged(boolean gainFocus, int direction,
            Rect previouslyFocusedRect) {
        super.onFocusChanged(gainFocus, direction, previouslyFocusedRect);
    }

    private int measureWidth(int measureSpec) {
        int result = 0;
        int specMode = MeasureSpec.getMode(measureSpec);
        int specSize = MeasureSpec.getSize(measureSpec);

        if (specMode == MeasureSpec.EXACTLY) {
            result = specSize;
        } else if (specMode == MeasureSpec.AT_MOST) {
            result = Math.min(result, specSize);
        }
        return result;
    }

    private int measureHeight(int measureSpec) {
        int result = 0;
        int specMode = MeasureSpec.getMode(measureSpec);
        int specSize = MeasureSpec.getSize(measureSpec);

        if (specMode == MeasureSpec.EXACTLY) {
            result = specSize;
        } else if (specMode == MeasureSpec.AT_MOST) {
            result = Math.min(result, specSize);
        }
        return result;
    }   

}

4、RoundChart

package com.example.lenovo.demo.view.cakeview;

import android.content.Context;
import android.graphics.Color;
import android.graphics.Point;
import android.util.AttributeSet;


public class RoundChart extends AbstractChart {

    /** * 默认图表标题 */
    public static final String DEFAULT_TITLE = "Round Chart";

    /** * 默认是否显示经线 */
    public static final boolean DEFAULT_DISPLAY_LONGITUDE = true;

    /** * 默认半径长度 */
    public static final int DEFAULT_LONGITUDE_LENGTH = 55;

    /** * 默认经线颜色 */
    public static final int DEFAULT_LONGITUDE_COLOR = Color.WHITE;

    /** * 默认圆弧的颜色 */
    public static final int DEFAULT_CIRCLE_BORDER_COLOR = Color.WHITE;

    /** * 默认绘图中心位置 */
    public static final Point DEFAULT_POSITION = new Point(0, 0);

    /** * 绘图中心位置 */
    protected Point position = DEFAULT_POSITION;

    /** * 半径长度 */
    protected float longitudeLength = DEFAULT_LONGITUDE_LENGTH;

    /** * 经线颜色 */
    protected int longitudeColor = DEFAULT_LONGITUDE_COLOR;

    /** * 圆弧的颜色 */
    protected int circleBorderColor = DEFAULT_CIRCLE_BORDER_COLOR;

    public RoundChart(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }

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

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

}

5、TitleValueEntity:一个bean文件

package com.example.lenovo.demo.view.cakeview;

public class TitleValueEntity {

    private String title;
    private int value;
    private int color;
    private String code;

    public TitleValueEntity(String title, int value, int color, String code) {
        this.title = title;
        this.value = value;
        this.color = color;
        this.code = code;
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public int getValue() {
        return value;
    }

    public void setValue(int value) {
        this.value = value;
    }

    public int getColor() {
        return color;
    }

    public void setColor(int color) {
        this.color = color;
    }

    public String getCode() {
        return code;
    }

    public void setCode(String code) {
        this.code = code;
    }
}

6、右侧listview的条目布局

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="horizontal" >
    <LinearLayout  android:layout_width="match_parent" android:layout_height="25dp" android:orientation="horizontal" android:gravity="center_vertical" >
    <TextView android:id="@+id/color" android:layout_width="10dp" android:layout_height="10dp" android:layout_marginRight="5dp" />
    <TextView android:id="@+id/tv_pie_data" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textSize="14sp" android:textColor="#666666" />
</LinearLayout>
</LinearLayout>

你可能感兴趣的:(饼状图)