<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
本文範例為大家分享了android實現可以滑動的平滑曲線圖的具體程式碼,供大家參考,具體內容如下
直接上程式碼,裡面有詳細註解
1 attr 屬性編寫
<!-- xy座標軸顏色 --> <attr name="xy_line_color" format="color" /> <!-- xy座標軸寬度 --> <attr name="xy_line_width" format="dimension" /> <!-- xy座標軸文字顏色 --> <attr name="xy_text_color" format="color" /> <!-- xy座標軸文字大小 --> <attr name="xy_text_size" format="dimension" /> <!-- 折線圖中折線的顏色 --> <attr name="line_color" format="color" /> <!-- x軸各個座標點水平間距 --> <attr name="interval" format="dimension" /> <!-- 背景顏色 --> <attr name="bg_color" format="color" /> <!-- 曲線選中外部顏色 --> <attr name="select_circle_color" format="color" /> <!-- 曲線選中內部顏色 --> <attr name="select_reminder_color" format="color" /> <!--是否擡手卷動--> <attr name="isScroll" format="boolean" /> <declare-styleable name="ChartView"> <attr name="xy_line_color" /> <attr name="xy_line_width" /> <attr name="xy_text_color" /> <attr name="xy_text_size" /> <attr name="line_color" /> <attr name="interval" /> <attr name="bg_color" /> <attr name="select_circle_color" /> <attr name="select_reminder_color" /> <attr name="isScroll" /> <!--提示框跟滑動顯示的位置--> <attr name="show_position"> <enum name="first" value="1" /> <enum name="middle" value="2" /> <enum name="end" value="3" /> </attr> </declare-styleable>
2 ChartView
package com.laisontech.commonuilibrary.customviews; import android.animation.Animator; import android.animation.ValueAnimator; import android.content.Context; import android.content.res.TypedArray; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.Path; import android.graphics.PorterDuff; import android.graphics.PorterDuffXfermode; import android.graphics.Rect; import android.graphics.RectF; import android.util.AttributeSet; import android.util.Log; import android.util.TypedValue; import android.view.MotionEvent; import android.view.VelocityTracker; import android.view.View; import android.view.animation.DecelerateInterpolator; import com.laisontech.commonuilibrary.R; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; /** * 自定義折線圖 */ public class ChartView extends View { private static final int FIRST = 1; private static final int MIDDLE = 2; private static final int END = 3; //xy座標軸顏色 private int xyLineColor = 0xffCFE2CF; //折線選中的圓形顏色 private int selectCircleColor = 0xff00A8FF; //選中資料提示框顏色 private int selectReminderColor = 0xff00A8FF; //折線中圓形內部部顏色 private int xyTextColor = 0xff0014FF; //折線圖中折線的顏色 private int lineColor = 0xffFD00FF; //xy座標軸寬度 private int xyLineWidth = dpToPx(1); //xy座標軸文字大小 private int xyTextSize = spToPx(12); //x軸各個座標點水平間距 private int interval = dpToPx(40); //背景顏色 private int bgColor = 0xffffffff; //是否有起手時的滑動感 private boolean isScroll = false; //提示框顯示位置 private int mShowPositionType = 3; //繪製XY軸座標對應的畫筆 private Paint mXYPaint; //繪製XY軸的文字對應的畫筆 private Paint mXYTextPaint; //畫折線對應的畫筆 private Paint mSpinnerLinePaint; private int width; private int height; //x軸的原點座標 private int mXOri; //y軸的原點座標 private int mYOri; //第一個點X的座標 private float mXInit; //第一個點對應的最大X座標 private float maxXInit; //第一個點對應的最小X座標 private float minXInit; //x軸座標對應的資料 private List<String> mXData = new ArrayList<>(); //y軸座標對應的資料 private List<Integer> mYData = new ArrayList<>(); //折線對應的資料 private Map<String, Integer> mSpinnerValue = new HashMap<>(); //點選的點對應的X軸的第幾個點,預設1 private int selectIndex = 1; //X軸刻度文字對應的最大矩形,為了選中時,在x軸文字畫的框框大小一致,獲取從資料中得到的x軸資料,獲得最長資料 private Rect xValueRect; //速度檢測器 private VelocityTracker mTracker; //是否為短距離滑動 private boolean isShortSlide = false; //獲取尺寸的的中間 private int mSelectMiddle = 0; //曲線切率 private float mLineSmoothness = 0.18f; public ChartView(Context context) { this(context, null); } public ChartView(Context context, AttributeSet attrs) { this(context, attrs, 0); } public ChartView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(context, attrs, defStyleAttr); initPaint(); } //設定切率 public void setLineSmoothness(float lineSmoothness) { if (lineSmoothness != this.mLineSmoothness) { this.mLineSmoothness = lineSmoothness; } } /** * 初始化 */ private void initPaint() { mXYPaint = new Paint(); mXYPaint.setAntiAlias(true); mXYPaint.setStrokeWidth(xyLineWidth); mXYPaint.setStrokeJoin(Paint.Join.ROUND); mXYPaint.setColor(xyLineColor); mXYTextPaint = new Paint(); mXYTextPaint.setAntiAlias(true); mXYTextPaint.setTextSize(xyTextSize); mXYTextPaint.setStrokeJoin(Paint.Join.ROUND); mXYTextPaint.setColor(xyTextColor); mXYTextPaint.setStyle(Paint.Style.STROKE); mSpinnerLinePaint = new Paint(); mSpinnerLinePaint.setAntiAlias(true); mSpinnerLinePaint.setStrokeWidth(xyLineWidth); mSpinnerLinePaint.setColor(lineColor); mSpinnerLinePaint.setStyle(Paint.Style.STROKE); mSpinnerLinePaint.setStrokeJoin(Paint.Join.ROUND); } /** * 初始化 * * @param context * @param attrs * @param defStyleAttr */ private void init(Context context, AttributeSet attrs, int defStyleAttr) { TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.ChartView, defStyleAttr, 0); int count = array.getIndexCount(); for (int i = 0; i < count; i++) { int attr = array.getIndex(i); if (attr == R.styleable.ChartView_xy_line_color) { xyLineColor = array.getColor(attr, xyLineColor); } else if (attr == R.styleable.ChartView_xy_line_width) { xyLineWidth = (int) array.getDimension(attr, TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_PX, xyLineWidth, getResources().getDisplayMetrics())); } else if (attr == R.styleable.ChartView_xy_text_color) { xyTextColor = array.getColor(attr, xyTextColor); } else if (attr == R.styleable.ChartView_xy_text_size) { xyTextSize = (int) array.getDimension(attr, TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_PX, xyTextSize, getResources().getDisplayMetrics())); } else if (attr == R.styleable.ChartView_line_color) { lineColor = array.getColor(attr, lineColor); } else if (attr == R.styleable.ChartView_interval) { interval = (int) array.getDimension(attr, TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_PX, interval, getResources().getDisplayMetrics())); } else if (attr == R.styleable.ChartView_bg_color) { bgColor = array.getColor(attr, bgColor); } else if (attr == R.styleable.ChartView_select_circle_color) { selectCircleColor = array.getColor(attr, selectCircleColor); } else if (attr == R.styleable.ChartView_select_reminder_color) { selectReminderColor = array.getColor(attr, selectReminderColor); } else if (attr == R.styleable.ChartView_isScroll) { isScroll = array.getBoolean(attr, isScroll); } else if (attr == R.styleable.ChartView_show_position) { mShowPositionType = array.getInt(attr, mShowPositionType); } } array.recycle(); } @Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) { if (changed) { width = getWidth(); height = getHeight(); //Y軸文字的最大寬度 float textYWdith = getTextBounds(mYData.get(getListItemMaxIndex(mYData)) + "", mXYTextPaint).width(); for (int i = 0; i < mYData.size(); i++) {//求取y軸文字最大的寬度 float temp = getTextBounds(mYData.get(i) + "", mXYTextPaint).width(); if (temp > textYWdith) textYWdith = temp; } int dp2 = dpToPx(2); int dp3 = dpToPx(3); mXOri = (int) (dp2 + textYWdith + dp2 + xyLineWidth); //獲取x軸的最長文字的寬度所佔的矩形 xValueRect = getTextBounds(mXData.get(getListItemMaxIndex(mXData)), mXYTextPaint); //X軸文字高度 float textXHeight = xValueRect.height(); for (int i = 0; i < mXData.size(); i++) { Rect rect = getTextBounds(mXData.get(i) + "", mXYTextPaint); if (rect.height() > textXHeight) textXHeight = rect.height(); if (rect.width() > xValueRect.width()) xValueRect = rect; } mYOri = (int) (height - dp2 - textXHeight - dp3 - xyLineWidth); mXInit = mXOri + xValueRect.width() / 2 + dpToPx(5); minXInit = width - (width - mXOri) * 0.1f - interval * (mXData.size() - 1); maxXInit = mXInit; } selectIndex = getSelectIndexFromShowType(mShowPositionType); super.onLayout(changed, left, top, right, bottom); } @Override protected void onDraw(Canvas canvas) { canvas.drawColor(bgColor); drawXY(canvas); drawBrokenLineAndPoint(canvas); } /** * 繪製交點處對應的點 */ private void drawBrokenLineAndPoint(Canvas canvas) { if (mXData.size() <= 0) return; int layerId = canvas.saveLayer(0, 0, width, height, null, Canvas.ALL_SAVE_FLAG); drawBrokenLine(canvas); drawBrokenPoint(canvas); // 將超出x軸座標的部分截掉 mSpinnerLinePaint.setStyle(Paint.Style.FILL); mSpinnerLinePaint.setColor(bgColor); mSpinnerLinePaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR)); RectF rectF = new RectF(0, 0, mXOri, height); canvas.drawRect(rectF, mSpinnerLinePaint); mSpinnerLinePaint.setXfermode(null); canvas.restoreToCount(layerId); } /** * 繪製曲線對應的點 */ private void drawBrokenPoint(Canvas canvas) { float dp2 = dpToPx(2); float dp4 = dpToPx(4); float dp7 = dpToPx(7); Log.e("selectIndex", "index:" + selectIndex); //繪製節點 for (int i = 0; i < mXData.size(); i++) { float x = mXInit + interval * i; float y = mYOri - mYOri * (1 - 0.1f) * mSpinnerValue.get(mXData.get(i)) / mYData.get(mYData.size() - 1); //繪製選中點 if (i == selectIndex - 1) { mSpinnerLinePaint.setStyle(Paint.Style.FILL); //設定選中顏色 mSpinnerLinePaint.setColor(selectCircleColor); canvas.drawCircle(x, y, dp7, mSpinnerLinePaint); mSpinnerLinePaint.setColor(selectReminderColor); canvas.drawCircle(x, y, dp4, mSpinnerLinePaint); drawFloatTextBox(canvas, x, y - dp7, mSpinnerValue.get(mXData.get(i))); } //繪製普通節點 mSpinnerLinePaint.setStyle(Paint.Style.FILL); mSpinnerLinePaint.setColor(Color.WHITE); canvas.drawCircle(x, y, dp2, mSpinnerLinePaint); mSpinnerLinePaint.setStyle(Paint.Style.STROKE); mSpinnerLinePaint.setColor(lineColor); canvas.drawCircle(x, y, dp2, mSpinnerLinePaint); } } /** * 繪製浮動框 * */ private void drawFloatTextBox(Canvas canvas, float x, float y, int text) { int dp6 = dpToPx(6); int dp18 = dpToPx(18); //p1 Path path = new Path(); path.moveTo(x, y); //p2 path.lineTo(x - dp6, y - dp6); //p3 path.lineTo(x - dp18, y - dp6); //p4 path.lineTo(x - dp18, y - dp6 - dp18); //p5 path.lineTo(x + dp18, y - dp6 - dp18); //p6 path.lineTo(x + dp18, y - dp6); //p7 path.lineTo(x + dp6, y - dp6); //p1 path.lineTo(x, y); canvas.drawPath(path, mSpinnerLinePaint); mSpinnerLinePaint.setColor(Color.WHITE); mSpinnerLinePaint.setTextSize(spToPx(14)); Rect rect = getTextBounds(text + "", mSpinnerLinePaint); canvas.drawText(text + "", x - rect.width() / 2, y - dp6 - (dp18 - rect.height()) / 2, mSpinnerLinePaint); } /** * 繪製平滑曲線 */ private void drawBrokenLine(Canvas canvas) { mSpinnerLinePaint.setStyle(Paint.Style.STROKE); mSpinnerLinePaint.setColor(lineColor); //繪製折線 Path path = new Path(); float prePreviousPointX = Float.NaN; float prePreviousPointY = Float.NaN; float previousPointX = Float.NaN; float previousPointY = Float.NaN; float currentPointX = Float.NaN; float currentPointY = Float.NaN; float nextPointX; float nextPointY; int lineSize = mXData.size(); for (int i = 0; i < lineSize; i++) { float x; float y; if (Float.isNaN(currentPointX)) { currentPointX = getSpinnerPoint(i).x; currentPointY = getSpinnerPoint(i).y; } if (Float.isNaN(previousPointX)) { //是第一個點? if (i > 0) { previousPointX = getSpinnerPoint(i - 1).x; previousPointY = getSpinnerPoint(i - 1).y; } else { //用當前點表示上一個點 previousPointX = currentPointX; previousPointY = currentPointY; } } if (Float.isNaN(prePreviousPointX)) { //是前兩個點? if (i > 1) { prePreviousPointX = getSpinnerPoint(i - 2).x; prePreviousPointY = getSpinnerPoint(i - 2).y; } else { //當前點表示上上個點 prePreviousPointX = previousPointX; prePreviousPointY = previousPointY; } } // 判斷是不是最後一個點了 if (i < lineSize - 1) { nextPointX = getSpinnerPoint(i + 1).x; nextPointY = getSpinnerPoint(i + 1).y; } else { //用當前點表示下一個點 nextPointX = currentPointX; nextPointY = currentPointY; } if (i == 0) { // 將Path移動到開始點 path.moveTo(currentPointX, currentPointY); } else { // 求出控制點座標 final float firstDiffX = (currentPointX - prePreviousPointX); final float firstDiffY = (currentPointY - prePreviousPointY); final float secondDiffX = (nextPointX - previousPointX); final float secondDiffY = (nextPointY - previousPointY); final float firstControlPointX = previousPointX + (mLineSmoothness * firstDiffX); final float firstControlPointY = previousPointY + (mLineSmoothness * firstDiffY); final float secondControlPointX = currentPointX - (mLineSmoothness * secondDiffX); final float secondControlPointY = currentPointY - (mLineSmoothness * secondDiffY); //畫出曲線 path.cubicTo(firstControlPointX, firstControlPointY, secondControlPointX, secondControlPointY, currentPointX, currentPointY); } // 更新 prePreviousPointX = previousPointX; prePreviousPointY = previousPointY; previousPointX = currentPointX; previousPointY = currentPointY; currentPointX = nextPointX; currentPointY = nextPointY; } canvas.drawPath(path, mSpinnerLinePaint); } /** * 繪製XY座標 */ private void drawXY(Canvas canvas) { int length = dpToPx(5);//刻度的長度 //繪製Y座標 canvas.drawLine(mXOri - xyLineWidth / 2, 0, mXOri - xyLineWidth / 2, mYOri, mXYPaint); //繪製箭頭 mXYPaint.setStyle(Paint.Style.STROKE); Path path = new Path(); path.moveTo(mXOri - xyLineWidth / 2 - dpToPx(5), dpToPx(12)); path.lineTo(mXOri - xyLineWidth / 2, xyLineWidth / 2); path.lineTo(mXOri - xyLineWidth / 2 + dpToPx(5), dpToPx(12)); canvas.drawPath(path, mXYPaint); //繪製刻度 int yLength = (int) (mYOri * (1 - 0.1f) / (mYData.size() - 1));//y軸上面空出10%,計算出y軸刻度間距 for (int i = 0; i < mYData.size(); i++) { //繪製刻度 canvas.drawLine(mXOri, mYOri - yLength * i + xyLineWidth / 2, mXOri + length, mYOri - yLength * i + xyLineWidth / 2, mXYPaint); mXYTextPaint.setColor(xyTextColor); //繪製文字 String text = mYData.get(i) + ""; Rect rect = getTextBounds(text, mXYTextPaint); canvas.drawText(text, 0, text.length(), mXOri - xyLineWidth - dpToPx(2) - rect.width(), mYOri - yLength * i + rect.height() / 2, mXYTextPaint); } //繪製座標 canvas.drawLine(mXOri, mYOri + xyLineWidth / 2, width, mYOri + xyLineWidth / 2, mXYPaint); //繪製箭頭 mXYPaint.setStyle(Paint.Style.STROKE); path = new Path(); //整個長度 float xLength = mXInit + interval * (mXData.size() - 1) + (width - mXOri) * 0.1f; if (xLength < width) xLength = width; path.moveTo(xLength - dpToPx(12), mYOri + xyLineWidth / 2 - dpToPx(5)); path.lineTo(xLength - xyLineWidth / 2, mYOri + xyLineWidth / 2); path.lineTo(xLength - dpToPx(12), mYOri + xyLineWidth / 2 + dpToPx(5)); canvas.drawPath(path, mXYPaint); //繪製x軸刻度 for (int i = 0; i < mXData.size(); i++) { float x = mXInit + interval * i; if (x >= mXOri) {//只繪製從原點開始的區域 mXYTextPaint.setColor(xyTextColor); canvas.drawLine(x, mYOri, x, mYOri - length, mXYPaint); //繪製X軸文字 String text = mXData.get(i); Rect rect = getTextBounds(text, mXYTextPaint); if (i == selectIndex - 1) { mXYTextPaint.setColor(lineColor); canvas.drawText(text, 0, text.length(), x - rect.width() / 2, mYOri + xyLineWidth + dpToPx(2) + rect.height(), mXYTextPaint); canvas.drawRoundRect(x - xValueRect.width() / 2 - dpToPx(3), mYOri + xyLineWidth + dpToPx(1), x + xValueRect.width() / 2 + dpToPx(3), mYOri + xyLineWidth + dpToPx(2) + xValueRect.height() + dpToPx(2), dpToPx(2), dpToPx(2), mXYTextPaint); } else { canvas.drawText(text, 0, text.length(), x - rect.width() / 2, mYOri + xyLineWidth + dpToPx(2) + rect.height(), mXYTextPaint); } } } } private float startX; private float startx; @Override public boolean onTouchEvent(MotionEvent event) { if (isScrolling) return super.onTouchEvent(event); //當該view獲得點選事件,就請求父控制元件不攔截事件 this.getParent().requestDisallowInterceptTouchEvent(true); obtainVelocityTracker(event); switch (event.getAction()) { case MotionEvent.ACTION_DOWN: startX = event.getX(); startx = event.getX(); Log.e("XXXX", "down:" + startX + ""); break; case MotionEvent.ACTION_MOVE: //滑動距離小於等於8的時候任務為短距離滑動 //當前x軸的尺寸與設定的x軸間隔的距離之乘積大於 螢幕中的顯示佈局寬度與x軸七點之差時,開始移動 if (interval * mXData.size() > width - mXOri) { //獲取滑動的距離 float dis = event.getX() - startX; //重新賦值給startX startX = event.getX(); //當前x原點距離與左右滑動的距離之和沒有最小值大,則將當前x距離賦值為最小,以下相似 if (mXInit + dis < minXInit) { mXInit = minXInit; } else if (mXInit + dis > maxXInit) { mXInit = maxXInit; } else { mXInit = mXInit + dis; } invalidate(); } break; case MotionEvent.ACTION_UP: isShortSlide = Math.abs(event.getX() - startx) <= dpToPx(8); clickAction(event); scrollAfterActionUp(); this.getParent().requestDisallowInterceptTouchEvent(false); recycleVelocityTracker(); break; case MotionEvent.ACTION_CANCEL: //增加這行程式碼防止與父類別的滑動事件衝突 this.getParent().requestDisallowInterceptTouchEvent(false); recycleVelocityTracker(); break; } return true; } //是否正在滑動 private boolean isScrolling = false; /** * 手指擡起後的滑動處理 */ private void scrollAfterActionUp() { if (!isScroll) return; final float velocity = getVelocity(); float scrollLength = maxXInit - minXInit; if (Math.abs(velocity) < 10000) scrollLength = (maxXInit - minXInit) * Math.abs(velocity) / 10000; ValueAnimator animator = ValueAnimator.ofFloat(0, scrollLength); animator.setDuration((long) (scrollLength / (maxXInit - minXInit) * 1000));//時間最大為1000毫秒,此處使用比例進行換算 animator.setInterpolator(new DecelerateInterpolator()); animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator valueAnimator) { float value = (float) valueAnimator.getAnimatedValue(); if (velocity < 0 && mXInit > minXInit) {//向左滑動 if (mXInit - value <= minXInit) mXInit = minXInit; else mXInit = mXInit - value; } else if (velocity > 0 && mXInit < maxXInit) {//向右滑動 if (mXInit + value >= maxXInit) mXInit = maxXInit; else mXInit = mXInit + value; } invalidate(); } }); animator.addListener(new Animator.AnimatorListener() { @Override public void onAnimationStart(Animator animator) { isScrolling = true; } @Override public void onAnimationEnd(Animator animator) { isScrolling = false; } @Override public void onAnimationCancel(Animator animator) { isScrolling = false; } @Override public void onAnimationRepeat(Animator animator) { } }); animator.start(); } /** * 獲取速度 * * @return */ private float getVelocity() { if (mTracker != null) { mTracker.computeCurrentVelocity(1000); return mTracker.getXVelocity(); } return 0; } /** * 點選X軸座標或者折線節點 * */ // 44 142 139 private void clickAction(MotionEvent event) { int dp8 = dpToPx(8); float eventX = event.getX(); float eventY = event.getY(); if (!isShortSlide) { for (int i = 0; i < mXData.size(); i++) { float x = mXInit + interval * i; float start = mXOri; if (x >= start + (mSelectMiddle - 1) * interval && x < start + mSelectMiddle * interval) { selectIndex = i + 1; invalidate(); } } return; } for (int i = 0; i < mXData.size(); i++) { //節點 float x = mXInit + interval * i; float y = mYOri - mYOri * (1 - 0.1f) * mSpinnerValue.get(mXData.get(i)) / mYData.get(mYData.size() - 1); if (eventX >= x - dp8 && eventX <= x + dp8 && eventY >= y - dp8 && eventY <= y + dp8 && selectIndex != i + 1) {//每個節點周圍範圍內都是可點選區域 selectIndex = i + 1; invalidate(); return; } //X軸刻度 String text = mXData.get(i); Rect rect = getTextBounds(text, mXYTextPaint); x = mXInit + interval * i; y = mYOri + xyLineWidth + dpToPx(2); if (eventX >= x - rect.width() / 2 - dp8 && eventX <= x + rect.width() + dp8 / 2 && eventY >= y - dp8 && eventY <= y + rect.height() + dp8 && selectIndex != i + 1) { selectIndex = i + 1; invalidate(); return; } } } /** * 獲取速度跟蹤器 * * @param event */ private void obtainVelocityTracker(MotionEvent event) { if (!isScroll) return; if (mTracker == null) { mTracker = VelocityTracker.obtain(); } mTracker.addMovement(event); } /** * 回收速度跟蹤器 */ private void recycleVelocityTracker() { if (mTracker != null) { mTracker.recycle(); mTracker = null; } } /** * 根據使用者輸入顯示型別,在滑動時在不同的位置顯示提示框 */ private int getSelectIndexFromShowType(int showPositionType) { int visibleScale = (width - mXOri) / interval; switch (showPositionType) { case FIRST: mSelectMiddle = 1; return mSelectMiddle; case MIDDLE: if (mXData.size() <= visibleScale) { mSelectMiddle = middleIndex(mXData.size()); } else { mSelectMiddle = middleIndex(visibleScale); } return mSelectMiddle; //螢幕可顯示的刻度 case END: if (mXData.size() <= visibleScale) { mSelectMiddle = mXData.size(); } else { mSelectMiddle = visibleScale; } return visibleScale; default: mSelectMiddle = 0; return mSelectMiddle; } } public void setValue(Map<String, Integer> value) { this.mSpinnerValue = value; invalidate(); } public void setValue(Map<String, Integer> value, List<String> xValue, List<Integer> yValue) { this.mSpinnerValue = value; this.mXData = xValue; this.mYData = yValue; invalidate(); } public Map<String, Integer> getValue() { return mSpinnerValue; } /** * 獲取丈量文字的矩形 * * @param text * @param paint * @return */ private Rect getTextBounds(String text, Paint paint) { Rect rect = new Rect(); paint.getTextBounds(text, 0, text.length(), rect); return rect; } /** * dp轉化成為px * * @param dp * @return */ private int dpToPx(int dp) { float density = getContext().getResources().getDisplayMetrics().density; return (int) (dp * density + 0.5f * (dp >= 0 ? 1 : -1)); } /** * sp轉化為px * * @param sp * @return */ private int spToPx(int sp) { float scaledDensity = getContext().getResources().getDisplayMetrics().scaledDensity; return (int) (scaledDensity * sp + 0.5f * (sp >= 0 ? 1 : -1)); } /** * 獲取集合中最長的index */ private static final int NULL_INDEX = -1; public int getListItemMaxIndex(List<?> data) { if (data == null || data.size() < 1) { return NULL_INDEX; } int max = (data.get(0) + "").length(); for (int i = 0; i < data.size(); i++) { String s = data.get(i) + ""; if (s.length() > max) { return i; } } return NULL_INDEX; } //獲得在滑動結束的時候在螢幕內的點 private int middleIndex(int size) { if (size % 2 == 0) { return size / 2; } else { return size / 2 + 1; } } /** * 根據兩點座標獲取中間某個點 * * @param from 座標1 * @param to 座標2 */ //獲取已知點的斜率 y = kx+b private float getSlope(Point from, Point to) { float k = (to.y - from.y) / (to.x - from.x); Log.e("Point", "引數b:" + k); return k; } //獲取引數 b private float getParams(Point from, Point to) { float b = from.y - (getSlope(from, to) * from.x); Log.e("Point", "引數b:" + b); return b; } //根據兩點間的座標獲取x軸的任意一個座標x值, private float getArbitrarilyX(Point from, Point to, int grade, int needGrade) { //獲得輸入的新座標 float x = ((to.x - from.x) * needGrade) / grade + from.x; Log.e("Point", "x座標值:" + x); return x; } //獲取座標值 private Point getPoint(Point from, Point to, int grade, int needGrade) { Point point = new Point(); point.setX(getArbitrarilyX(from, to, grade, needGrade)); float slope = getSlope(from, to); point.setY(slope * point.x + getParams(from, to)); return point; } //獲取繪製折線的點 private Point getSpinnerPoint(int valueIndex) { float x = mXInit + interval * (valueIndex); float y = mYOri - mYOri * (1 - 0.1f) * mSpinnerValue.get(mXData.get(valueIndex)) / mYData.get(mYData.size() - 1); return new Point(x, y); } private class Point { float x; float y; public Point() { } public float getX() { return x; } public void setX(float x) { this.x = x; } public float getY() { return y; } public void setY(float y) { this.y = y; } public Point(float x, float y) { this.x = x; this.y = y; } @Override public String toString() { return "Point{" + "x=" + x + ", y=" + y + '}'; } } }
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支援it145.com。
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45