温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

怎么在Android中通过自定义控件实现一个折线图

发布时间:2021-04-20 17:49:52 来源:亿速云 阅读:207 作者:Leah 栏目:移动开发

这篇文章给大家介绍怎么在Android中通过自定义控件实现一个折线图,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。

Android是什么

Android是一种基于Linux内核的自由及开放源代码的操作系统,主要使用于移动设备,如智能手机和平板电脑,由美国Google公司和开放手机联盟领导及开发。

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

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

/*绘制三条横线*/ 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));

怎么在Android中通过自定义控件实现一个折线图

测试代码及效果;

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);   } });

怎么在Android中通过自定义控件实现一个折线图

完整代码如下:

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;   /*Handler刷新界面产生动画效果*/   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);     /*设置透明度,取值范围为0~255,数值越小越透明,0表示完全透明*/     mPaintLine1.setAlpha(0);     mPaintLine1.setAntiAlias(true);     mPaintLine1.setColor(mLineColor1);     mPaintLine1.setStrokeWidth(5);     mPaintLine2.setStyle(Paint.Style.STROKE);     /*设置透明度,取值范围为0~255,数值越小越透明,0表示完全透明*/     mPaintLine2.setAlpha(0);     mPaintLine2.setAntiAlias(true);     mPaintLine2.setColor(mLineColor2);     mPaintLine2.setStrokeWidth(5);     if (typedValue.resourceId==R.color.white){       /*PorterDuff.Mode.SCREEN 上下层都显示。*/       mPaintLine2.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SCREEN));       mPaintLine1.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SCREEN));     }else {       /*PorterDuff.Mode.DARKEN 上下层都显示。变暗*/       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);   } }

关于怎么在Android中通过自定义控件实现一个折线图就分享到这里了,希望以上内容可以对大家有一定的帮助,可以学到更多知识。如果觉得文章不错,可以把它分享出去让更多的人看到。

向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

AI