效果图:

07551ddfb911

image

07551ddfb911

image

设计图标注:

07551ddfb911

image

1.自定义折线图LineChartView的属性,可以参照上面给出的标注图:

2.在布局文件使用自定义的属性值画图,自定义一个LineChartView嵌套在HorizontalScrollView下面,让LineChartView可以左右滑动;

android:layout_width="match_parent"

android:layout_height="match_parent"

xmlns:linchart="http://schemas.android.com/apk/res-auto"

android:orientation="vertical">

android:layout_width="match_parent"

android:layout_height="wrap_content"

android:fillViewport="true"

android:scrollbars="none"

android:layout_marginTop="50dp">

android:layout_width="match_parent"

android:layout_height="wrap_content">

android:id="@+id/lineChart"

android:layout_width="match_parent"

android:layout_height="200dp"

linchart:lineColor="@color/colorLine"

linchart:dividerCount="5"

linchart:xInterval="70dp"

linchart:leftInterval="20dp"

linchart:bottomInterval="20dp"

linchart:topInterval="40dp"

linchart:yAxisFontSize="14sp"/>

3.看一下LineChartView的代码,在构造函数里获取自定义的属性值:

public LineChartView(Context context, AttributeSet attrs, int defStyleAttr) {

super(context, attrs, defStyleAttr);

/**

* 获得我们所定义的自定义样式属性

*/

TypedArray a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.LineChartView, defStyleAttr, 0);

int n = a.getIndexCount();

for (int i = 0; i < n; i++){

int index = a.getIndex(i);

switch (index)

{

// 折线颜色

case R.styleable.LineChartView_lineColor:

mLineColor = a.getColor(index, Color.BLACK);

break;

// X轴每个刻度的间距间距

case R.styleable.LineChartView_dividerCount:

dividerCount = a.getInt(index, 5);

break;

// X轴每个刻度的间距间距

case R.styleable.LineChartView_xInterval:

mxInterval = a.getDimensionPixelSize(index, (int) TypedValue.applyDimension(

TypedValue.COMPLEX_UNIT_DIP, 16, getResources().getDisplayMetrics()));

break;

// Y轴距离view长度

case R.styleable.LineChartView_leftInterval:

mLeftInterval = a.getDimensionPixelSize(index, (int) TypedValue.applyDimension(

TypedValue.COMPLEX_UNIT_DIP, 16, getResources().getDisplayMetrics()));

break;

// X轴距离view底部的高度

case R.styleable.LineChartView_bottomInterval:

mBottomInterval = a.getDimensionPixelSize(index, (int) TypedValue.applyDimension(

TypedValue.COMPLEX_UNIT_DIP, 16, getResources().getDisplayMetrics()));

break;

// X轴距离view顶部长度

case R.styleable.LineChartView_topInterval:

mTopInterval = a.getDimensionPixelSize(index, (int) TypedValue.applyDimension(

TypedValue.COMPLEX_UNIT_DIP, 16, getResources().getDisplayMetrics()));

break;

// Y轴字体的大小

case R.styleable.LineChartView_yAxisFontSize:

// 默认设置为16sp,TypeValue也可以把sp转化为px

mYAxisFontSize = a.getDimensionPixelSize(index, (int) TypedValue.applyDimension(

TypedValue.COMPLEX_UNIT_SP, 16, getResources().getDisplayMetrics()));

break;

}

}

a.recycle();

}

4.然后在构造函数调用init()方法,初始化各种画笔,注意一点的是,折线与折线之间的交点,为了达到线与圆之间有间隙,圆心有空隙,我是用三个画笔来画这圆的.

private void init(Context context){

// 画坐标线的轴

axisPaint = new Paint();

axisPaint.setTextSize(mYAxisFontSize);

axisPaint.setColor(Color.parseColor("#D9D9D9"));

// 画X轴文字

axisTextPaint = new Paint();

axisTextPaint.setTextSize(mYAxisFontSize);

axisTextPaint.setColor(Color.parseColor("#878787"));

// 连接线条

linePaint = new Paint();

linePaint.setColor(mLineColor);

linePaint.setAntiAlias(true);

linePaint.setStyle(Paint.Style.STROKE);

linePaint.setStrokeWidth(mStrokeWidth);

// 小圆点内环

innerCirclePaint = new Paint();

innerCirclePaint.setStyle(Paint.Style.FILL);

innerCirclePaint.setAntiAlias(true);

innerCirclePaint.setColor(Color.WHITE);

innerCirclePaint.setStrokeWidth(UtilApp.dip2px(context,2));

// 小圆点中间环

middleCiclePaint = new Paint();

middleCiclePaint.setStyle(Paint.Style.STROKE);

middleCiclePaint.setAntiAlias(true);

middleCiclePaint.setColor(mLineColor);

middleCiclePaint.setStrokeWidth(UtilApp.dip2px(context,2));

// 小圆点外环

outterCiclePaint = new Paint();

outterCiclePaint.setStyle(Paint.Style.STROKE);

outterCiclePaint.setAntiAlias(true);

outterCiclePaint.setColor(Color.WHITE);

outterCiclePaint.setStrokeWidth(UtilApp.dip2px(context,2));

// 折线路径

mpolylinePath = new Path();

//小圆点内环半径

innerCircleRadius = UtilApp.dip2px(context,3);

//小圆点中间环半径

middleRadius = UtilApp.dip2px(context,4);

//小圆点外环半径

outerRadius = UtilApp.dip2px(context,6);

}

