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<PathPlan.Place> points = new ArrayList<>();
|
ArrayList<Line> 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<PathPlan.Place> getPoints() {
|
return points;
|
}
|
|
/**
|
* 设置位置
|
* @param points
|
*/
|
public void setPoints(ArrayList<PathPlan.Place> 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<PathPlan.Place> places ) {
|
setAnimPoints(places,null);
|
}
|
public void setAnimPoints(ArrayList<PathPlan.Place> 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(value<time){
|
listener.onAnimation(value);
|
}else{
|
listener.onFinish();
|
}
|
}
|
int i = value / animTime;
|
progress = value % animTime*1.0 /animTime;
|
if(points.size()<i+1 && places.size()>i){
|
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<Line> lines){
|
this.lines = lines;
|
invalidate();
|
}
|
|
public void drawAnimLine(ArrayList<Line> 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(value<time){
|
listener.onAnimation(value);
|
}else{
|
listener.onFinish();
|
}
|
}
|
int i = value / animTime;
|
progress = value % animTime*1.0 /animTime;
|
Log.i("view","i:"+i+" size:"+points.size()+" animate:"+animation.getAnimatedValue()+" progress:"+progress);
|
if(lines.size()<i+1 && tempLines.size()>i){
|
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();
|
}
|
}
|