Android自定义控件实现折线图

时间:2021-05-20

本文实例实现一个如下图所示的Android折线图,供大家参考,具体内容如下

首先是控件绘图区域的划分,控件左边取一小部分(控件总宽度的八分之一)绘制表头,右边剩余的部分绘制表格

确定表格的行列数,首先绘制一个三行八列的网格,设置好行列的坐标后开始绘制

for(int i=0;i<3;i++){ canvas.drawLine(textWide, mLineYs[i], totalWidth, mLineYs[i], mPaintLine);}for(int i=0;i<8;i++){ canvas.drawLine(mLineXs[i], 0, mLineXs[i], totalHeight, mPaintLine);}

网格绘制完成后,开始绘制折线图

根据输入的节点数据,分别绘制两条折线

通过canvas的drawLine方法依次连接两点即可

在每个数据节点处绘制一个小圆,突出显示

for (int i = 0; i < mPerformance_1.length - 1; i++) { mPaintLine.setStrokeWidth(5); float prePointX =mLineXs[i]; float prePointY =mLineYs[2] - (mLineYs[2] - mLineYs[mPerformance_1[i].type]) * animCurrentValue; float nextPointX=mLineXs[i + 1]; float nextPointY=mLineYs[2] - (mLineYs[2] - mLineYs[mPerformance_1[i + 1].type]) * animCurrentValue; canvas.drawLine(prePointX, prePointY, nextPointX, nextPointY, mPaintLine1); canvas.drawCircle(prePointX, prePointY, mSmallDotRadius, mPointPaint);}

两条折线重合的地方,需要特殊考虑,比如希望两条折线重合的地方折线变为白色

设置下两条折线的画笔即可

mPaintLine2.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SCREEN));mPaintLine1.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SCREEN));

测试代码及效果;

final Random random=new Random();final LineChartView myView=(LineChartView)findViewById(R.id.custom_view);final LineChartView.Performance[] performances1=new LineChartView.Performance[8];final LineChartView.Performance[] performances2=new LineChartView.Performance[8];myView.setOnClickListener(new View.OnClickListener(){ @Override public void onClick(View v){ for(int i=0;i<performances1.length;i++){ switch (random.nextInt(2016)%3){ case 0: performances1[i]= LineChartView.Performance.WIN; break; case 1: performances1[i]= LineChartView.Performance.DRAW; break; case 2: performances1[i]= LineChartView.Performance.LOSE; break; default: performances1[i]= LineChartView.Performance.LOSE; break; } switch (random.nextInt(2016)%3){ case 0: performances2[i]= LineChartView.Performance.WIN; break; case 1: performances2[i]= LineChartView.Performance.DRAW; break; case 2: performances2[i]= LineChartView.Performance.LOSE; break; default: performances1[i]= LineChartView.Performance.LOSE; break; } } myView.setPerformances(performances1,performances2); }});

完整代码如下:

