之前从某网上看了一个描述自定义条形图的视频教程,因为没有源码,所以自己记录了一下,方便以后用到,初学者也可以互相学习.
废话不多说,首先看下效果图:(可能界面比较low哈....)
我们先看一下 画图三要素的介绍
Canvas : 画布, 绘制Bitmap操作;
Paint : 绘制所需的画笔(一般用来规定颜色,样式等);
Path : 路径 轨迹;
那么接下来直接上代码,代码中都有注释,我就不过度赘述了;
设置条形图的样式在styles.xml中:
<!--自定义条形图样式--> <declare-styleable name="ChartStyle"> <attr name="graphTitle" format="string"></attr> <attr name="xAxisName" format="string"></attr> <attr name="yAxisName" format="string"></attr> <attr name="axisTextSize" format="dimension|integer"></attr> <attr name="axisTextColor" format="color|integer"></attr> </declare-styleable>
创建抽象类BaseView继承自View
public abstract class BaseView extends View { private Context mContext; //画笔 private Paint mPaint; //视图的宽 public int width; //视图的高 public int height; //原始起点的X,Y坐标值 public int originalX = 80; public int originalY = 500; //X,Y轴等份划分 public int axisDividedSizeX; public int axisDividedSizeY; //第一个维度为值,第二个维度为颜色 public int[][] columnInfo; //图表标题 private String mGraphTitle; //X轴Name private String mXAxisName; //Y轴Name private String mYAxisName; //坐标轴上字体的大小 private float mAxisTextSize; //坐标轴字体的颜色 public int mAxisTextColor; public BaseView(Context context) { this(context, null); } public BaseView(Context context, @Nullable AttributeSet attrs) { this(context, attrs, -1); } /** * 设置X轴的刻度份数 * @param axisDividedSizeX */ public void setAxisDividedSizeX(int axisDividedSizeX) { this.axisDividedSizeX = axisDividedSizeX; } /** * 设置Y轴的刻度份数 * @param axisDividedSizeY */ public void setAxisDividedSizeY(int axisDividedSizeY) { this.axisDividedSizeY = axisDividedSizeY; } /** * 设置条形图的数值和颜色 * @param columnInfo */ public void setColumnInfo(int[][] columnInfo) { this.columnInfo = columnInfo; } public BaseView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); mContext = context; //获取自定义样式 TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.ChartStyle); //取出自定义的设置 mGraphTitle = typedArray.getString(R.styleable.ChartStyle_graphTitle); mXAxisName = typedArray.getString(R.styleable.ChartStyle_xAxisName); mYAxisName = typedArray.getString(R.styleable.ChartStyle_yAxisName); mAxisTextColor = typedArray.getColor(R.styleable.ChartStyle_axisTextColor, context.getResources().getColor(android.R.color.black)); mAxisTextSize = typedArray.getDimension(R.styleable.ChartStyle_axisTextSize, 12); //若不为null if (typedArray != null){ //回收 typedArray.recycle(); } //初始化画笔 initPaint(); } //初始化画笔 private void initPaint() { if (mPaint == null){ mPaint = new Paint(); //防抖动 mPaint.setDither(true); //去锯齿 mPaint.setAntiAlias(true); } } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); //视图的宽 为 屏幕的宽 - 起始位置 width = getWidth() - originalX - 80; //视图的高度 为 若原始位置超过屏幕高度 则设置 屏幕高度为视图高度 否则 设置原始位置为视图高度 height = (originalY > getHeight() ? getHeight():originalY) - 100; //画X轴 drawXAxis(canvas, mPaint); //画Y轴 drawYAxis(canvas, mPaint); //画标题 drawTitle(canvas, mPaint); //画X刻度 drawXAxisScale(canvas, mPaint); //画X刻度值 drawXAxisScaleValue(canvas, mPaint); //画Y刻度 drawYAxisScale(canvas, mPaint); //画Y刻度值 drawYAxisScaleValue(canvas, mPaint); //画X箭头 drawXAxisArrow(canvas, mPaint); //画Y箭头 drawYAxisArrow(canvas, mPaint); //画柱形图 drawColumn(canvas, mPaint); //画柱形图上的值 drawColumnValue(canvas, mPaint); } /** * 画柱形图上的值 * @param canvas * @param mPaint */ protected abstract void drawColumnValue(Canvas canvas, Paint mPaint); /** * 画柱形条 * @param canvas * @param mPaint */ protected abstract void drawColumn(Canvas canvas, Paint mPaint); /** * 画Y轴的箭头 * @param canvas * @param mPaint */ private void drawYAxisArrow(Canvas canvas, Paint mPaint) { Path mPathY = new Path(); //画法介绍:画一个三角形,将箭头顶点路径移动到 Y轴顶点-30的位置(), 然后X轴左右各+-10 封闭起来 mPathY.moveTo(originalX, originalY - height - 30); mPathY.lineTo(originalX - 10, originalY - height); mPathY.lineTo(originalX + 10, originalY - height); mPathY.close(); mPaint.setColor(mAxisTextColor); canvas.drawPath(mPathY, mPaint); canvas.drawText(mYAxisName, originalX - 50, originalY - height - 30, mPaint); } /** * 画X轴的箭头 * @param canvas * @param mPaint */ private void drawXAxisArrow(Canvas canvas, Paint mPaint) { Path mPathX = new Path(); //画法介绍:其实就是画一个三角形,将箭头顶点路径移动到 X轴顶点+30的位置, 然后Y轴上下各+-10 封闭起来 mPathX.moveTo(originalX + width + 30, originalY); mPathX.lineTo(originalX + width, originalY + 10); mPathX.lineTo(originalX + width, originalY - 10); mPathX.close(); mPaint.setColor(mAxisTextColor); canvas.drawPath(mPathX, mPaint); canvas.drawText(mXAxisName, originalX + width, originalY + 50, mPaint); } /** * 画Y轴的刻度值 * @param canvas * @param mPaint */ protected abstract void drawYAxisScaleValue(Canvas canvas, Paint mPaint); /** * 画Y轴的刻度 * @param canvas * @param mPaint */ protected abstract void drawYAxisScale(Canvas canvas, Paint mPaint); /** * 画X轴的刻度值 * @param canvas * @param mPaint */ protected abstract void drawXAxisScaleValue(Canvas canvas, Paint mPaint); /** * 画X轴刻度 * @param canvas * @param mPaint */ protected abstract void drawXAxisScale(Canvas canvas, Paint mPaint); /** * 画图表标题 * @param canvas * @param mPaint */ private void drawTitle(Canvas canvas, Paint mPaint) { if (!TextUtils.isEmpty(mGraphTitle)){ mPaint.setTextSize(mAxisTextSize); mPaint.setColor(mAxisTextColor); // mPaint.setFakeBoldText(true);//粗体 //要求文字宽度的中点 在其屏幕横向的中点 canvas.drawText(mGraphTitle, (getWidth()/2) - (mPaint.measureText(mGraphTitle))/2, originalY + 70, mPaint ); } } /** * 画Y轴 * @param canvas * @param mPaint */ protected abstract void drawYAxis(Canvas canvas, Paint mPaint); /** * 画X轴 * @param canvas * @param mPaint */ protected abstract void drawXAxis(Canvas canvas, Paint mPaint); }
创建ChartView继承自BaseView并实现其中的抽象方法
public class ChartView extends BaseView { public ChartView(Context context) { super(context); } public ChartView(Context context, @Nullable AttributeSet attrs) { super(context, attrs); } public ChartView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } /** * 画柱形图上的值 * @param canvas * @param mPaint */ @Override protected void drawColumnValue(Canvas canvas, Paint mPaint) { float cellWidth = width/axisDividedSizeX; if (columnInfo != null){ mPaint.setColor(Color.parseColor("#4682B4")); for (int i = 0; i < columnInfo.length; i++) { float leftTopY = originalY - height*(columnInfo[i][0])/axisDividedSizeY; canvas.drawText(columnInfo[i][0]+"", (originalX + cellWidth*(i+1)) + cellWidth/2, leftTopY - 10, mPaint); } } } /** * 画柱形条 * @param canvas * @param mPaint */ @Override protected void drawColumn(Canvas canvas, Paint mPaint) { if (columnInfo != null){ float cellWidth = width/axisDividedSizeX; for (int i = 0; i < columnInfo.length; i++) { mPaint.setColor(columnInfo[i][1]); float leftTopY = originalY - height*(columnInfo[i][0])/axisDividedSizeY; canvas.drawRect(originalX + cellWidth * (i + 1), leftTopY, originalX+cellWidth*(i+2), originalY, mPaint); } } } /** * 画Y轴的刻度值 * @param canvas * @param mPaint */ @Override protected void drawYAxisScaleValue(Canvas canvas, Paint mPaint) { mPaint.setColor(mAxisTextColor); mPaint.setStrokeWidth(2); float cellHeight = height / axisDividedSizeY; for (int i = 0; i < axisDividedSizeY; i++) { canvas.drawText(String.valueOf(i), originalX - 30, originalY - cellHeight * i + 10, mPaint); } } /** * 画Y轴的刻度 * @param canvas * @param mPaint */ @Override protected void drawYAxisScale(Canvas canvas, Paint mPaint) { mPaint.setColor(mAxisTextColor); mPaint.setStrokeWidth(2); float cellHeight = height / axisDividedSizeY; for (int i = 0; i < axisDividedSizeY - 1; i++) { canvas.drawLine(originalX, (originalY - cellHeight * (i+1)), originalX + 10, (originalY - cellHeight * (i+1)), mPaint); } } /** * 画X轴的刻度值 * @param canvas * @param mPaint */ @Override protected void drawXAxisScaleValue(Canvas canvas, Paint mPaint) { mPaint.setColor(mAxisTextColor); mPaint.setTextSize(16); // mPaint.setFakeBoldText(true); float cellWidth = width/axisDividedSizeX; for (int i = 0; i < axisDividedSizeX; i++) { canvas.drawText(String.valueOf(i), cellWidth * (i+1) + originalX - 35, originalY + 30, mPaint); } } /** * 画X轴刻度 * @param canvas * @param mPaint */ @Override protected void drawXAxisScale(Canvas canvas, Paint mPaint) { mPaint.setColor(mAxisTextColor); mPaint.setStrokeWidth(2); float cellWidh = width / axisDividedSizeX; for (int i = 0; i < axisDividedSizeX - 1; i++) { canvas.drawLine(cellWidh * (i+1) + originalX, originalY, cellWidh * (i+1) + originalX, originalY- 10, mPaint ); } } /** * 画Y轴 * @param canvas * @param mPaint */ @Override protected void drawYAxis(Canvas canvas, Paint mPaint) { mPaint.setColor(mAxisTextColor); mPaint.setStrokeWidth(3); canvas.drawLine(originalX, originalY, originalX, originalY- height, mPaint); } /** * 画X轴 * @param canvas * @param mPaint */ @Override protected void drawXAxis(Canvas canvas, Paint mPaint) { mPaint.setColor(mAxisTextColor); mPaint.setStrokeWidth(3); canvas.drawLine(originalX, originalY, originalX + width, originalY, mPaint); } }设置xml布局文件,很简单就只有一个自定义的ChartView
<com.example.joy.chartsdemo.view.ChartView android:id="@+id/chartview" android:layout_width="wrap_content" android:layout_height="wrap_content" app:graphTitle="ChartView条形图" app:axisTextColor="#20B2AA" app:xAxisName="天" app:yAxisName="个数" app:axisTextSize="20sp" />
最后在MainActivity中onCreate()设置自定义的ChartView的一些属性.
ChartView mChartView = findViewById(R.id.chartview); int[][] columnInfo = new int[][]{ {6, Color.parseColor("#FFA500")}, {2, Color.parseColor("#FFD700")}, {8, Color.parseColor("#BC8F8F")}, {6, Color.parseColor("#DB7093")}, {7, Color.parseColor("#FFA500")}, {9, Color.parseColor("#DAA520")}, {10, Color.parseColor("#9932CC")}, }; mChartView.setColumnInfo(columnInfo); mChartView.setAxisDividedSizeX(10); mChartView.setAxisDividedSizeY(10);
the end...
烦请大家尊重原创者版权,转载请标明出处:https://blog.csdn.net/JOYU_/article/details/80911719