【Android】自定义View -- 条形图(柱状图)

【问题】

实现可动态变化的条形图;

【效果图】


 

【用法】

How to use1?

<!-- xml -->

<com.lyloou.view.HistogramView
android:id="@+id/dcv_7"
android:layout_margin="16dp"
android:padding="16dp"
android:layout_width="match_parent"
android:layout_height="match_parent" />

<!-- Activity -->

HistogramView dcv7 = (HistogramView) view.findViewById(R.id.dcv_7);
ArrayList<Bar> bar7Lists = new ArrayList<Bar>();
Bar bar1 = dcv7.new Bar(1, 0.3f, Color.parseColor("#b6bcc8"), "one", "30");
Bar bar2 = dcv7.new Bar(2, 0.65f, Color.parseColor("#ff2d65"), "two", "65");
Bar bar3 = dcv7.new Bar(3, 0.8f, Color.parseColor("#59bbfa"), "three", "80");
bar7Lists.add(bar1);
bar7Lists.add(bar2);
bar7Lists.add(bar3);
dcv7.setBarLists(bar7Lists);

How to use2?
<!-- xml -->

<com.lyloou.view.HistogramView
android:id="@+id/histogram_view"
android:layout_margin="16dp"
android:paddingLeft="16dp"
android:paddingRight="32dp"
android:paddingTop="15dp"
android:paddingBottom="33dp"
android:layout_width="match_parent"
android:layout_height="400dp" />

<!-- Activity -->

HistogramView histogram = (HistogramView) findViewById(R.id.histogram_view);
ArrayList<Bar> barLists = new ArrayList<Bar>();
for(int i=0; i<15; i++){
float ratio = (float) Math.random();
int color = (int) (Color.GRAY * ratio);
Bar bar = histogram.new Bar(i, ratio, color, "", "");
barLists.add(bar);
}
histogram.setBarLists(barLists);

【代码】

import java.util.ArrayList;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Paint.FontMetricsInt;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.view.Display;
import android.view.View;
import android.view.WindowManager;

/**
 *
 * @author Lyloou
 */

public class HistogramView extends View {

    private Paint mPaint;
    private Rect mRect;
    private int mWidth;
    private int mHeight;
    private int mPaddingStart;
    private int mPaddingEnd;
    private int mPaddingTop;
    private int mPaddingBottom;
    private int mLeft;
    private int mTop;
    private int mRight;
    private int mBottom;
    private Context mContext;
    private ArrayList<Bar> mBarLists;

