美文网首页
用RecycleView自定义可滚动柱状图

用RecycleView自定义可滚动柱状图

作者: 小玉1991 | 来源:发表于2019-12-16 17:27 被阅读0次
需求图片

最终结果如下

image.png

如图,因工作需要,要自定义一个柱状图,要求实现滚动和UI的设计效果。

思路1:自定义View,修改触摸事件,实现滚动。放弃!!!滚动效果太差,解耦不灵活。
思路2:用RecycleView实现,滚动很流畅。容易使用和扩展。

代码
重点,定义 一个Item--->BarGraphItem

public class BarGraphItem extends View {
    private static final String TAG = "BarGraphView";
    private Paint paint;
    private int measuredWidth;
    private int measuredHeight;
    private float ratio;
    private int mBarColor;
    private Rect histogramPaintRect;
    private int mWidth;
    private Paint mTextPaint;


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

    public BarGraphItem(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        init(attrs);
    }

    public BarGraphItem(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(attrs);
    }

    //设置柱子的高度
    public void setRatio(float ratio, int barColor) {
        this.ratio = ratio;
        mBarColor = barColor;
        initPaint();
        invalidate();
    }

    private void initPaint() {
        paint = new Paint();
        paint.setStyle(Paint.Style.FILL);
        paint.setColor(getResources().getColor(mBarColor));
        paint.setAntiAlias(true);
    }

    private void init(AttributeSet attrs) {
        histogramPaintRect = new Rect();
        TypedArray typedArray = getContext().obtainStyledAttributes(attrs, R.styleable.HistogramView);
        mWidth = typedArray.getDimensionPixelSize(R.styleable.HistogramView_histogramHistogramWidth, PixelUtil.dp2px(50));

        mTextPaint = new Paint();
        mTextPaint.setStyle(Paint.Style.FILL);
        mTextPaint.setColor(getResources().getColor(R.color.textcolor_subject_name));
        mTextPaint.setAntiAlias(true);
    }


    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        measuredWidth = getMeasuredWidth();
        measuredHeight = getMeasuredHeight();
    }

    @Override
    protected void onDraw(Canvas canvas) {

        int startX = (int) ((measuredWidth - mWidth) / 2 + 0.5);
        //画柱子的背景色
        //计算柱子实际高度
        int realheight = measuredHeight - Padding_Bottom - Padding_Top;

        int ratioHeight = (int) (realheight * ratio + 0.5);
        //默认坐标原点在左上角,这里我们把画布移到左上角

        histogramPaintRect.left = startX;
        histogramPaintRect.right = histogramPaintRect.left + mWidth;
        histogramPaintRect.top = Padding_Top + (realheight - ratioHeight);
        histogramPaintRect.bottom = histogramPaintRect.top + ratioHeight;

        canvas.drawRect(histogramPaintRect, paint);

        String textTop = ratio + "%";
        float valueTextY = histogramPaintRect.top - PixelUtil.dp2px(3);
        float textWidth = mTextPaint.measureText(textTop);
        canvas.drawText(textTop, startX + (mWidth - textWidth) / 2, valueTextY, mTextPaint);

        String textDown = ratio + "%";
        float valueTextDownY = histogramPaintRect.bottom + Padding_Bottom / 2;
        float textDownWidth = mTextPaint.measureText(textDown);
        canvas.drawText(textDown, startX + (mWidth - textDownWidth) / 2, valueTextDownY, mTextPaint);

        //draw little circle
        Paint circlePaint = new Paint();
        circlePaint.setAntiAlias(true);
        circlePaint.setStyle(Paint.Style.FILL);
        circlePaint.setColor(Color.WHITE);
        canvas.drawCircle(startX + mWidth / 2f, histogramPaintRect.bottom, PixelUtil.dp2px(5), circlePaint);
        circlePaint.setStyle(Paint.Style.STROKE);
        circlePaint.setColor(getResources().getColor(R.color.notice_date));
//        circlePaint.setStrokeWidth(PixelUtil.dp2px(1));
        canvas.drawCircle(startX + mWidth / 2f, histogramPaintRect.bottom, PixelUtil.dp2px(5), circlePaint);

    }
}

自定义HistogramView

public class HistogramView extends LinearLayout {

    private Context mContext;
    private Paint mlinePaint;
    private int width;
    private int height;
    private LinearLayoutManager layoutManager;
    private RecyclerView recyclerView;
    private BarGraphAdapter barGraphAdapter;

    public static final int Padding_Top = PixelUtil.dp2px(30);
    public static final int Padding_Bottom = PixelUtil.dp2px(30);

    private int paddingLeft = PixelUtil.dp2px(65);
    private int paddingRight = PixelUtil.dp2px(45);
    private Paint mTextPaint;

    public HistogramView(Context context) {
        super(context);
        initView(context);
    }

