1200字范文,内容丰富有趣,写作的好帮手!
1200字范文 > android地图路径绘制 android:利用svg的path路径+canvas 开发自定义地图控件

android地图路径绘制 android:利用svg的path路径+canvas 开发自定义地图控件

时间:2023-05-08 01:06:41

相关推荐

android地图路径绘制 android:利用svg的path路径+canvas 开发自定义地图控件

需求:做小型地图的一个显示功能

实现思路:自定义view解析对应的svg文件,在利用canvas的画笔画出相应的地图线条。各个线条围成的区域可以表示成各个元素比如树,街道,路灯,汽车等等一切事物。然后通过view的点击事件可以给自定义控件添加点击,长按,放大缩小等等操作。

需要美工给一个svg格式的图片。

//当然这里并不止一个path路径,这里的path路径就是地图的线条

android:width="3000dp"

android:height="3000dp"

android:viewportWidth="3000"

android:viewportHeight="3000">

android:dataName="CCCC"

android:cabinId="9a43312887844fa3a2815dfac018f6ee"

android:pathData="M7,2297H157v60H7v-60Z"

android:strokeWidth="8.333"

android:fillType="evenOdd"

android:strokeColor="#000"/>

path标签内可存放一切你想要存放的信息,可以是表示一棵树,一栋房子都随意,只需要按照相应的格式解析出来存放到对象内就行了。

//控件自适应请重写onMeasure方法,我这里是直接全屏了。

