所謂動(dòng)態(tài)折線圖,就是折線圖能隨著手指的滑動(dòng)進(jìn)行動(dòng)態(tài)繪制,這里很定會(huì)產(chǎn)生動(dòng)畫(huà)效果。基于這個(gè)效果,這里使用SurfaceView進(jìn)行制圖。
創(chuàng)新互聯(lián)專(zhuān)注于企業(yè)網(wǎng)絡(luò)營(yíng)銷(xiāo)推廣、網(wǎng)站重做改版、渭源網(wǎng)站定制設(shè)計(jì)、自適應(yīng)品牌網(wǎng)站建設(shè)、H5場(chǎng)景定制、商城網(wǎng)站建設(shè)、集團(tuán)公司官網(wǎng)建設(shè)、外貿(mào)網(wǎng)站建設(shè)、高端網(wǎng)站制作、響應(yīng)式網(wǎng)頁(yè)設(shè)計(jì)等建站業(yè)務(wù),價(jià)格優(yōu)惠性?xún)r(jià)比高,為渭源等各大城市提供網(wǎng)站開(kāi)發(fā)制作服務(wù)。
實(shí)現(xiàn)步奏如下:
(1): 這里新建一個(gè)繪圖ChartView,繼承SurfaceView并實(shí)現(xiàn)SurfaceHolder.Callback , Runnable接口,主要繪圖工作在子線程中完成。
(2):現(xiàn)實(shí) SurfaceHolder.Callback接口的三個(gè)方法,并在 surfaceCreated中開(kāi)啟子線程進(jìn)行繪圖。
(3):重寫(xiě)onTouchEvent方法,在Move事件中,根據(jù)手指的滑動(dòng)距離計(jì)算偏移量,具體實(shí)現(xiàn)請(qǐng)看代碼。
(4): 這里的折線圖的坐標(biāo)值是隨意添加的,可以在實(shí)際項(xiàng)目中根據(jù)需求自己添加。
(5):此例中有大量從集合中添加和刪除元素,建議使用LinkedList來(lái)進(jìn)行保存數(shù)據(jù)。
自定義ChartView:
public class ChartView extends SurfaceView implements SurfaceHolder.Callback , Runnable { private Context mContext; private Paint mPaint; private Resources res; private DisplayMetrics dm; private int canvasHeight; private int canvasWidth; private int bHeight = 0; private int bWidth; private boolean isMeasure = true; private boolean canScrollRight = true; private boolean canScrollLeft = true; //y軸最大值 private int maxValue; //y軸間隔值 private int averageValue; private int marginTop = 20; private int marginBottom = 80; //曲線上的總點(diǎn)數(shù) private Point[] mPoints; //縱坐標(biāo)值 private LinkedList<Double> yRawData; //橫坐標(biāo)值 private LinkedList<String> xRawData; //根據(jù)間隔計(jì)算出的每個(gè)X的值 private LinkedList<Integer> xList = new LinkedList<>(); private LinkedList<String> xPreData = new LinkedList<>(); private LinkedList<Double> yPreData = new LinkedList<>(); private LinkedList<String> xLastData = new LinkedList<>(); private LinkedList<Double> yLastData = new LinkedList<>(); private int spacingHeight; private SurfaceHolder holder; private boolean isRunning = true; private int lastX; private int offSet; private Rect mRect; private int xAverageValue = 0; public ChartView(Context context) { this(context , null); } public ChartView(Context context , AttributeSet attrs) { super(context, attrs); this.mContext = context; initView(); } private void initView() { this.res = mContext.getResources(); this.mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); dm = new DisplayMetrics(); WindowManager wm = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE); wm.getDefaultDisplay().getMetrics(dm); xPreData.add("05-18"); xPreData.add("05-17"); xPreData.add("05-16"); xPreData.add("05-15"); xPreData.add("05-14"); xPreData.add("05-13"); yPreData.add(4.53); yPreData.add(3.45); yPreData.add(6.78); yPreData.add(5.21); yPreData.add(2.34); yPreData.add(6.32); xLastData.add("05-26"); xLastData.add("05-27"); xLastData.add("05-28"); xLastData.add("05-29"); xLastData.add("05-30"); xLastData.add("05-31"); yLastData.add(2.35); yLastData.add(5.43); yLastData.add(6.23); yLastData.add(7.33); yLastData.add(3.45); yLastData.add(2.45); holder = this.getHolder(); holder.addCallback(this); } @Override protected void onSizeChanged(int w , int h , int oldW , int oldH) { if (isMeasure) { this.canvasHeight = getHeight(); this.canvasWidth = getWidth(); if (bHeight == 0) { bHeight = canvasHeight - marginBottom; } bWidth = dip2px(30); xAverageValue = (canvasWidth - bWidth) / 7; isMeasure = false; } } @Override public void run() { while (isRunning) { drawView(); try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } } } private void drawView() { Canvas canvas = holder.lockCanvas(); canvas.drawColor(Color.WHITE); mPaint.setColor(res.getColor(R.color.color_f2f2f2)); drawAllXLine(canvas); mRect = new Rect(bWidth - 3, marginTop - 5 , bWidth + (canvasWidth - bWidth) / yRawData.size() * (yRawData.size() - 1) + 3, bHeight + marginTop + marginBottom); //鎖定畫(huà)圖區(qū)域 canvas.clipRect(mRect); drawAllYLine(canvas); mPoints = getPoints(); mPaint.setColor(res.getColor(R.color.color_ff4631)); mPaint.setStrokeWidth(dip2px(2.5f)); mPaint.setStyle(Paint.Style.STROKE); drawLine(canvas); mPaint.setStyle(Paint.Style.FILL); for (int i = 0 ; i < mPoints.length ; i++) { canvas.drawCircle(mPoints[i].x , mPoints[i].y , 5 , mPaint); } holder.unlockCanvasAndPost(canvas); } //繪制折線圖 private void drawLine(Canvas canvas) { Point startP = null; Point endP = null; for (int i = 0 ; i < mPoints.length - 1; i++) { startP = mPoints[i]; endP = mPoints[i + 1]; canvas.drawLine(startP.x , startP.y , endP.x , endP.y , mPaint); } } //繪制所有的縱向分割線 private void drawAllYLine(Canvas canvas) { for (int i = 0 ; i < yRawData.size() ; i++) { if (i == 0) { canvas.drawLine(bWidth, marginTop , bWidth, bHeight + marginTop , mPaint); } if (i == yRawData.size() - 1) { canvas.drawLine(bWidth + xAverageValue * i, marginTop , bWidth + xAverageValue * i , bHeight + marginTop , mPaint); } xList.add(bWidth + xAverageValue * i); canvas.drawLine(bWidth + xAverageValue * i + offSet, marginTop , bWidth + xAverageValue * i + offSet , bHeight + marginTop , mPaint); drawText(xRawData.get(i) , bWidth + xAverageValue * i - 30 + offSet, bHeight + dip2px(26) , canvas); } } //繪制所有的橫向分割線 private void drawAllXLine(Canvas canvas) { for (int i = 0 ; i < spacingHeight + 1 ; i++) { canvas.drawLine(bWidth , bHeight - (bHeight / spacingHeight) * i + marginTop , bWidth + xAverageValue * (yRawData.size() - 1) , bHeight - (bHeight / spacingHeight) * i + marginTop , mPaint); drawText(String.valueOf(averageValue * i) , bWidth / 2 , bHeight - (bHeight / spacingHeight) * i + marginTop, canvas); } } //繪制坐標(biāo)值 private void drawText(String text , int x , int y , Canvas canvas) { Paint p = new Paint(Paint.ANTI_ALIAS_FLAG); p.setTextSize(dip2px(12)); p.setColor(res.getColor(R.color.color_999999)); p.setTextAlign(Paint.Align.LEFT); canvas.drawText(text , x , y , p); } @Override public void surfaceCreated(SurfaceHolder surfaceHolder) { new Thread(this).start(); Log.d("OOK" , "Created"); } @Override public void surfaceChanged(SurfaceHolder surfaceHolder, int i, int i1, int i2) { Log.d("OOK" , "Changed"); } @Override public void surfaceDestroyed(SurfaceHolder surfaceHolder) { isRunning = false; try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } } @Override public boolean onTouchEvent(MotionEvent event) { int action = event.getAction(); int rawX = (int) event.getX(); switch (action) { case MotionEvent.ACTION_DOWN: lastX = rawX; break; case MotionEvent.ACTION_MOVE: int offsetX = rawX - lastX; if (xPreData.size() == 0 && offSet > 0) { offSet = 0; canScrollRight = false; } if (xLastData.size() == 0 && offSet < 0) { offSet = 0; canScrollLeft = false; } offSet = offSet + offsetX; if (offSet > xAverageValue && canScrollRight) { offSet = offSet % xAverageValue; xRawData.addFirst(xPreData.pollFirst()); yRawData.addFirst(yPreData.pollFirst()); xLastData.addFirst(xRawData.removeLast()); yLastData.addFirst(yRawData.removeLast()); canScrollLeft = true; } if (offSet < -xAverageValue && canScrollLeft) { offSet = offSet % xAverageValue; xRawData.addLast(xLastData.pollFirst()); yRawData.addLast(yLastData.pollFirst()); xPreData.addFirst(xRawData.removeFirst()); yPreData.addFirst(yRawData.removeFirst()); canScrollRight = true; } lastX = rawX; break; case MotionEvent.ACTION_UP: break; } return true; } private Point[] getPoints() { Point[] points = new Point[yRawData.size()]; for (int i = 0 ; i < yRawData.size() ; i++) { int ph = bHeight - (int)(bHeight * (yRawData.get(i) / maxValue)); points[i] = new Point(xList.get(i) + offSet , ph + marginTop); } return points; } public void setData(LinkedList<Double> yRawData , LinkedList<String> xRawData , int maxValue , int averageValue) { this.maxValue = maxValue; this.averageValue = averageValue; this.mPoints = new Point[yRawData.size()]; this.yRawData = yRawData; this.xRawData = xRawData; this.spacingHeight = maxValue / averageValue; } private int dip2px(float dpValue) { return (int) (dpValue * dm.density + 0.5f); } }
MainActivity代碼:
public class MainActivity extends Activity { LinkedList<Double> yList; LinkedList<String> xRawData; ChartView chartView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main_activity); chartView = (ChartView) findViewById(R.id.chartView); yList = new LinkedList<>(); yList.add(2.203); yList.add(4.05); yList.add(6.60); yList.add(3.08); yList.add(4.32); yList.add(2.0); yList.add(5.0); xRawData = new LinkedList<>(); xRawData.add("05-19"); xRawData.add("05-20"); xRawData.add("05-21"); xRawData.add("05-22"); xRawData.add("05-23"); xRawData.add("05-24"); xRawData.add("05-25"); chartView.setData(yList , xRawData , 8 , 2); } }
此例頁(yè)面布局比較簡(jiǎn)單,就是在主頁(yè)面布局中添加一個(gè)自定義的ChartView即可,這里不再貼出??赡軐?xiě)得有點(diǎn)倉(cāng)促,如果不妥之處,請(qǐng)大家批評(píng)指正,謝謝!
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持創(chuàng)新互聯(lián)。
網(wǎng)站名稱(chēng):Android繪制動(dòng)態(tài)折線圖
標(biāo)題URL:http://aaarwkj.com/article34/phohpe.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供外貿(mào)網(wǎng)站建設(shè)、網(wǎng)站建設(shè)、服務(wù)器托管、響應(yīng)式網(wǎng)站、標(biāo)簽優(yōu)化、App開(kāi)發(fā)
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶(hù)投稿、用戶(hù)轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話(huà):028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)