美文网首页
用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