Android - draw mutable circle on google map

I am trying to draw a modified circle on top of my google map, which the user can expand or compress using touch gestures (for example, to reduce the circle that the user will clamp the circle on the screen, I want it to work as an option to zoom to / from the map, only that only the circle will be bigger / smaller on the map). Can this be implemented? And if so, how can I do this.

I searched Google and Stackoverflow, and as I understand it, I need to add a custom view on top of my map fragment and implement OnTouchListener for this view (and this is just the beginning). Can someone please advise what to do or how to act? I can draw a circle on the map, but I don’t know how to make it respond to touch events.

Thanks in advance.

+4
source share
3 answers

Based on your question, you want to impose a “listening view” that draws an oval shape based on a pinch. To do this, I made some poorly tested codes, adapting them as needed:

MainLayout:

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" > <!-- Replace the ImageView with your MapView or whatever you are overlaying with the oval shape --> <ImageView android:layout_width="match_parent" android:layout_height="match_parent" android:src="#F00" /> <com.example.testapp.CircleTouchView android:id="@+id/circle_drawer_view" android:layout_width="match_parent" android:layout_height="match_parent" /> </FrameLayout> 

CircleTouchView:

 public class CircleTouchView extends View { private static final int MODE_PINCH = 0; private static final int MODE_DONT_CARE = 1; ShapeDrawable mCircleDrawable; int mTouchMode = MODE_DONT_CARE; public CircleTouchView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); mCircleDrawable = new ShapeDrawable(new OvalShape()); mCircleDrawable.getPaint().setColor(0x66FFFFFF); } public CircleTouchView(Context context, AttributeSet attrs) { this(context, attrs, 0); } public CircleTouchView(Context context) { this(context, null, 0); } @Override public boolean onTouchEvent(MotionEvent event) { switch (event.getActionMasked()) { case MotionEvent.ACTION_DOWN: mCircleDrawable.setBounds(0, 0, 0, 0); invalidate(); break; case MotionEvent.ACTION_POINTER_DOWN: prepareCircleDrawing(event); break; case MotionEvent.ACTION_MOVE: if (mTouchMode == MODE_PINCH) { prepareCircleDrawing(event); } break; case MotionEvent.ACTION_POINTER_UP: if (event.getActionIndex() <= 1) { mTouchMode = MODE_DONT_CARE; } break; default: super.onTouchEvent(event); } return true; } private void prepareCircleDrawing(MotionEvent event) { int top, right, bottom, left; int index = event.getActionIndex(); if (index > 1) { return; } mTouchMode = MODE_PINCH; if (event.getX(0) < event.getX(1)) { left = (int) event.getX(0); right = (int) event.getX(1); } else { left = (int) event.getX(1); right = (int) event.getX(0); } if (event.getY(0) < event.getY(1)) { top = (int) event.getY(0); bottom = (int) event.getY(1); } else { top = (int) event.getY(1); bottom = (int) event.getY(0); } mCircleDrawable.setBounds(left, top, right, bottom); invalidate(); } @Override protected void onDraw(Canvas canvas) { mCircleDrawable.draw(canvas); } } 

If you want a perfect circle instead of an oval shape, change the prepareCircleDrawing () method so that it takes the smallest values ​​for X and Y between events 0 and 1.

Edit: you can add the snippet below before calling mCircleDrawable.setBounds(left, top, right, bottom); to draw a perfect circle. There are other ways to draw circles, it depends on how you want it to behave.

 int height = bottom - top; int width = right - left; if (height > width) { int delta = height - width; top += delta / 2; bottom -= delta / 2; } else { int delta = width - height; left += delta / 2; right -= delta / 2; } 

Hope I clearly said hi.

+4
source

It has been a while since the question was asked, but I used it in the past before switching to something other than a circle.