public class LineChartView extends View { private Context context; DecelerateInterpolator mDecelerateInterpolator = new DecelerateInterpolator(); private int mDuration = 10; private int mCurrentTime = 0; private Performance[] mPerformance_1, mPerformance_2; private int mLineColor1, mLineColor2; private Paint mPaintText = new Paint(); private Paint mPaintLine = new Paint(); private Paint mPaintLine1 =new Paint(); private Paint mPaintLine2 =new Paint(); private Paint mPointPaint = new Paint(); private float mSmallDotRadius = 4; private TypedValue typedValue; private int mPaintClolor; private Handler mHandler = new Handler(); private Runnable mAnimation = new Runnable() { @Override public void run() { if (mCurrentTime < mDuration) { mCurrentTime++; LineChartView.this.invalidate(); } } }; public LineChartView(Context context) { super(context); this.context=context; init(); } public LineChartView(Context context, AttributeSet attrs) { super(context, attrs); this.context=context; init(); } public LineChartView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); this.context=context; init(); } public enum Performance { WIN(0), DRAW(1), LOSE(2); public int type; Performance(int type) { this.type = type; } } public void setPerformances(Performance[] performance1, Performance[] performance2) { if (performance1 == null) { performance1 = new Performance[0]; } if (performance2 == null) { performance2 = new Performance[0]; } mPerformance_1 = Arrays.copyOf(performance1, performance1.length > 8 ? 8 : performance1.length); mPerformance_2 = Arrays.copyOf(performance2, performance2.length > 8 ? 8 : performance2.length); if (isShown()) { mCurrentTime = 0; this.invalidate(); } } /** * 设置折线1的颜色 * * @param mLineColor1 */ public void setLineColor1(int mLineColor1) { this.mLineColor1 = mLineColor1; } /** * 设置折线2的颜色 * * @param mLineColor2 */ public void setLineColor2(int mLineColor2) { this.mLineColor2 = mLineColor2; } private void init() { mLineColor1=Color.BLUE; mLineColor2 = Color.GREEN; typedValue=new TypedValue(); context.getTheme().resolveAttribute(R.attr.title_bar,typedValue,true); mPaintClolor =getResources().getColor(typedValue.resourceId); final LineChartView.Performance[] performances1=new LineChartView.Performance[8]; final LineChartView.Performance[] performances2=new LineChartView.Performance[8]; final Random random=new Random(); for(int i=0;i<performances1.length;i++){ switch (random.nextInt(2016)%3){ case 0: performances1[i]= LineChartView.Performance.WIN; break; case 1: performances1[i]= LineChartView.Performance.DRAW; break; case 2: performances1[i]= LineChartView.Performance.LOSE; break; default: performances1[i]= LineChartView.Performance.LOSE; break; } switch (random.nextInt(2016)%3){ case 0: performances2[i]= LineChartView.Performance.WIN; break; case 1: performances2[i]= LineChartView.Performance.DRAW; break; case 2: performances2[i]= LineChartView.Performance.LOSE; break; default: performances1[i]= LineChartView.Performance.LOSE; break; } } setPerformances(performances1,performances2); } /** * @param canvas */ @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); float totalWidth = getWidth(); float totalHeight = getHeight(); float textWide = totalWidth / 8; float left_offset = 10; float chartWide = totalWidth - textWide - left_offset; float[] mLineYs = new float[]{totalHeight / 8, totalHeight / 2, totalHeight * 7 / 8}; float[] mLineXs = new float[]{ textWide + left_offset + chartWide * 0 / 8, textWide + left_offset + chartWide * 1 / 8, textWide + left_offset + chartWide * 2 / 8, textWide + left_offset + chartWide * 3 / 8, textWide + left_offset + chartWide * 4 / 8, textWide + left_offset + chartWide * 5 / 8, textWide + left_offset + chartWide * 6 / 8, textWide + left_offset + chartWide * 7 / 8, }; mPaintText.setStyle(Paint.Style.FILL); mPaintText.setColor(mPaintClolor); mPaintText.setAlpha(226); mPaintText.setTextSize(28); mPaintText.setTextAlign(Paint.Align.CENTER); Paint.FontMetrics fontMetrics = mPaintText.getFontMetrics(); float textBaseLineOffset = (fontMetrics.bottom - fontMetrics.top) / 2 - fontMetrics.bottom; canvas.drawText("胜场", textWide / 2, mLineYs[0] + textBaseLineOffset, mPaintText); canvas.drawText("平局", textWide / 2, mLineYs[1] + textBaseLineOffset, mPaintText); canvas.drawText("负场", textWide / 2, mLineYs[2] + textBaseLineOffset, mPaintText); mPaintLine.setStyle(Paint.Style.STROKE); mPaintLine.setAntiAlias(true); mPaintLine.setColor(mPaintClolor); mPaintLine.setAlpha(80); mPaintLine.setStrokeWidth(1); for(int i=0;i<3;i++){ canvas.drawLine(textWide, mLineYs[i], totalWidth, mLineYs[i], mPaintLine); } for(int i=0;i<8;i++){ canvas.drawLine(mLineXs[i], 0, mLineXs[i], totalHeight, mPaintLine); } mPaintLine1.setStyle(Paint.Style.STROKE); mPaintLine1.setAlpha(0); mPaintLine1.setAntiAlias(true); mPaintLine1.setColor(mLineColor1); mPaintLine1.setStrokeWidth(5); mPaintLine2.setStyle(Paint.Style.STROKE); mPaintLine2.setAlpha(0); mPaintLine2.setAntiAlias(true); mPaintLine2.setColor(mLineColor2); mPaintLine2.setStrokeWidth(5); if (typedValue.resourceId==R.color.white){ mPaintLine2.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SCREEN)); mPaintLine1.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SCREEN)); }else { mPaintLine2.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DARKEN)); mPaintLine1.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DARKEN)); } mPointPaint.setStyle(Paint.Style.STROKE); mPointPaint.setAntiAlias(true); mPointPaint.setColor(mPaintClolor); float animCurrentValue = mDecelerateInterpolator.getInterpolation(1.0f * mCurrentTime / mDuration); mPaintLine.setColor(mLineColor1); for (int i = 0; i < mPerformance_1.length - 1; i++) { mPaintLine.setStrokeWidth(5); float prePointX =mLineXs[i]; float prePointY =mLineYs[2] - (mLineYs[2] - mLineYs[mPerformance_1[i].type]) * animCurrentValue; float nextPointX=mLineXs[i + 1]; float nextPointY=mLineYs[2] - (mLineYs[2] - mLineYs[mPerformance_1[i + 1].type]) * animCurrentValue; canvas.drawLine(prePointX, prePointY, nextPointX, nextPointY, mPaintLine1); canvas.drawCircle(prePointX, prePointY, mSmallDotRadius, mPointPaint); } float lastPointX=mLineXs[mPerformance_1.length - 1]; float lastPointY= mLineYs[2] - (mLineYs[2] - mLineYs[mPerformance_1[mPerformance_1.length - 1].type]) * animCurrentValue; canvas.drawCircle(lastPointX,lastPointY ,mSmallDotRadius, mPointPaint); mPaintLine.setColor(mLineColor2); for (int i = 0; i < mPerformance_2.length - 1; i++) { mPaintLine.setStrokeWidth(5); float prePointX =mLineXs[i]; float prePointY =mLineYs[2] - (mLineYs[2] - mLineYs[mPerformance_2[i].type]) * animCurrentValue; float nextPointX=mLineXs[i + 1]; float nextPointY=mLineYs[2] - (mLineYs[2] - mLineYs[mPerformance_2[i + 1].type]) * animCurrentValue; canvas.drawLine(prePointX, prePointY, nextPointX, nextPointY, mPaintLine2); canvas.drawCircle(prePointX, prePointY, mSmallDotRadius, mPointPaint); } lastPointX=mLineXs[mPerformance_2.length - 1]; lastPointY= mLineYs[2] - (mLineYs[2] - mLineYs[mPerformance_2[mPerformance_2.length - 1].type]) * animCurrentValue; canvas.drawCircle(lastPointX,lastPointY ,mSmallDotRadius, mPointPaint); mHandler.postDelayed(mAnimation, 20); }}

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。

声明:本页内容来源网络,仅供用户参考;我单位不保证亦不表示资料全面及准确无误,也不保证亦不表示这些资料为最新信息,如因任何原因,本网内容或者用户因倚赖本网内容造成任何损失或损害,我单位将不会负任何法律责任。如涉及版权问题,请提交至online#300.cn邮箱联系删除。

相关文章