关于自定义View,相信多数开发者都已经非常熟悉了,网络上的例子也非常多,各种炫酷吊炸天的自定义View也层出不穷。本文只是一个初级学习教程,对于初学者有参考价值。
下面正式进入主题。
本文采用自定义View的方式实现柱状统计图BarGraphView,实现了柱状统计图的基本功能,因为本身是为了学习自定义View,因此扩展性比较差,只能作为自定义View的参考。
上效果图:
View显示到屏幕上主要经过这三个过程
(1)Measure(测量)
首先View需要测量自身的大小,包括长和宽。 当View类的成员函数measure决定要重新测量当前View的宽度和高度之后,会去调用另外一个成员函数onMeasure来真正执行测量宽度和高度的操作。因此,自定义View大多都需要覆写onMeasure方法来测量View的大小。onMeasure方法如下:
@Override
public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
其中widthMeasureSpec和heightMeasureSpec两个参数为父视图的建议大小。 参数measureSpec的值其实是由两部分内容来组成的,最高2位表示一个测量模式,而低30位表示一个宽度值或者高度值,测量模式有三种,分别是MeasureSpec.EXACTLY、MeasureSpec.UNSPECIFIED和MeasureSpec.AT_MOST,这里就不讲三种模式的区别了。在BarGraphView中将会参考这个两个数值来确定BarGraphView的大小。
(2)Layout(布局)
这个过程只在View容器(ViewGroup及其子类)有用,因为非容器类View在屏幕中的位置操作由父控件来决定,所以不需要覆写onLayout()方法。
(3)Draw(绘制)
最后绘制View的过程,在这个过程里主要通过Paint对象在Canvas上面绘制相应图像,最终把View展现在屏幕上。 对于自定义View来说,通常需要覆写onDraw()方法绘制View。
@Override
public void onDraw(Canvas canvas) {
}
该方法提供了一块画布,我们只需要创建一个画笔在画布上绘图案即可。
好了,了解了上述过程,接下来我们开始实现BarGraphView。
BarGraphView主要代码集中在Draw的过程,通过onDraw方法把统计图绘制到屏幕上来。
经过分析,把柱状图分为以下几部分
1.横/纵坐标轴
2.横/纵坐标轴刻度线
3.横/纵坐标轴刻度值
4.横/纵坐标轴箭头
5.标题
6.柱状图
针对不同部分利用drawLine()(画直线)、drawText()(画文字)、drawPath()(画多边形)以及drawRect()(画矩形)的方法分别绘制相应图案。
以下是BarGraphView类代码,可以直接看注释。
package com.eleven.demo.widget;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.util.AttributeSet;
import android.view.View;
import com.eleven.demo.R;
/**
* Created by Eleven on 2015/5/3.
*/
public class BarGraphView extends View {
private final String TAG = BarGraphView.class.getName();
//画笔
private Paint mPaint;
//标题
private String title;
//标题颜色
private int titleColor;
//标题大小
private float titleSize;
//X坐标轴最大值
private float maxAxisValueX = 900;
//X坐标轴刻度线数量
private int axisDivideSizeX = 9;
//Y坐标轴最大值
private float maxAxisValueY = 700;
//Y坐标轴刻度线数量
private int axisDivideSizeY = 7;
//视图宽度
private int width;
//视图高度
private int height;
//坐标原点位置
private final int originX = 100;
private final int originY = 800;
//柱状图数据
private int columnInfo[][];
public BarGraphView(Context context, AttributeSet attrs) {
super(context, attrs);
//创建画笔
mPaint = new Paint();
//获取配置的属性值
TypedArray mArray = context.obtainStyledAttributes(attrs, R.styleable.BarGraphView);
title = mArray.getString(R.styleable.BarGraphView_barGraph_title);
titleColor = mArray.getColor(R.styleable.BarGraphView_barGraph_titleColor, Color.BLACK);
titleSize = mArray.getDimension(R.styleable.BarGraphView_barGraph_titleSize, 36);
}
/**
* 设置X轴的最大值及刻度线数量(包括0坐标刻度)
*
* @param maxValue X轴的最大值
* @param divideSize 刻度线数量
*/
public void setAxisX(float maxValue, int divideSize) {
maxAxisValueX = maxValue;
axisDivideSizeX = divideSize;
}
/**
* 设置Y轴的最大值及刻度线数量(包括0坐标刻度)
*
* @param maxValue Y轴的最大值
* @param divideSize 刻度线数量
*/
public void setAxisY(float maxValue, int divideSize) {
maxAxisValueY = maxValue;
axisDivideSizeY = divideSize;
}
/**
* 设置柱状图数据
*
* @param columnInfo
*/
public void setColumnInfo(int[][] columnInfo) {
this.columnInfo = columnInfo;
}
@Override
public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
width = MeasureSpec.getSize(widthMeasureSpec) - 200;
height = MeasureSpec.getSize(heightMeasureSpec) - 800;
}
@Override
public void onDraw(Canvas canvas) {
drawAxisX(canvas, mPaint);
drawAxisY(canvas, mPaint);
drawAxisScaleMarkX(canvas, mPaint);
drawAxisScaleMarkY(canvas, mPaint);
drawAxisArrowsX(canvas, mPaint);
drawAxisArrowsY(canvas, mPaint);
drawAxisScaleMarkValueX(canvas, mPaint);
drawAxisScaleMarkValueY(canvas, mPaint);
drawColumn(canvas, mPaint);
drawTitle(canvas, mPaint);
}
/**
* 绘制横坐标轴(X轴)
*
* @param canvas
* @param paint
*/
private void drawAxisX(Canvas canvas, Paint paint) {
paint.setColor(Color.BLACK);
//设置画笔宽度
paint.setStrokeWidth(5);
//设置画笔抗锯齿
paint.setAntiAlias(true);
//画横轴(X)
canvas.drawLine(originX, originY, originX + width, originY, paint);
}
/**
* 绘制纵坐标轴(Y轴)
*
* @param canvas
* @param paint
*/
private void drawAxisY(Canvas canvas, Paint paint) {
//画竖轴(Y)
canvas.drawLine(originX, originY, originX, originY - height, paint);//参数说明:起始点左边x,y,终点坐标x,y,画笔
}
/**
* 绘制横坐标轴刻度线(X轴)
*
* @param canvas
* @param paint
*/
private void drawAxisScaleMarkX(Canvas canvas, Paint paint) {
float cellWidth = width / axisDivideSizeX;
for (int i = 0; i
MainActivity的布局文件:
MainActivity中使用
public class MainActivity extends ActionBarActivity {
private BarGraphView mBarGraphView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
}
private void initView(){
mBarGraphView = (BarGraphView)findViewById(R.id.custom_view);
mBarGraphView.setAxisX(900, 9);
mBarGraphView.setAxisY(700,7);
int columnInfo[][] = new int[][]{{600, Color.BLUE},{500, Color.GREEN},{400, Color.RED},{300, Color.BLUE},
{500, Color.YELLOW},{300, Color.LTGRAY},{200, Color.BLUE}};
mBarGraphView.setColumnInfo(columnInfo);
}
该自定义View的实现中使用了自定义属性的方式定义了三个属性值,关于attrs.xml文件的使用方式参考 http://blog.csdn.net/jiangwei0910410003/article/details/17006087
Android自定义View------柱状统计图