我爱编程Android 进阶技术篇专题安卓开发博客

Android 自定义优美的柱形图控件

2018-07-01  本文已影响20人  SwitchLife

开篇

  由于进来工作比较忙,很久没有写博客了。在近期的项目中用到柱形图,虽然第三方开源的图饼库也挺多的,但是,项目中不需要那么复杂的图饼,所以就花了点时间自己撸了一个。啥也不说,先看效果图。

效果截屏


立即体验

扫描以下二维码下载体验App(从0.2.3版本开始,体验App内嵌版本更新检测功能):


JSCKit库传送门:https://github.com/JustinRoom/JSCKit

简析源码

VerticalColumnarGraphViewk.java

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

        clipRect.set(getPaddingLeft() + lOffset, getPaddingTop() + tOffset, getWidth() - getPaddingRight() - rOffset, getHeight() - getPaddingBottom() - bOffset);
        drawAxis(canvas);
        float[] xAxisScales = calculateXScales(clipRect.left);
        float[] yAxisScales = calculateYScales(clipRect.bottom);
        drawXAxisScales(canvas, xAxisScales, 10);
        drawYAxisScales(canvas, yAxisScales, 10);

        clipRect.set(getPaddingLeft(), getPaddingTop(), getWidth() - getPaddingRight(), getHeight() - getPaddingBottom());
        textPaint.setColor(axisLabelTextColor);
        textPaint.setTextSize(axisLabelTextSize);
        textPaint.setTypeface(Typeface.defaultFromStyle(Typeface.NORMAL));
        textPaint.setAlpha(0xFF);
        drawXAxisLabels(canvas, xAxisScales);
        drawYAxisLabels(canvas, yAxisScales);

        clipRect.set(getPaddingLeft() + lOffset, getPaddingTop() + tOffset, getWidth() - getPaddingRight() - rOffset, getHeight() - getPaddingBottom() - bOffset);
        drawItems(canvas);

        if (isPressed) {

        } else {
            drawSelectedItemDetailInfo(canvas);
        }

    }

⚠️要想onTouchEvent方法触发MotionEvent.ACTION_UP事件,必须返回true。

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                if (!isPressed) {
                    isPressed = true;
                    selectedIndex = getSelectedIndex(event.getX(), event.getY(), space / 3);

                    pressedTimStamp = System.nanoTime();
                    if (selectedIndex >= 0){
                        //Send a long click event message after DEFAULT_LONG_CLICK_TIME million seconds.
                        getHandler().postDelayed(longClickRunnable, DEFAULT_LONG_CLICK_TIME);
                    }
                }
                break;
            case MotionEvent.ACTION_MOVE:
                int moveIndex = getSelectedIndex(event.getX(), event.getY(), space / 3);
                if (moveIndex < 0) {
                    pressedTimStamp = 0;
                    //Remove long click event.
                    getHandler().removeCallbacks(longClickRunnable);
                }
                break;
            case MotionEvent.ACTION_UP:
                isPressed = false;
                //Remove long click event.
                getHandler().removeCallbacks(longClickRunnable);
                if (System.nanoTime() - pressedTimStamp <= DEFAULT_CLICK_TIME) {
                    pressedTimStamp = 0;
                    performColumnarItemClick(selectedIndex);
                }
                break;
        }
        return true;
    }
    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        invalidate();
    }
    /**
     * 个性化定制UI。
     *
     * @param builder builder
     */
    public void initCustomUI(Builder builder) {
        if (builder == null)
            return;
        xAxisLabels = builder.xAxisLabels;
        yAxisLabels = builder.yAxisLabels;
        axisColor = builder.axisColor;
        axisLabelTextColor = builder.axisLabelTextColor;
        axisLabelTextSize = builder.axisLabelTextSize;
        column = builder.column;
        lOffset = builder.leftOffset;
        tOffset = builder.topOffset;
        rOffset = builder.rightOffset;
        bOffset = builder.bottomOffset;
        if (axisLabelTextSize <= 0)
            axisLabelTextSize = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 10, getResources().getDisplayMetrics());
        invalidate();
    }

Builder.java

⚠️自带一些默认设置,避免在没有设置某些参数时引起view绘制混乱。

public class Builder {
        String[] yAxisLabels;
        String[] xAxisLabels;
        int axisColor;//坐标系以及刻度线颜色
        int axisLabelTextColor;//刻度字体颜色
        float axisLabelTextSize;//刻度字体大小
        int column;//柱形数目
        int leftOffset;
        int topOffset;
        int rightOffset;
        int bottomOffset;

    ...
}
    public void setOnColumnarItemClickListener(OnColumnarItemClickListener onColumnarItemClickListener) {
        this.onColumnarItemClickListener = onColumnarItemClickListener;
    }

    public void setOnColumnarItemLongClickListener(OnColumnarItemLongClickListener onColumnarItemLongClickListener) {
        this.onColumnarItemLongClickListener = onColumnarItemLongClickListener;
    }

用法

        verticalColumnarGraphView.setOnColumnarItemClickListener(new VerticalColumnarGraphView.OnColumnarItemClickListener() {
            @Override
            public void onColumnarItemClick(VerticalColumnarGraphView view, int selectedIndex, @Nullable ColumnarItem selectedItem) {
                showCustomToast("click " + selectedIndex);
            }
        });
        verticalColumnarGraphView.setOnColumnarItemLongClickListener(new VerticalColumnarGraphView.OnColumnarItemLongClickListener() {
            @Override
            public void onColumnarItemLongClick(VerticalColumnarGraphView view, int selectedIndex, @Nullable ColumnarItem selectedItem) {
                showCustomToast("long click " + selectedIndex);
            }
        });

        verticalColumnarGraphView.initCustomUI(
                new VerticalColumnarGraphView.Builder()
                        .setYAxisLabels(new String[]{"\u20000", "25", "50", "75", "100"})
                        .setOffset(60, 0, 20, 20)
        );
        verticalColumnarGraphView.setItems(createTestData());

    /**
     * 创建测试数据
     *
     * @return test data source
     */
    private List<ColumnarItem> createTestData() {
        List<ColumnarItem> data = new ArrayList<>();
        float[] ratios = {.76f, .36f, .54f, .36f, .05f, .36f, .6f};
        int[] colors = {0xFFFFCF5E, 0xFFB4EE4D, 0xFF27E67B, 0xFF36C771, 0xFF1CA291, 0xFF24DDD0, 0xFf32CEF7};
        String[] labels = {"返情配种", "多次输精", "人工授精", "本交", "同精液配种", "已配种母猪", "其他配种"};
        String[] values = {"76头", "36头", "54头", "36头", "5头", "36头", "60头"};
        for (int i = 0; i < 7; i++) {
            ColumnarItem item = new ColumnarItem();
            item.setColor(colors[i]);
            item.setRatio(ratios[i]);
            item.setLabel(labels[i]);
            item.setValue(values[i]);
            data.add(item);
        }
        return data;
    }

  百忙之中抽点时间分享此控件,文字写得不多,请参照代码里的注释予以理解。写得不好请见谅。

篇尾

  QQ:1006368252

土地是以它的肥沃和收获而被估价的;才能也是土地,不过它生产的不是粮食,而是真理。如果只能滋生瞑想和幻想的话,即使再大的才能也只是砂地或盐池,那上面连小草也长不出来的。 —— 别林斯基

上一篇 下一篇

猜你喜欢

热点阅读