public class MapView extends View {

private Paint paint;

private Context mContext;

private int[] colors = new int[]{Color.BLUE,Color.CYAN,Color.YELLOW,Color.GREEN};

private List pathItemList = new ArrayList<>();

GestureDetector gestureDetector;

ScaleGestureDetector scaleGestureDetector;

//双指操作下的中心位置

float focusX = 0,focusY = 0;

float posX = 0, posY = 0;

int viewWidth, viewHeight;

//是否初始化了

boolean hasInitViewSize;

float widthScale, heightScale;

float scaleFactor = 1.0f;

private int imgWidth = 3000,imgHeight=3000;

private MapPathItem selectPathItem;

//地图最大的矩阵

private RectF mapRectF;

private List users;

private List usersLocationInfo;

private Bitmap userLocationIcon;

private itemClickListener itemClickListener;

public MapView(Context context) {

super(context);

}

public MapView(Context context, @Nullable AttributeSet attrs) {

super(context, attrs);

init(context);

}

private void init(Context context) {

this.mContext = context;

this.paint = new Paint();

users = new ArrayList<>();

usersLocationInfo = new ArrayList<>();

userLocationIcon = BitmapFactory.decodeResource(getResources(),R.drawable.avtar_icon);

gestureDetector = new GestureDetector(context, new MySimpleOnGestureDetector());

scaleGestureDetector = new ScaleGestureDetector(context, new MySimpleScaleOnGestureDetector());

thread.start();

}

//双指缩放

class MySimpleScaleOnGestureDetector extends ScaleGestureDetector.SimpleOnScaleGestureListener {

@Override

public boolean onScale(ScaleGestureDetector detector) {

scaleFactor *= detector.getScaleFactor();

scaleFactor = scaleFactor < 1 ? (float) 1 : scaleFactor > 3 ? 3 : scaleFactor;

focusX = detector.getFocusX();

focusY = detector.getFocusY();

invalidate();

return true;

}

}

//单指移动

class MySimpleOnGestureDetector extends GestureDetector.SimpleOnGestureListener {

@Override

public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {

posX -= distanceX;

posY -= distanceY;

invalidate();

return true;

}

@Override

public boolean onSingleTapConfirmed(MotionEvent e) {

//点击区域是舱段区域才触发listener

for (MapPathItem item:pathItemList){

if(item.isTouch(e.getX()-posX,e.getY()-posY,scaleFactor)){

onTouch(e.getX(),e.getY());

}

}

return super.onSingleTapConfirmed(e);

}

}

public void initSize() {

viewWidth = getWidth();

viewHeight = getHeight();

if (viewWidth < 0 && viewHeight < 0) {

return;

}

hasInitViewSize = true;

widthScale = viewWidth / imgWidth;

heightScale = viewHeight / imgHeight;

scaleFactor = Math.min(widthScale, heightScale);

scaleFactor = 1f;

posX = viewWidth / 2 - imgWidth / 2;

posY = viewHeight / 2 - imgHeight / 2;

}

@Override

public boolean onTouchEvent(MotionEvent event) {

scaleGestureDetector.onTouchEvent(event); //双指缩放

gestureDetector.onTouchEvent(event); //单指移动

//点击区域事件

return true;

}

@RequiresApi(api = Build.VERSION_CODES.N)

public void refreshUserLocation(List users){

usersLocationInfo.clear();

Log.e("users", String.valueOf(users.size()));

for (MapPathItem item:pathItemList){

users.forEach(userLocationInf -> {

if(item.getCabinId().equals(userLocationInf.getCabinId())){

usersLocationInfo.add(item);

}

});

}

Log.e("usersLocationInfosize", String.valueOf(usersLocationInfo.size()));

invalidate();

}

private void onTouch(float x, float y) {

for (MapPathItem item:pathItemList){

if(item.isTouch(x-posX,y-posY,scaleFactor)){

selectPathItem = item;

}

}

//从新绘制

if(selectPathItem!=null){

//设置点击事件

//ToastShow.showText(getContext(),"点击了item"+selectPathItem.getCabinId());

if(itemClickListener!=null){

itemClickListener.itemClick(selectPathItem);

}

Log.e("选中",selectPathItem.toString());

invalidate();

}

}

public interface itemClickListener{

void itemClick(MapPathItem selectPathItem);

}

private void checkBounds() { //检查边界

if (scaleFactor > widthScale) {

posX = Math.min(posX, (scaleFactor - 1) * (imgWidth / 2));

posX = Math.max(posX, viewWidth - imgHeight*scaleFactor - (scaleFactor - 1) * (imgWidth / 2));

} else {

posX = Math.max(posX, (scaleFactor - 1) * (imgWidth / 2));

posX = Math.min(posX, viewWidth - imgWidth*scaleFactor - (scaleFactor - 1) * (imgWidth / 2));

}

if (scaleFactor > heightScale) {

posY = Math.min(posY, (scaleFactor - 1) * (imgHeight / 2));

posY = Math.max(posY, viewHeight - imgHeight*scaleFactor - (scaleFactor - 1) * (imgHeight / 2));

} else {

posY = Math.max(posY, (scaleFactor - 1) * (imgHeight / 2));

posY = Math.min(posY, viewHeight - imgHeight*scaleFactor - (scaleFactor - 1) * (imgHeight / 2));

}

}

//子线程加载svg

private Thread thread = new Thread(new Runnable() {

@Override

public void run() {

InputStream inputStream = mContext.getResources().openRawResource(R.raw.cabins);

//数据流转化为path DocumentBuilderFactory dom解析工厂

DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();

try {

DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();

Document document = documentBuilder.parse(inputStream);

//根节点

Element documentElement = document.getDocumentElement();

String attribute = documentElement.getAttribute("android:viewportWidth");

Log.e("viewportWidth",attribute);

//子节点

NodeList nodeList = documentElement.getElementsByTagName("path");

//svg的上下左右边界

float left = -1,top = -1,right = -1,bottom = -1;

//解析子节点属性

for(int i = 0;i

Element element = (Element)nodeList.item(i);

//拿到路径

String pathData = element.getAttribute("android:pathData");

String dataName = element.getAttribute("android:dataName");

String cabinId = element.getAttribute("android:cabinId");

Path path = PathParser.createPathFromPathData(pathData);

MapPathItem pathItem = new MapPathItem(path);

pathItem.setDataName(dataName);

pathItem.setCabinId(cabinId);

pathItem.setColor(Color.BLACK);

pathItemList.add(pathItem);

RectF rectF = new RectF();

puteBounds(rectF,true);

left = left ==-1?rectF.left:Math.min(rectF.left,left);

top = top ==-1?rectF.top:Math.min(rectF.top,top);

right = right ==-1?rectF.right:Math.min(rectF.right,right);

bottom = bottom ==-1?rectF.bottom:Math.min(rectF.bottom,bottom);

}

mapRectF = new RectF(left,top,right,bottom);

measure(getMeasuredWidth(),getMeasuredHeight());

handler.sendEmptyMessage(1);

} catch (Exception e) {

e.printStackTrace();

}

}

});

@SuppressLint("HandlerLeak")

private Handler handler = new Handler(){

@RequiresApi(api = Build.VERSION_CODES.N)

@Override

public void handleMessage(@NonNull Message msg) {

super.handleMessage(msg);

invalidate();

}

};

@RequiresApi(api = Build.VERSION_CODES.N)

@Override

protected void onDraw(Canvas canvas) {

super.onDraw(canvas);

if (!hasInitViewSize) {

initSize();

}

checkBounds();

canvas.translate(posX,posY);

//canvas.scale(scaleFactor, scaleFactor, focusX-posX, focusY-posY);

canvas.scale(scaleFactor,scaleFactor);

for (MapPathItem pathItem : pathItemList) {

pathItem.drawItem(canvas,paint,false);

}

if(selectPathItem!=null){

Log.e("sadasd","重绘");

selectPathItem.drawItem(canvas,paint,true);

}

if(usersLocationInfo.size()!= 0 ){

usersLocationInfo.forEach(user->{

user.drawUserIcon(canvas,paint,userLocationIcon);

});

}

}

public void setItemClickListener(MapView.itemClickListener itemClickListener) {

this.itemClickListener = itemClickListener;

}

}

