最近项目用到地图绘制效果,可以选中相应的区域进行判读点位是否在制定区域内,先看效果。




下面我们先看一下最主要的类,自定义类PathView:
package com.example.lenovo.enclosure;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Point;
import android.graphics.RectF;
import android.graphics.Region;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
/**
* 路径绘制
* Created by kaidaye on 2017/4/19.
*/
public class PathView extends View {
/**
* 线条颜色值
*/
private int paintColor = 0xff4598e5;
/**
* 第二条线颜色值
*/
private int paintTransparentColor = 0x154598e5;
/**
* 线条宽度
*/
private float strokeWidth = 15.0f;
/**
* 第二条线宽度
*/
private float xustrokeWidth = 200.0f;
/**
* 透明度
*/
private int alpha = 80;
/**
* 闭合X坐标距
*/
private int closeX = 300;
/**
* 闭合Y坐标距
*/
private int closeY = 300;
/**
* 是否是闭合只需要闭合状态
*/
private Boolean isClose = false;
/**
* 当前闭合状态,true表示闭合,false 表示未闭合
*/
private Boolean isStatus = false;
private Paint mPaint = new Paint();
private Paint transparentPaint = new Paint();
private Path pathCircle = new Path();
private Path mPath = new Path();
private Path transparentPath = new Path();
private Region region = new Region();
private float pathX;
private float pathY;
private float startX;
private float startY;
private Boolean isDrwable = false;
private Boolean isActionUp = false;
private OnFinishListener listener;
public PathView(Context context) {
super(context);
init();
}
public PathView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
private void init() {
//设置画笔颜色
mPaint.setColor(paintColor);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeWidth(strokeWidth);
transparentPaint.setColor(paintTransparentColor);
transparentPaint.setStyle(Paint.Style.STROKE);
transparentPaint.setStrokeCap(Paint.Cap.ROUND);
transparentPaint.setStrokeWidth(xustrokeWidth);
transparentPaint.setAlpha(alpha);
}
@Override
protected void onDraw(Canvas canvas) {
canvas.drawPath(mPath, mPaint);
if (isDrwable) {
canvas.drawPath(transparentPath, transparentPaint);
}
}
@Override
public boolean onTouchEvent(MotionEvent event) {
if (isActionUp) {
isActionUp = false;
mPaint.setStyle(Paint.Style.STROKE);
return true;
}
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
touchDown(event);
break;
case MotionEvent.ACTION_MOVE:
touchMove(event);
break;
case MotionEvent.ACTION_UP:
if (isClose) {//只需要闭合状态
mPath.close();//路径闭合方法,如果起点和结束点没有关闭调用此方法会直接将起点和结束的连线
transparentPath.close();
transparentPaint.setStyle(Paint.Style.FILL);
transparentPaint.setStrokeWidth(strokeWidth);
isStatus = true;
RectF r = new RectF();
mPath.computeBounds(r, true);
//设置区域路径和剪辑描述的区域
region.setPath(mPath, new Region((int) r.left, (int) r.top, (int) r.right, (int) r.bottom));
} else {//闭合与非闭合两种状态
if (Math.abs(startX - event.getX()) <= closeX && Math.abs(startY - event.getY()) <= closeY) {//距离较近可以闭合
mPath.close();//路径闭合方法,如果起点和结束点没有关闭调用此方法会直接将起点和结束的连线
transparentPath.close();
transparentPaint.setStyle(Paint.Style.FILL);
transparentPaint.setStrokeWidth(strokeWidth);
isStatus = true;
RectF r = new RectF();
mPath.computeBounds(r, true);
//设置区域路径和剪辑描述的区域
region.setPath(mPath, new Region((int) r.left, (int) r.top, (int) r.right, (int) r.bottom));
} else {
RectF rCircle = new RectF();
pathCircle.computeBounds(rCircle, true);
region.setPath(pathCircle, new Region((int) rCircle.left, (int) rCircle.top, (int) rCircle.right, (int) rCircle.bottom));
isStatus = false;
}
}
isDrwable = true;
if (listener != null)
listener.onFinish(region);
break;
}
postInvalidate();
return true;
}
//手指在屏幕上滑动时调用
private void touchMove(MotionEvent event) {
final float x = event.getX();
final float y = event.getY();
Point point = new Point();
point.x = (int) event.getX();
point.y = (int) event.getY();
pathCircle.addCircle(event.getX(), event.getY(), (xustrokeWidth - strokeWidth) / 2, Path.Direction.CCW);
final float dx = Math.abs(x - pathX);
final float dy = Math.abs(y - pathY);
//两点之间的距离大于等于3时,生成贝塞尔绘制曲线
if (dx >= 3 || dy >= 3) {
//设置贝塞尔曲线的操作点为起点和终点的一半
float cX = (x + pathX) / 2;
float cY = (y + pathY) / 2;
//二次贝塞尔,实现平滑曲线;previousX, previousY为操作点,cX, cY为终点
mPath.quadTo(pathX, pathY, cX, cY);
transparentPath.quadTo(pathX, pathY, cX, cY);
//第二次执行时,第一次结束调用的坐标值将作为第二次调用的初始坐标值
pathX = x;
pathY = y;
}
}
private void touchDown(MotionEvent event) {
reset();
pathX = event.getX();
pathY = event.getY();
startX = event.getX();
startY = event.getY();
mPath.moveTo(pathX, pathY);
transparentPath.moveTo(pathX, pathY);
isActionUp = true;
}
/**
* 清除所有内容
*/
public void reset() {
mPath.reset();
transparentPath.reset();
pathCircle.reset();
init();
isDrwable = false;
}
public Boolean getClose() {
return isClose;
}
/**
* 是否只是闭合状态
*
* @param close
*/
public void setClose(Boolean close) {
isClose = close;
}
public int getPaintColor() {
return paintColor;
}
/**
* 设置画笔颜色
*
* @param paintColor
*/
public void setPaintColor(int paintColor) {
this.paintColor = paintColor;
}
public int getPaintTransparentColor() {
return paintTransparentColor;
}
/**
* 设置粗画笔颜色
*
* @param paintTransparentColor
*/
public void setPaintTransparentColor(int paintTransparentColor) {
this.paintTransparentColor = paintTransparentColor;
}
public int getCloseX() {
return closeX;
}
/**
* 设置闭合X距离
*
* @param closeX
*/
public void setCloseX(int closeX) {
this.closeX = closeX;
}
public int getCloseY() {
return closeY;
}
/**
* 设置闭合Y距离
*
* @param closeY
*/
public void setCloseY(int closeY) {
this.closeY = closeY;
}
/**
* 当前闭合状态
*
* @return
*/
public Boolean getStatus() {
return isStatus;
}
public void setStatus(Boolean status) {
isStatus = status;
}
public float getStrokeWidth() {
return strokeWidth;
}
/**
* 设置线条宽度
*
* @param strokeWidth
*/
public void setStrokeWidth(float strokeWidth) {
this.strokeWidth = strokeWidth;
mPaint.setStrokeWidth(strokeWidth);
}
public float getXustrokeWidth() {
return xustrokeWidth;
}
/**
* 设置第二条线宽度
*
* @param xustrokeWidth
*/
public void setXustrokeWidth(float xustrokeWidth) {
this.xustrokeWidth = xustrokeWidth;
transparentPaint.setStrokeWidth(xustrokeWidth);
}
/**
* 设置第二条线透明度
*
* @param alpha
*/
public void setAlpha(int alpha) {
this.alpha = alpha;
transparentPaint.setAlpha(alpha);
}
public void setOnFinishListener(OnFinishListener listener) {
this.listener = listener;
}
public interface OnFinishListener {
public void onFinish(Region p);
}
}
其中最主要的几个方法,第一:init()方法,初始化画笔,设置透明度等等。第二:onTouchEvent()方法会获取用户的点击事件,用户点击调用touchDown()方法,调用完成之后用户开始进行“画”,画就会调用移动方法touchMove(),当移动完成就抬起手指运行ACTION_UP之后的代码。
我们直接开始说touchMove()方法:
根据移动的X,Y坐标与上一个点位的X,Y坐标进行相减取绝对值,如果绝对值大于3就进行path路径的添加,不过这里需要注意的是,添加的路径是贝塞尔曲线,没有用lineto,而是用的quadTo,主要是为了解决路径不平滑问题。
下面就是ACTION_UP,手指抬起运行的代码:
第一先判断,当前是否只需要闭合一种状态,如果只需要这种状态,进行路径闭合状态的关闭
path.close();//路径闭合方法,如果起点和结束点没有关闭调用此方法会直接将起点和结束的连线
然后进行路径的区域获取
RectF r = new RectF();//添加一个矩形
mPath.computeBounds(r, true);//设置路径的区域为矩形的区域
最后将路径的区域和矩形的区域取交集,也就是闭合区域的路径
region.setPath(mPath, new Region((int) r.left, (int) r.top, (int) r.right, (int) r.bottom));
同理,非闭合区域状态一样判断。
MainActivity代码:
package com.example.lenovo.enclosure;
import android.graphics.Bitmap;
import android.graphics.Point;
import android.graphics.Region;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import com.baidu.mapapi.SDKInitializer;
import com.baidu.mapapi.map.BitmapDescriptor;
import com.baidu.mapapi.map.BitmapDescriptorFactory;
import com.baidu.mapapi.map.GroundOverlayOptions;
import com.baidu.mapapi.map.MapView;
import com.baidu.mapapi.map.OverlayOptions;
import com.baidu.mapapi.model.LatLng;
import com.baidu.mapapi.model.LatLngBounds;
public class MainActivity extends AppCompatActivity implements PathView.OnFinishListener{
private PathView pview;
private MapView bmapView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
SDKInitializer.initialize(getApplicationContext());
setContentView(R.layout.activity_main);
bmapView = (MapView) findViewById(R.id.bmapView);
pview = (PathView) findViewById(R.id.pview);
pview.setOnFinishListener(this);
}
@Override
public void onFinish(Region p) {
// p.contains(x,y)//闭合区域 判断用是否在区域里面
pview.setVisibility(View.GONE);
Point point = new Point(0, 0);
Point point1 = new Point(pview.getWidth(), pview.getHeight());
BitmapDescriptor bitmapDescriptor = BitmapDescriptorFactory.fromBitmap(getViewBitmap(pview));
LatLng southwest = bmapView.getMap().getProjection().fromScreenLocation(point);
LatLng northeast = bmapView.getMap().getProjection().fromScreenLocation(point1);
LatLngBounds bounds = new LatLngBounds.Builder().include(northeast).include(southwest).build();
OverlayOptions path = new GroundOverlayOptions().positionFromBounds(bounds).image(bitmapDescriptor).zIndex(9);
bmapView.getMap().addOverlay(path);
}
/**
* 将View转换为图片
* @param v
* @return
*/
private Bitmap getViewBitmap(View v) {
v.clearFocus();
v.setPressed(false);
boolean willNotCache = v.willNotCacheDrawing();
v.setWillNotCacheDrawing(false);
// Reset the drawing cache background color to fully transparent
// for the duration of this operation
int color = v.getDrawingCacheBackgroundColor();
v.setDrawingCacheBackgroundColor(0);
if (color != 0) {
v.destroyDrawingCache();
}
v.buildDrawingCache();
Bitmap cacheBitmap = v.getDrawingCache();
if (cacheBitmap == null) {
Log.e("Folder", "failed getViewBitmap(" + v + ")", new RuntimeException());
return null;
}
Bitmap bitmap = Bitmap.createBitmap(cacheBitmap);
// Restore the view
v.destroyDrawingCache();
v.setWillNotCacheDrawing(willNotCache);
v.setDrawingCacheBackgroundColor(color);
return bitmap;
}
}
这里需要注意的是onFinish方法,这是当绘制状态结束之后调用(即手指抬起之后),然后隐藏布局文件的自定义控件,然后再将这个自定义控件绘制完成的view转换为图片,并且添加到mapview上面。
布局文件activity_main:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1">
<com.baidu.mapapi.map.MapView
android:id="@+id/bmapView"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
<com.example.lenovo.enclosure.PathView
android:id="@+id/pview"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</RelativeLayout>
如有纰漏,尽请批正。谢!
如果你喜欢文摘,恰好你也看了我写的文摘,又恰巧你喜欢专研技术,那么为什么不加入我们那。(QQ群:417487178)欢迎交流。
网友评论