温馨提示×

温馨提示×

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

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

怎么在Android中绘制一个曲线图

发布时间:2021-03-10 16:32:12 来源:亿速云 阅读:304 作者:Leah 栏目:移动开发

这期内容当中小编将会给大家带来有关怎么在Android中绘制一个曲线图,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。

使用方式

// 初始化数据表格相关 with(mTableView) {   // 配置坐标系   setupCoordinator("日", "人", /*这里是横坐标的值*/0f, 5f, 10f, 15f, 20f, 25f, 30f)   // 添加曲线, 确保纵坐标的数值位数相等   addWave(ContextCompat.getColor(this@MainActivity, R.color.colorYellow), false,       0f, 10f, 30f, 54f, 30f, 100f, 10f)   addWave(ContextCompat.getColor(this@MainActivity, R.color.colorGreen), false,       0f, 30f, 20f, 20f, 46f, 25f, 5f)   addWave(ContextCompat.getColor(this@MainActivity, R.color.colorPink), false,       0f, 30f, 20f, 50f, 46f, 30f, 30f)   addWave(Color.parseColor("#8596dee9"), true,       0f, 15f, 10f, 10f, 40f, 20f, 5f) }

实现思路

  1. 横坐标是固定的, 纵坐标需要跟随曲线传入的数值去动态的调整

  2. 绘制坐标轴: 纵横交错的网格

  3. 根据用户传入坐标数值去绘制坐标轴上的数值

  4. 给X轴和Y轴添加单位信息

  5. 根据用户传入的具体的数值绘制曲线(这里不采用Bezier, 不容易精确的控制顶点的位置)

  6. 绘制填充效果

  7. 添加属性动画

代码实现