5.在onMeasure()方法根据传入X轴值的数量算出折线图的宽( mWidth = mxInterval(mXAxis.size()-1) + mLeftInterval2;),折线图的高根据XML的定义好的高度获取.

@Override

protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

int widthMode = MeasureSpec.getMode(widthMeasureSpec);

int heightMode = MeasureSpec.getMode(heightMeasureSpec);

int widthSize = MeasureSpec.getSize(widthMeasureSpec);

int heightSize = MeasureSpec.getSize(heightMeasureSpec);

Log.d(TAG,"widthSize:"+widthSize+",heightSize:"+heightSize );

mHeight =heightSize;

if(mXAxis == null){

Log.d(TAG,"mWidth:"+mWidth+",mHeight:"+mHeight +"mXAxis:"+mXAxis);

return;

}

//宽度通过数组长度计算

mWidth = mxInterval*(mXAxis.size()-1) + mLeftInterval*2;

setMeasuredDimension(mWidth, mHeight);

}

6.在onLayout()方法根据要划分Y轴的数量,算出Y轴每个刻度之间的数量值:

@Override

protected void onLayout(boolean changed, int left, int top, int right, int bottom) {

super.onLayout(changed, left, top, right, bottom);

myInterval = (getHeight()-mBottomInterval-mTopInterval)/dividerCount;

}

7.在onDraw()方法分别画X,Y坐标轴,折线和交点.

@Override

protected void onDraw(Canvas canvas) {

if(mXAxis.size() ==0 || mYAxis.size()==0){

Log.e(TAG,"数据异常");

return;

}

// 画横线

for(int i = 0;i <= dividerCount;i++){

canvas.drawLine(mLeftInterval, mHeight - mBottomInterval - i * myInterval, (mXAxis.size()-1)*mxInterval+ mLeftInterval,

mHeight - mBottomInterval - myInterval * i, axisPaint);

}

// x轴的刻度集合

int[] xPoints = new int[mXAxis.size()];

for (int i = 0; i < mXAxis.size(); i++) {

float xTextWidth = axisPaint.measureText(mXAxis.get(i))/2 ; //文字宽度一半

float xfloat = i * mxInterval + mLeftInterval - xTextWidth;

// 画X轴的文字

canvas.drawText(mXAxis.get(i), xfloat, mHeight - mBottomInterval + mYAxisFontSize, axisTextPaint);

xPoints[i] = (int) (xfloat+xTextWidth);

// 画竖线

float xvfloat = i * mxInterval + mLeftInterval;

canvas.drawLine(xvfloat,mHeight - mBottomInterval, xvfloat,

mHeight - mBottomInterval - myInterval*dividerCount, axisPaint);

}

/**

* 画轨迹

*/

int y = myInterval * (dividerCount - 1); // 只拿纵轴的dividerCount-1/dividerCount画图

axisPaint.setColor(mLineColor); // 设置坐标值的颜色

for (int i = 0;i

int h = mHeight - (mBottomInterval + y * mYAxis.get(i)/ maxYValue);

float textWidth = axisPaint.measureText(String.valueOf(mYAxis.get(i)))/2 ; //文字宽度一半

if (i==0){

mpolylinePath.moveTo(mLeftInterval,h);

canvas.drawText(mYAxis.get(i) + "", mLeftInterval - textWidth, h - mYAxisFontSize, axisPaint);

}else{

mpolylinePath.lineTo(mLeftInterval + i*mxInterval,h);

canvas.drawText(mYAxis.get(i) + "", mLeftInterval+i*mxInterval- textWidth, h - mYAxisFontSize, axisPaint);

}

}

canvas.drawPath(mpolylinePath,linePaint);

/**

* 画小圆圈

*/

for (int i = 0;i

int h = mHeight - (mBottomInterval + y * mYAxis.get(i)/ maxYValue);

if (i==0){

canvas.drawCircle(mLeftInterval,h,innerCircleRadius,innerCirclePaint);

canvas.drawCircle(mLeftInterval,h,middleRadius,middleCiclePaint);

canvas.drawCircle(mLeftInterval,h,outerRadius,outterCiclePaint);

}else{

canvas.drawCircle(mLeftInterval + i*mxInterval,h,innerCircleRadius,innerCirclePaint);

canvas.drawCircle(mLeftInterval + i*mxInterval,h,middleRadius,middleCiclePaint);

canvas.drawCircle(mLeftInterval + i*mxInterval,h,outerRadius,outterCiclePaint);

}

}

}

8.在MainActivity设置好X轴和Y轴的值,并求出Y轴的最大值.

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

mLineChartView = (LineChartView) findViewById(R.id.lineChart);

//X轴

String[] xItem = {"4/1","4/2","4/3","4/4","4/5","4/6","4/7","4/8","4/9","4/10","4/11","4/12",

"4/13","4/14","4/15","4/16","4/17","4/18","4/19","4/20","4/21","4/22","4/23","4/24"

,"4/25","4/26","4/27","4/28","4/29","4/30"};

ArrayList xItemArray = new ArrayList();

for (int i = 0; i < xItem.length; i++) {

xItemArray.add(xItem[i]);

}

//Y轴

int[] yItem = {3,7,19,7,20,19,27,8,18,19,21,20,19,20,8,18,19,21,20,22,21,24,26,24,20,22,21,24,26,24};

ArrayList yItemArray = new ArrayList<>();

for (int i = 0; i < yItem.length; i++) {

yItemArray.add(yItem[i]);

}

int yMax = findMax(yItem);

mLineChartView.setXItem(xItemArray);

mLineChartView.setYItem(yItemArray);

mLineChartView.setMaxYValue(yMax);

}

Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