package com.demo.navtogether; import android.animation.ValueAnimator; import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.Path; import android.graphics.PathMeasure; import android.graphics.Point; import android.graphics.RectF; import android.util.AttributeSet; import android.util.DisplayMetrics; import android.util.Log; import android.util.TypedValue; import android.view.View; import android.view.animation.DecelerateInterpolator; import android.view.animation.LinearInterpolator; import com.demo.navtogether.utils.PathPlan; import com.demo.navtogether.utils.TriangleUtils; import java.text.DecimalFormat; import java.util.ArrayList; import androidx.annotation.Nullable; /** * My father is Object, ites purpose of * * @purpose Created by Runt (qingingrunt2010@qq.com) on 2020-12-23. */ public class PlanPathView extends View { //定义画笔 private Paint mPaint = new Paint(),mCirclePaint = new Paint(),mTextPaint = new Paint(); private RectF mRectF; // 绘制区域 ArrayList points = new ArrayList<>(); ArrayList lines = new ArrayList<>(); public PlanPathView(Context context) { super(context); init(); } public PlanPathView(Context context, @Nullable AttributeSet attrs) { super(context, attrs); init(); } public PlanPathView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(); } public PlanPathView(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); init(); } private void init(){ mPaint.setColor(Color.BLUE); // 初始化画笔 mPaint.setStyle(Paint.Style.FILL); // 填充 //mProgPaint.setStrokeCap(Paint.Cap.ROUND); // 设置圆角 mPaint.setAntiAlias(true); // 设置抗锯齿 mPaint.setDither(true); // 设置抖动 mPaint.setStrokeWidth(5); mPaint.setColor(Color.BLUE); // 初始化圆环画笔 mCirclePaint.setStyle(Paint.Style.FILL); // 填充 //mProgPaint.setStrokeCap(Paint.Cap.ROUND); // 设置圆角 mCirclePaint.setAntiAlias(true); // 设置抗锯齿 mCirclePaint.setDither(true); // 设置抖动 mCirclePaint.setColor(Color.GREEN); mCirclePaint.setStrokeWidth(10); mTextPaint = new Paint(); mTextPaint.setAntiAlias(true); // 是否抗锯齿 //mTextPaint.setAlpha(50); // 设置alpha不透明度,范围为0~255 mTextPaint.setColor(Color.BLACK); DisplayMetrics displayMetrics = getResources().getDisplayMetrics(); mTextPaint.setTextSize(15 * displayMetrics.scaledDensity); // 设置画笔属性 mTextPaint.setStyle(Paint.Style.FILL);//画笔属性是实心圆 // paint.setStyle(Paint.Style.STROKE);//画笔属性是空心圆 mTextPaint.setStrokeWidth(4);//设置画笔粗细 } /** * 重写draw方法 * @param canvas */ @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); DecimalFormat df = new DecimalFormat("#.00"); double totalLength = 0 ; mTextPaint.setColor(Color.RED); for(int i = 0 ; i < lines.size() ; i ++ ) { if(i == lines.size() -1 && progress>0){ int chaX = lines.get(i).end.x- lines.get(i).start.x; int chaY = lines.get(i).end.y- lines.get(i).start.y; canvas.drawLine(lines.get(i).start.x, lines.get(i).start.y, (float) (lines.get(i).end.x-(chaX*(1-progress))), (float) (lines.get(i).end.y-(chaY*(1-progress))), mPaint);// drawRect 绘制矩形 }else { canvas.drawLine(lines.get(i).start.x, lines.get(i).start.y, lines.get(i).end.x, lines.get(i).end.y, mPaint);// drawRect 绘制矩形 } boolean left = lines.get(i).start.x>lines.get(i).end.x,//左偏移 top = lines.get(i).start.y>lines.get(i).end.y;//向上偏移 totalLength +=Double.parseDouble(df.format(lines.get(i).distance)); int textWidth = getTextWidth(mTextPaint, df.format(lines.get(i).distance)); int chaLeft = (lines.get(i).start.x - lines.get(i).end.x)/2 ; int chaTop = (lines.get(i).start.y - lines.get(i).end.y)/2 ; //文本位置 float x = lines.get(i).start.x - chaLeft - textWidth/2,y = lines.get(i).start.y- chaTop; canvas.drawText( df.format(lines.get(i).distance),x,y, mTextPaint); if(i == lines.size() -1){ String totalText = "总路线长度:"+df.format(totalLength); textWidth = getTextWidth(mTextPaint, totalText); canvas.drawText( totalText, getWidth()/2-(textWidth/2), getHeight() - (mTextPaint.descent()- mTextPaint.ascent() + getResources().getDisplayMetrics().density*5), mTextPaint); } } mTextPaint.setColor(Color.BLACK); for(int i = 0 ; i < points.size() ; i ++ ) { PathPlan.Place place = points.get(i); int textWidth = getTextWidth(mTextPaint, place.name); if(i == points.size() -1 && progress>0 && lines.size() == 0){ canvas.drawCircle(place.point.x, place.point.y, (float) (10*progress), mCirclePaint); }else{ canvas.drawCircle(place.point.x, place.point.y, (float) (10), mCirclePaint); } canvas.drawText(place.name, place.point.x-(textWidth/2), place.point.y -(mTextPaint.descent() + getResources().getDisplayMetrics().density*5), mTextPaint); } } //第二个参数是一个数组.传进去个长度跟字符串长度相同的float数组,方法调用后,里边塞的是每个字符的长度. public int getTextWidth(Paint paint, String str) { int iRet = 0; if (str != null && str.length() > 0) { int len = str.length(); float[] widths = new float[len]; paint.getTextWidths(str, widths); for (int j = 0; j < len; j++) { iRet += (int) Math.ceil(widths[j]); } } return iRet; } /** * 重写onMeasure方法 * * @param widthMeasureSpec * @param heightMeasureSpec */ @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); } public ArrayList getPoints() { return points; } /** * 设置位置 * @param points */ public void setPoints(ArrayList points) { this.points = points; invalidate(); } public void addPoint(PathPlan.Place point){ points.add(point); invalidate(); } int animTime = 500; double progress = 0 ; /** * 动画显示位置 * @param places */ public void setAnimPoints(ArrayList places ) { setAnimPoints(places,null); } public void setAnimPoints(ArrayList places ,AnimatorListener listener){ int time = places.size()*animTime; Log.i("view"," animTime:"+(time)); ValueAnimator animator = ValueAnimator.ofInt(time); animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { int value = (int)animation.getAnimatedValue(); if(listener != null){ if(valuei){ points.add(places.get(i)); } invalidate(); } }); animator.setInterpolator(new LinearInterpolator()); animator.setDuration(time);//耗时 animator.start(); } interface AnimatorListener{ void onAnimation(int value); void onFinish(); } public void drawLine(ArrayList lines){ this.lines = lines; invalidate(); } public void drawAnimLine(ArrayList tempLines,AnimatorListener listener){ // 0 - getLength() int time = tempLines.size()*animTime; ValueAnimator valueAnimator = ValueAnimator.ofInt(time); valueAnimator.setDuration(time); // 减速插值器 valueAnimator.setInterpolator(new DecelerateInterpolator()); valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { int value = (int)animation.getAnimatedValue(); if(listener != null){ if(valuei){ lines.add(tempLines.get(i)); } invalidate(); } }); valueAnimator.start(); } public static class Line{ public Point start,end; public double distance; public Line(Point start, Point end, double distance) { this.start = start; this.end = end; this.distance = distance; } } public void clearLines(){ lines.clear(); progress = 0 ; clearAnimation(); invalidate(); } public void clear(){ points.clear(); lines.clear(); progress = 0 ; clearAnimation(); invalidate(); } }