public class MapPathItem {

//画笔路径

private Path path;

private int color;

private String dataName;

private String cabinId;

public MapPathItem(Path path) {

this.path = path;

}

public void setColor(int color) {

this.color = color;

}

public void drawItem(Canvas canvas, Paint paint,boolean isSelect){

if(isSelect){

//画边框

paint.setStrokeWidth(4);

paint.setStyle(Paint.Style.STROKE);

paint.setShadowLayer(6,0,0,Color.RED);

paint.setColor(Color.BLACK);

canvas.drawPath(path, paint);

//填充色

paint.setColor(Color.RED);

paint.setStyle(Paint.Style.FILL);

paint.setStrokeWidth(4);

}else {

//清除阴影

paint.clearShadowLayer();

//画边框

paint.setStrokeWidth(2);

paint.setStyle(Paint.Style.STROKE);

paint.setColor(Color.BLACK);

canvas.drawPath(path, paint);

//填充色

paint.setColor(Color.WHITE);

paint.setStyle(Paint.Style.FILL);

paint.setStrokeWidth(2);

}

canvas.drawPath(path, paint);

}

public void drawUserIcon(Canvas canvas, Paint paint, Bitmap b) {

RectF rectF = new RectF();

puteBounds(rectF,true);

Rect src=new Rect(0,0,b.getWidth(),b.getHeight());

canvas.drawBitmap(b,src,rectF,paint);

}

/**

* 判断当前区域是否选中

* @param x

* @param y

* @param scaleFactor 缩放倍数

* @return

*/

public boolean isTouch(float x,float y,float scaleFactor){

RectF rectF = new RectF();

puteBounds(rectF,true);

//区域

Region region = new Region();

region.set((int)(rectF.left*scaleFactor),(int)(rectF.top*scaleFactor),(int)(rectF.right*scaleFactor),(int)(rectF.bottom*scaleFactor));

return region.contains((int)x,(int)y);

}

public String getDataName() {

return dataName;

}

public void setDataName(String dataName) {

this.dataName = dataName;

}

public String getCabinId() {

return cabinId;

}

public void setCabinId(String cabinId) {

this.cabinId = cabinId;

}

}

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。