its not perfect, but maybe it will help someone.

 public class CircleView extends View { private static final String TAG = "CircleView"; private static final double MOVE_SENSITIVITY = 1.25; private Paint circlePaint; private boolean isPinchMode; private int lastCircleX; private int lastCircleY; public Circle circle; private boolean isDoneResizing = true; public CircleView(Context context) { super(context); setCirclePaint(0x220000ff); } public CircleView(Context context, AttributeSet attrs) { super(context, attrs); setCirclePaint(0x220000ff); } public CircleView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); setCirclePaint(0x220000ff); } private void setCirclePaint(int color) { circle = new Circle(); circlePaint = new Paint(); circlePaint.setColor(color); } @Override protected void onDraw(Canvas canvas) { canvas.drawCircle(circle.centerX, circle.centerY, circle.radius, circlePaint); } @Override public boolean onTouchEvent(final MotionEvent event) { int historySize; double lastDistance; double oneBeforeLastDistance; switch (event.getActionMasked()) { case MotionEvent.ACTION_DOWN: lastCircleX = circle.centerX; lastCircleY = circle.centerY; break; case MotionEvent.ACTION_POINTER_DOWN: isPinchMode = true; isDoneResizing = false; break; case MotionEvent.ACTION_MOVE: circle.centerX = lastCircleX; circle.centerY = lastCircleY;; if (getTouchedCircle((int) event.getX(), (int) event.getY()) && !isPinchMode && isDoneResizing) { historySize = event.getHistorySize(); if (historySize > 0) { oneBeforeLastDistance = Math.sqrt((event.getX() - event.getHistoricalX(0, historySize - 1)) * (event.getX() - event.getHistoricalX(0, historySize - 1)) + (event.getY() - event.getHistoricalY(0, historySize - 1)) * (event.getY() - event.getHistoricalY(0, historySize - 1))); if (oneBeforeLastDistance > MOVE_SENSITIVITY) { circle.centerX = (int) event.getX(); circle.centerY = (int) event.getY(); lastCircleX = circle.centerX; lastCircleY = circle.centerY; } } } if (isPinchMode) { circle.centerX = lastCircleX; circle.centerY = lastCircleY; historySize = event.getHistorySize(); if (historySize > 0) { lastDistance = Math.sqrt((event.getX(0) - event.getX(1)) * (event.getX(0) - event.getX(1)) + (event.getY(0) - event.getY(1)) * (event.getY(0) - event.getY(1))); oneBeforeLastDistance = Math.sqrt((event.getHistoricalX(0, historySize - 1) - event.getHistoricalX(1, historySize - 1)) * (event.getHistoricalX(0, historySize - 1) - event.getHistoricalX(1, historySize - 1)) + (event.getHistoricalY(0, historySize - 1) - event.getHistoricalY(1, historySize - 1)) * (event.getHistoricalY(0, historySize - 1) - event.getHistoricalY(1, historySize - 1))); if (lastDistance < oneBeforeLastDistance) { circle.radius -= Math.abs(lastDistance - oneBeforeLastDistance); } else { circle.radius += Math.abs(lastDistance - oneBeforeLastDistance); } } } lastCircleX = circle.centerX; lastCircleY = circle.centerY; invalidate(); break; case MotionEvent.ACTION_POINTER_UP: circle.centerX = lastCircleX; circle.centerY = lastCircleY; isPinchMode = false; break; case MotionEvent.ACTION_UP: circle.centerX = lastCircleX; circle.centerY = lastCircleY; isPinchMode = false; isDoneResizing = true; break; case MotionEvent.ACTION_CANCEL: break; case MotionEvent.ACTION_HOVER_MOVE: break; default: super.onTouchEvent(event); break; } return true; } private Boolean getTouchedCircle(final int xTouch, final int yTouch) { if ((circle.centerX - xTouch) * (circle.centerX - xTouch) + (circle.centerY - yTouch) * (circle.centerY - yTouch) <= circle.radius * circle.radius) { return true; } else { return false; } } static class Circle { int radius; int centerX; int centerY; Circle() { this.radius = 150; this.centerX = 378; this.centerY = 478; } } } 
+2
source

Some time has passed since this question was asked, but I want to introduce another way to do this. I created my own library to handle drag-and-drop map area (circle). https://github.com/ac-opensource/MarkerBuilder

It can be implemented by initializing the MarkerBuilderManager

 markerBuilderManager = new MarkerBuilderManagerV2.Builder(this) .map(mMap) // required .build(); 
0
source

All Articles