您好,登錄后才能下訂單哦!
這期內容當中小編將會給大家帶來有關怎么在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) }
實現思路
橫坐標是固定的, 縱坐標需要跟隨曲線傳入的數值去動態的調整
繪制坐標軸: 縱橫交錯的網格
根據用戶傳入坐標數值去繪制坐標軸上的數值
給X軸和Y軸添加單位信息
根據用戶傳入的具體的數值繪制曲線(這里不采用Bezier, 不容易精確的控制頂點的位置)
繪制填充效果
添加屬性動畫
代碼實現
/** * 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中繪制一個曲線圖了,如果剛好有類似的疑惑,不妨參照上述分析進行理解。如果想知道更多相關知識,歡迎關注億速云行業資訊頻道。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。