/**  * Created by FrankChoo on 2017/12/29.  * Email: frankchoochina@gmail.com  * Version: 1.0  * Description: 表格自定义View  */ public class TableView extends View {   private List<WaveConfigData> mWaves;// 数值集合   // 坐标轴的数值   private int mCoordinateYCount = 8;   private float[] mCoordinateXValues;// 外界传入   private float[] mCoordinateYValues;// 动态计算   // 坐标的单位   private String mXUnit;   private String mYUnit;   // 所有曲线中所有数据中的最大值   private float mGlobalMaxValue;// 用于确认是否需要调整坐标系   private Paint mCoordinatorPaint;   private Paint mTextPaint;   private Paint mWrapPaint;   // 坐标轴上描述性文字的空间大小   private int mTopUnitHeight;// 顶部Y轴单位高度   private int mBottomTextHeight;   private int mLeftTextWidth;   // 网格尺寸   private int mGridWidth, mGridHeight;   private float mAnimProgress;   public TableView(Context context) {     this(context, null);   }   public TableView(Context context, @Nullable AttributeSet attrs) {     this(context, attrs, 0);   }   public TableView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {     super(context, attrs, defStyleAttr);     init();     post(new Runnable() {       @Override       public void run() {         showAnimator();       }     });   }   private void init() {     // 初始化数据集合的容器     mWaves = new ArrayList<>();     // 坐标系的单位     mBottomTextHeight = dp2px(40);// X轴底部字体的高度     mLeftTextWidth = mBottomTextHeight;// Y轴左边字体的宽度     mTopUnitHeight = dp2px(30);// 顶部Y轴的单位     // 初始化坐标轴Paint     mCoordinatorPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.DITHER_FLAG);     mCoordinatorPaint.setColor(Color.LTGRAY);     // 初始化文本Paint     mTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.DITHER_FLAG);     mTextPaint.setColor(Color.GRAY);     mTextPaint.setTextSize(sp2px(12));     // 初始化曲线Paint     mWrapPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.DITHER_FLAG);     mWrapPaint.setPathEffect(new CornerPathEffect(200f));   }   /**    * 配置坐标轴信息    *    * @param xUnit       X 轴的单位    * @param yUnit       Y 轴的单位    * @param coordinateXValues X 坐标轴上的数值    */   public void setupCoordinator(String xUnit, String yUnit, float... coordinateXValues) {     mXUnit = xUnit;     mYUnit = yUnit;     mCoordinateXValues = coordinateXValues;   }   /**    * 添加一条曲线, 确保与横坐标的数值对应    *    * @param color    * @param isCoverRegion    * @param values    */   public void addWave(int color, boolean isCoverRegion, float... values) {     mWaves.add(new WaveConfigData(color, isCoverRegion, values));     // 根据value的值去计算纵坐标的数值     float maxValue = 0;     for (float value : values) {       maxValue = Math.max(maxValue, value);     }     if (maxValue < mGlobalMaxValue) return;     mGlobalMaxValue = maxValue;     // 保证网格的数值都为 5 的倍数     float gridValue = mGlobalMaxValue / (mCoordinateYCount - 1);     if (gridValue % 5 != 0) {       gridValue += 5 - (gridValue % 5);     }     // 给纵坐标的数值赋值     mCoordinateYValues = new float[mCoordinateYCount];     for (int i = 0; i < mCoordinateYCount; i++) {       mCoordinateYValues[i] = i * gridValue;     }     invalidate();   }   @Override   protected void onDraw(Canvas canvas) {     drawCoordinate(canvas);     drawWrap(canvas);   }   public void showAnimator() {     ValueAnimator animator = ValueAnimator.ofFloat(0f, 1f).setDuration(1000);     animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {       @Override       public void onAnimationUpdate(ValueAnimator animation) {         mAnimProgress = (float) animation.getAnimatedValue();         invalidate();       }     });     animator.start();   }   /**    * 绘制坐标系    */   private void drawCoordinate(Canvas canvas) {     Point start = new Point();     Point stop = new Point();     // 1. 绘制横轴线和纵坐标单位     int xLineCount = mCoordinateYValues.length;     mGridHeight = (getHeight() - getPaddingTop() - getPaddingBottom() - mBottomTextHeight - mTopUnitHeight) / (xLineCount - 1);     for (int i = 0; i < xLineCount; i++) {       start.x = getPaddingLeft() + mLeftTextWidth;       start.y = getHeight() - getPaddingBottom() - mBottomTextHeight - mGridHeight * i;       stop.x = getRight() - getPaddingRight();       stop.y = start.y;       // 绘制横轴线       canvas.drawLine(start.x, start.y, stop.x, stop.y, mCoordinatorPaint);       // 绘制纵坐标单位       if (i == 0) continue;       String drawText = String.valueOf((int) mCoordinateYValues[i]);       Paint.FontMetricsInt fontMetrics = mTextPaint.getFontMetricsInt();       float offsetY = ((fontMetrics.bottom - fontMetrics.top) / 2 + fontMetrics.bottom) / 2;       float baseLine = start.y + offsetY;       float left = getPaddingLeft() + mLeftTextWidth / 2 - mTextPaint.measureText(drawText) / 2;       canvas.drawText(drawText, left, baseLine, mTextPaint);       // 绘制Y轴单位       if (i == xLineCount - 1) {         drawText = mYUnit;         baseLine = getPaddingTop() + mTopUnitHeight / 2;         canvas.drawText(drawText, left, baseLine, mTextPaint);       }     }     // 2. 绘制纵轴线和横坐标单位     int yLineCount = mCoordinateXValues.length;     mGridWidth = (getWidth() - getPaddingLeft() - getPaddingRight() - mLeftTextWidth) / (yLineCount - 1);     for (int i = 0; i < yLineCount; i++) {       start.x = getPaddingTop() + mLeftTextWidth + mGridWidth * i;       start.y = getPaddingTop() + mTopUnitHeight;       stop.x = start.x;       stop.y = getHeight() - mBottomTextHeight - getPaddingBottom();       // 绘制纵轴线       canvas.drawLine(start.x, start.y, stop.x, stop.y, mCoordinatorPaint);       // 绘制横坐标单位       String drawText = String.valueOf((int) mCoordinateXValues[i]);       Paint.FontMetricsInt fontMetrics = mTextPaint.getFontMetricsInt();       float offsetY = ((fontMetrics.bottom - fontMetrics.top) / 2 + fontMetrics.bottom) / 2;       float baseLine = getHeight() - getPaddingBottom() - mBottomTextHeight / 2 + offsetY;       float left = start.x - mTextPaint.measureText(drawText) / 2;       // 绘制X轴单位       if (i == 0) {         drawText = mXUnit;         left = getPaddingLeft() + mLeftTextWidth / 2 - mTextPaint.measureText(drawText) / 2;       }       canvas.drawText(drawText, left, baseLine, mTextPaint);     }   }   /**    * 绘制曲线    */   private void drawWrap(Canvas canvas) {     canvas.clipRect(new RectF(         mLeftTextWidth,         getPaddingTop() + mTopUnitHeight,         (getRight() - getPaddingRight()) * mAnimProgress,         getHeight() - getPaddingBottom() - mBottomTextHeight)     );     float yHeight = mGridHeight * (mCoordinateYCount - 1);     for (WaveConfigData wave : mWaves) {       Path path = new Path();       path.moveTo(0, getHeight());       float maxY = mCoordinateYValues[mCoordinateYCount - 1];// Y轴坐标的最大值       for (int index = 1; index < wave.values.length; index++) {         path.lineTo(             mLeftTextWidth + mGridWidth * index,             getHeight() - getPaddingBottom() - mBottomTextHeight                 - yHeight * (wave.values[index] / maxY)         );       }       if (wave.isCoverRegion) {         mWrapPaint.setStyle(Paint.Style.FILL);         path.lineTo(getRight() - getPaddingRight(), getHeight());         path.close();       } else {         mWrapPaint.setStyle(Paint.Style.STROKE);         mWrapPaint.setStrokeWidth(10);       }       mWrapPaint.setColor(wave.color);       canvas.drawPath(path, mWrapPaint);     }   }   private int dp2px(float dp) {     return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,         dp, getResources().getDisplayMetrics());   }   private int sp2px(float sp) {     return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP,         sp, getResources().getDisplayMetrics());   }   public static class WaveConfigData {     int color;     boolean isCoverRegion;     float values[];     public WaveConfigData(int color, boolean isCoverRegion, float[] values) {       this.color = color;       this.isCoverRegion = isCoverRegion;       this.values = values;     }   } }

上述就是小编为大家分享的怎么在Android中绘制一个曲线图了,如果刚好有类似的疑惑,不妨参照上述分析进行理解。如果想知道更多相关知识,欢迎关注亿速云行业资讯频道。

向AI问一下细节

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

AI