    public HistogramView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        initView(context);
    }

    public HistogramView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        initView(context);
    }

    public HistogramView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
        initView(context);
    }

    private void initView(Context context) {
        mContext = context;
        mlinePaint = new Paint();
        mlinePaint.setStyle(Paint.Style.FILL);
        mlinePaint.setColor(getResources().getColor(R.color.notice_date));
        mlinePaint.setAntiAlias(true);
        mlinePaint.setStrokeWidth(0.5f);

        mTextPaint = new Paint();
        mTextPaint.setStyle(Paint.Style.FILL);
        mTextPaint.setColor(getResources().getColor(R.color.notice_date));
        mTextPaint.setAntiAlias(true);
        mTextPaint.setTextAlign(Paint.Align.CENTER);
        mTextPaint.setStrokeWidth(0.5f);

        View view = View.inflate(context, R.layout.histpgramview_recycle, null);
        recyclerView = view.findViewById(R.id.recyclerview);
        layoutManager = new LinearLayoutManager(getContext());
        layoutManager.setOrientation(LinearLayoutManager.HORIZONTAL);
        recyclerView.setLayoutManager(layoutManager);
        recyclerView.setOverScrollMode(View.OVER_SCROLL_NEVER);
        barGraphAdapter = new BarGraphAdapter(context, new ArrayList());
        recyclerView.setAdapter(barGraphAdapter);

        addView(view);
        setPadding(paddingLeft, 0, paddingRight, 0);
    }

    public void setData(List<ChildData> list) {
        barGraphAdapter.refresh(list);
        invalidate();
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        width = getMeasuredWidth();
        height = getMeasuredHeight();
    }


    @Override
    protected void dispatchDraw(Canvas canvas) {
        initDrawBg(canvas);//放在super前是后景,相反是前景,前景会覆盖子布局
        super.dispatchDraw(canvas);
    }

    private void initDrawBg(Canvas canvas) {
        float startX = paddingLeft;
        float stopX = width - paddingRight;

        float middleY = Padding_Top + (height - Padding_Bottom - Padding_Top) / 2f;
        canvas.drawLine(startX, Padding_Top, stopX, Padding_Top, mlinePaint);
        canvas.drawLine(startX, middleY, stopX, middleY, mlinePaint);
        canvas.drawLine(startX, height - Padding_Bottom, stopX, height - Padding_Bottom, mlinePaint);

        float w1 = mTextPaint.measureText("100");
        float w2 = mTextPaint.measureText("50");
        float w3 = mTextPaint.measureText("0");

        Rect bounds = new Rect();
        mTextPaint.getTextBounds("100", 0, "100".length(), bounds);
        float height = bounds.bottom - bounds.top;
        float offh=height/2;

        canvas.drawText("100", startX - w1/2-3, Padding_Top+offh, mTextPaint);
        canvas.drawText("50", startX - w2/2-3, middleY+offh, mTextPaint);
        canvas.drawText("0", startX - w3/2-3, this.height - Padding_Bottom+offh, mTextPaint);
    }


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

adapter BarGraphAdapter

public class BarGraphAdapter extends BaseAdapter<ChildData> {

    public BarGraphAdapter(Context mContext, List data) {
        super(mContext, data);
    }

    @Override
    public int getItemViewType(int position) {
        return TYPE_ITEM;
    }


    @Override
    public int getItemCount() {
        return mData.size();
    }

    @Override
    protected RecyclerView.ViewHolder CreateVH(ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(parent.getContext())
                .inflate(R.layout.item_histogam, parent, false);
        return new ChartViewHolder(view);
    }

    @Override
    protected void BindVH(RecyclerView.ViewHolder holder, int position) {
        ChildData childData = mData.get(position);
        ChartViewHolder viewHolder = (ChartViewHolder) holder;
        viewHolder.bar_item.setRatio(childData.getValue(), R.color.green);

    }

    public static class ChartViewHolder extends RecyclerView.ViewHolder {
        public View mView;
        public BarGraphItem bar_item;

        public ChartViewHolder(View view) {
            super(view);
            mView = view;
            bar_item = (BarGraphItem) view.findViewById(R.id.bar_item);
        }
    }
}

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

    <com.lenovo.smartclass.view.chart.BarGraphItem
            android:id="@+id/bar_item"
            android:layout_width="@dimen/dp_110"
            android:layout_height="match_parent"/>

</RelativeLayout>

bean

public class ChildData {

    private float value;
    private String name;
    private int type;


    public float getValue() {
        return value;
    }

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

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getType() {
        return type;
    }

    public void setType(int type) {
        this.type = type;
    }
}

最后使用

  ArrayList<ChildData> list = new ArrayList<>();
        for (int i = 21; i>0; i--) {
            ChildData childData = new ChildData();
            childData.setName("aaa" + i);
            childData.setValue(i * 5/100f);
            list.add(childData);
        }
        chart_view.setData(list);

最后换图片其他细节,可以在Adapter中实现,也可以在自定义的Item中实现。

相关文章

网友评论

      本文标题:用RecycleView自定义可滚动柱状图

      本文链接:https://www.haomeiwen.com/subject/dnpdnctx.html