![](https://img.haomeiwen.com/i1847512/98e0a438e6b65299.png)
最终结果如下
![](https://img.haomeiwen.com/i1847512/57dcd31267c6ba3e.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中实现。
网友评论