android - draw resizable circle on google map

前端 未结 3 561
心在旅途
心在旅途 2020-12-18 05:25

I\'m trying to draw a resizable circle on top of my google map, which the user will be able to expand or shrink using touch gestures (for example to shrink the circle the us

相关标签:
3条回答
  • 2020-12-18 05:35

    It has been a while since this question was asked but I want to introduce another way of doing this. I created my own library to handle draggable resizable map area (circle). https://github.com/ac-opensource/MarkerBuilder

    It can be implemented by just initialising the MarkerBuilderManager

    markerBuilderManager = new MarkerBuilderManagerV2.Builder(this)
              .map(mMap) // required
              .build();
    
    0 讨论(0)
  • 2020-12-18 05:48

    Based on your question, you want to overlay a "pinch listening" view that draws an oval shape based on the pinch. I made some poorly-tested code for this purpose, adapt it as you need:

    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 event 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 for drawing 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 made myself clear, regards.

    0 讨论(0)
  • 2020-12-18 05:52

    it has been a while since the question was asked but I used this in the past before switching to something different 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;
        }        
    }
    
    
    
    }
    
    0 讨论(0)
提交回复
热议问题