package cn.androidy.thinking.views; import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.Path; import android.util.AttributeSet; import android.util.DisplayMetrics; import android.view.SurfaceHolder; import android.view.SurfaceView; import java.util.ArrayList; import java.util.List; import java.util.Random; import cn.androidy.thinking.charting.ChartingUtils; import cn.androidy.thinking.charting.data.Entry; import cn.androidy.thinking.charting.data.EntryScreen; public class ProgressCylinderView extends SurfaceView implements SurfaceHolder.Callback, Runnable { List<Entry> entries = new ArrayList<>(); /** * main paint object used for rendering */ protected Paint mRenderPaint; protected Path cubicPath = new Path(); protected Path cubicFillPath = new Path(); protected int xIndexWidth; protected DisplayMetrics dm; protected float mRange; protected float maxVal; protected float minVal; float scale = 1; int j = 0; /** * 与SurfaceHolder绑定的Canvas */ private Canvas mCanvas; private SurfaceHolder mHolder; Random random = new Random(); /** * 线程的控制开关 */ private boolean isRunning; private int progress; Thread t; public void setProgress(int progress) { this.progress = progress; } public int getProgress() { return progress; } public ProgressCylinderView(Context context) { this(context, null); } public ProgressCylinderView(Context context, AttributeSet attrs) { super(context, attrs); dm = getResources().getDisplayMetrics(); mHolder = getHolder(); mHolder.addCallback(this); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); for (int i = 0; i < entries.size(); i++) { entries.get(i).setEntryScreen(new EntryScreen(maxVal, minVal, getTop(), getBottom())); } scale = 10 / mRange; } private float getPhaseY() { return progress * 1.0f / 100; } private void draw() { // 获得canvas mCanvas = mHolder.lockCanvas(); if (mCanvas != null) { mCanvas.drawColor(Color.WHITE); int minx = 0; int maxx = entries.size(); float intensity = 0.2f; float phaseY = getPhaseY(); cubicPath.reset(); float h = getHeight(); int size = (int) Math.ceil((maxx - minx) + minx); if (size - minx >= 2) { float prevDx = 0f; float prevDy = 0f; float curDx = 0f; float curDy = 0f; Entry prevPrev = entries.get(minx); Entry prev = entries.get(minx); Entry cur = entries.get(minx); Entry next = entries.get(minx + 1); // let the spline start cubicPath.moveTo(cur.getXIndex(), cur.findYCoordinate(phaseY, scale, -h / 2)); prevDx = (cur.getXIndex() - prev.getXIndex()) * intensity; prevDy = (cur.findYCoordinate(phaseY, scale, -h / 2) - prev.findYCoordinate(phaseY, scale, -h / 2)) * intensity; curDx = (next.getXIndex() - cur.getXIndex()) * intensity; curDy = (next.findYCoordinate(phaseY, scale, -h / 2) - cur.findYCoordinate(phaseY, scale, -h / 2)) * intensity; // the first cubic cubicPath.cubicTo(xIndexWidth * (prev.getXIndex() + prevDx), (prev.findYCoordinate(phaseY, scale, -h / 2) + prevDy), xIndexWidth * (cur.getXIndex() - curDx), (-curDy), cur.getXIndex() * xIndexWidth, cur.findYCoordinate(phaseY, scale, -h / 2)); for (int j = minx + 1, count = Math.min(size, entries.size() - 1); j < count; j++) { prevPrev = entries.get(j == 1 ? 0 : j - 2); prev = entries.get(j - 1); cur = entries.get(j); next = entries.get(j + 1); prevDx = (cur.getXIndex() - prevPrev.getXIndex()) * intensity; prevDy = (cur.findYCoordinate(phaseY, scale, -h / 2) - prevPrev.findYCoordinate(phaseY, scale, -h / 2)) * intensity; curDx = (next.getXIndex() - prev.getXIndex()) * intensity; curDy = (next.findYCoordinate(phaseY, scale, -h / 2) - prev.findYCoordinate(phaseY, scale, -h / 2)) * intensity; cubicPath.cubicTo(xIndexWidth * (prev.getXIndex() + prevDx), (prev.findYCoordinate(phaseY, scale, -h / 2) + prevDy), xIndexWidth * (cur.getXIndex() - curDx), (cur.findYCoordinate(phaseY, scale, -h / 2) - curDy), cur.getXIndex() * xIndexWidth, cur.findYCoordinate(phaseY, scale, -h / 2)); } if (size > entries.size() - 1) { prevPrev = entries.get((entries.size() >= 3) ? entries.size() - 3 : entries.size() - 2); prev = entries.get(entries.size() - 2); cur = entries.get(entries.size() - 1); next = cur; prevDx = (cur.getXIndex() - prevPrev.getXIndex()) * intensity; prevDy = (cur.findYCoordinate(phaseY, scale, -h / 2) - prevPrev.findYCoordinate(phaseY, scale, -h / 2)) * intensity; curDx = (next.getXIndex() - prev.getXIndex()) * intensity; curDy = (next.findYCoordinate(phaseY, scale, -h / 2) - prev.findYCoordinate(phaseY, scale, -h / 2)) * intensity; // the last cubic cubicPath.cubicTo(xIndexWidth * (prev.getXIndex() + prevDx), (prev.findYCoordinate(phaseY, scale, -h / 2) + prevDy), xIndexWidth * (cur.getXIndex() - curDx), (cur.findYCoordinate(phaseY, scale, -h / 2) - curDy), cur.getXIndex() * xIndexWidth, cur.findYCoordinate(phaseY, scale, -h / 2)); } } cubicFillPath.reset(); cubicFillPath.addPath(cubicPath); // create a new path, this is bad for performance drawCubicFill(mCanvas, cubicFillPath, 0, size); mRenderPaint.setColor(0xffed145b); mRenderPaint.setStyle(Paint.Style.STROKE); mCanvas.drawPath(cubicPath, mRenderPaint); mRenderPaint.setPathEffect(null); mHolder.unlockCanvasAndPost(mCanvas); } } protected void drawCubicFill(Canvas canvas, Path spline, int from, int to) { spline.lineTo((to - 1) * xIndexWidth, getHeight()); spline.lineTo(from * xIndexWidth, getHeight()); spline.close(); mRenderPaint.setStyle(Paint.Style.FILL); mRenderPaint.setColor(Color.BLUE); // filled is drawn with less alpha mRenderPaint.setAlpha(80); canvas.drawPath(spline, mRenderPaint); mRenderPaint.setAlpha(255); } @Override public void surfaceCreated(SurfaceHolder holder) { mRenderPaint = new Paint(Paint.ANTI_ALIAS_FLAG); mRenderPaint.setStyle(Paint.Style.FILL); mRenderPaint.setStrokeWidth(3); for (int i = 0; i < 5; i++) { entries.add(new Entry(1 + random.nextInt(9) * 0.1f, i)); } maxVal = ChartingUtils.getMaxVal(entries); minVal = ChartingUtils.getMinVal(entries); mRange = maxVal - minVal; xIndexWidth = dm.widthPixels / (entries.size() - 1); // 开启线程 isRunning = true; t = new Thread(this); t.start(); } @Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { } @Override public void surfaceDestroyed(SurfaceHolder holder) { // 通知关闭线程 isRunning = false; } @Override public void run() { while (isRunning) { for (int i = 0, count = entries.size(); i < count; i++) { Entry e = entries.get(i); float newVal = (float) (1.0 * Math.sin(j++)); e.setVal(newVal); } long start = System.currentTimeMillis(); draw(); long end = System.currentTimeMillis(); try { if (end - start < 150) { Thread.sleep(150 - (end - start)); } } catch (InterruptedException e) { e.printStackTrace(); } } } }