    public HistogramView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        mContext = context;
        initData();
    }

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

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

    private void initData() {

        mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mPaint.setStyle(Paint.Style.FILL_AND_STROKE);
        mRect = new Rect();

        // default data
        mBarLists = new ArrayList<Bar>();
        Bar bar1 = new Bar(1, 0.3f, Color.CYAN, "one", "30");
        Bar bar2 = new Bar(2, 0.55f, Color.GREEN, "two", "55");
        Bar bar3 = new Bar(3, 0.8f, Color.BLUE, "three", "80");
        mBarLists.add(bar1);
        mBarLists.add(bar2);
        mBarLists.add(bar3);
    }

    public void setBarLists(ArrayList<Bar> barLists) {
        mBarLists = barLists;
        postInvalidate();
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        mWidth = getSizeFromMeasureSpec(widthMeasureSpec, 480);
        mHeight = getSizeFromMeasureSpec(heightMeasureSpec, 480);

        mPaddingStart = getPaddingStart();
        mPaddingEnd = getPaddingEnd();
        mPaddingTop = getPaddingTop();
        mPaddingBottom = getPaddingBottom();

        mLeft = mPaddingStart;
        mTop = mPaddingTop;
        mRight = mWidth - mPaddingEnd;
        mBottom = mHeight - mPaddingBottom;

        setMeasuredDimension(mWidth, mHeight);
    }

    @Override
    protected void onDraw(Canvas canvas) {

        // set background
        canvas.drawColor(Color.RED);
        mRect.set(mLeft, mTop, mRight, mBottom);
        mPaint.setColor(Color.YELLOW);
        canvas.drawRect(mRect, mPaint);
        // */

        // 设置底部文字属性
        mPaint.setTextSize(sp2Px(mContext, 11));
        mPaint.setTextAlign(Paint.Align.CENTER);
        FontMetricsInt fontMetricsInt = mPaint.getFontMetricsInt();
        int fontHeight = (int) Math.ceil(fontMetricsInt.bottom - fontMetricsInt.top);

        int N = mBarLists.size();
        int UNIT_WIDTH = (mRight - mLeft) / (2 * N + 1);

        int left = 0;
        int top = 0;
        int right = 0;
        int bottom = 0;

        // 逐个画bar
        for (int i = 0; i < N; i++) {
            Bar bar = mBarLists.get(i);

            // 画 bar 底部文字
            left = (int) (mLeft + (i * 2 + 0.5f) * UNIT_WIDTH);
            right = left + UNIT_WIDTH * 2;
            top = mBottom - fontHeight;
            bottom = mBottom;
            mRect.set(left, top, right, bottom);
            int baseLine = (mRect.top + mRect.bottom - fontMetricsInt.top - fontMetricsInt.bottom) / 2;
            mPaint.setColor(Color.BLACK);
            canvas.drawText(bar.bootomText, mRect.centerX(), baseLine, mPaint);

            // 画 bar 图形
            left = mLeft + (i * 2 + 1) * UNIT_WIDTH;
            right = left + UNIT_WIDTH;
            bottom = mBottom - fontHeight;
            top = bottom - (int) ((mBottom - mTop - fontHeight * 2) * bar.ratio);
            mRect.set(left, top, right, bottom);
            mPaint.setColor(bar.color);
            canvas.drawRect(mRect, mPaint);

            // 画 bar 顶部文字
            left = (int) (mLeft + (i * 2 + 0.5f) * UNIT_WIDTH);
            right = left + UNIT_WIDTH * 2;
            bottom = top;
            top = top - fontHeight;
            mRect.set(left, top, right, bottom);
            baseLine = (mRect.top + mRect.bottom - fontMetricsInt.top - fontMetricsInt.bottom) / 2;
            mPaint.setColor(Color.BLACK);
            canvas.drawText(bar.topText, mRect.centerX(), baseLine, mPaint);
        }

        // 画线
        mPaint.setColor(Color.BLACK);
        canvas.drawLine(mLeft, mBottom - fontHeight, mRight, mBottom - fontHeight, mPaint);
        // canvas.drawLine(mLeft, mTop + fontHeight, mRight, mTop + fontHeight, mPaint);

        super.onDraw(canvas);
    }

    public class Bar {
        public int id;
        public float ratio;
        public int color;
        public String bootomText;
        public String topText;

        public Bar(int id, float ratio, int color, String bootomText, String topText) {
            this.id = id;
            this.ratio = ratio;
            this.color = color;
            this.bootomText = bootomText;
            this.topText = topText;
        }
    }

    // 工具类
    public static int getSizeFromMeasureSpec(int measureSpec, int defaultSize) {
        int result = 0;
        int mode = MeasureSpec.getMode(measureSpec);
        int size = MeasureSpec.getSize(measureSpec);
        if (mode == MeasureSpec.EXACTLY) {
            result = size;
        } else {
            result = defaultSize;
            if (mode == MeasureSpec.AT_MOST) {
                result = Math.min(defaultSize, size);
            }
        }
        return result;
    }

    public static float sp2Px(Context context, float sp) {
        DisplayMetrics metrics = new DisplayMetrics();
        WindowManager wm = (WindowManager) context
                .getSystemService(Context.WINDOW_SERVICE);
        Display display = wm.getDefaultDisplay();
        display.getMetrics(metrics);
        float px = metrics.scaledDensity;
        return sp * px;
    }
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值