0

How to add on map an rectangle representing 80% width and 80% height of the screen like Maps offline area selection screen. I need to get the LatLngBound of this rectangle, a LinearLayout may not be the solution here.

Daminox
  • 313
  • 1
  • 8

1 Answers1

1

You can get LatLon coordinates of pixel by getProjection() method, and draw everything you want in onDraw() method of custom view.

So, like in this answer of NSimon just add custom view (e.g. FrameView) with needed transparency over MapFragment in your map activity layout xml:

<fragment
    android:id="@+id/map_fragment"
    android:name="com.google.android.gms.maps.MapFragment"
    android:layout_width="match_parent"
    android:layout_height="match_parent"/>

<[your_package].FrameView
    android:id="@+id/frame_view"
    android:layout_width="match_parent"
    android:layout_height="match_parent"/>

where [your_package].FrameView is

public class FrameView extends View {

    private Paint mTransparentPaint;
    private Paint mBorderPaint;
    private Paint mSemiBlackPaint;
    private Path mPath = new Path();
    private GoogleMap mGoogleMap = null;
    private float x1, y1, x2, y2;

    public FrameView(Context context) {
        super(context);
        init();
    }

    public FrameView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    public FrameView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }

    private void init() {
        mTransparentPaint = new Paint();
        mTransparentPaint.setColor(Color.TRANSPARENT);
        mTransparentPaint.setStyle(Paint.Style.FILL);

        mBorderPaint = new Paint();
        mBorderPaint.setColor(Color.BLUE);
        mBorderPaint.setStyle(Paint.Style.STROKE);
        mBorderPaint.setStrokeWidth(10);

        mSemiBlackPaint = new Paint();
        mSemiBlackPaint.setColor(Color.TRANSPARENT);
        mSemiBlackPaint.setStyle(Paint.Style.FILL);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        x1 = 0.1f * canvas.getWidth();
        y1 = 0.1f * canvas.getHeight();
        x2 = 0.9f * canvas.getWidth();
        y2 = 0.8f * canvas.getHeight();

        mPath.reset();

        mPath.addRect(x1, y1, x2, y2, Path.Direction.CW);
        mPath.setFillType(Path.FillType.INVERSE_EVEN_ODD);

        canvas.drawRect(x1, y1, x2, y2, mTransparentPaint);
        canvas.drawRect(x1, y1, x2, y2, mBorderPaint);
        canvas.drawPath(mPath, mSemiBlackPaint);

        canvas.clipPath(mPath);
        canvas.drawColor(Color.parseColor("#83000000"));
    }

    public void setMap(GoogleMap googleMap) {
        mGoogleMap = googleMap;
    }

    public LatLng getTopLeft() {
        return point2LatLng(new Point((int)x1, (int)y1));
    }

    public LatLng getTopRight() {
        return point2LatLng(new Point((int)x2, (int)y1));
    }

    public LatLng getBottomLeft() {
        return point2LatLng(new Point((int)x1, (int)y2));
    }

    public LatLng getBottomRight() {
        return point2LatLng(new Point((int)x2, (int)y2));
    }

    public LatLng point2LatLng(Point point) {
        if (mGoogleMap != null) {
            Projection projection = mGoogleMap.getProjection();
            return projection.fromScreenLocation(point);
        } else {
            return null;
        }
    }

}

where x1, x2, y1, y2 - coordinates of "frame" rectangle in pixels.

Than you need get FrameView object in onCreate():

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    mFrameView = (FrameView) findViewById(R.id.frame_view);
    mapFragment = (MapFragment) getFragmentManager()
            .findFragmentById(R.id.map_fragment);
    mapFragment.getMapAsync(this);

    ...
}

and set GoogleMap object for mFrameView in onMapReady():

@Override
public void onMapReady(GoogleMap googleMap) {
    mGoogleMap = googleMap;
    mFrameView.setMap(mGoogleMap);
    ...
}

and now you can get LatLon coords by mFrameView.getTopLeft(), mFrameView.getTopRight() etc. calls when you need it:

enter image description here

NB! This is just quick and dirty example of custom component.

Andrii Omelchenko
  • 13,183
  • 12
  • 43
  • 79
  • The getProjection() was the part I missed...Sounds perfect !! Why do you say "quick and dirty" ? – Daminox Nov 08 '17 at 15:52
  • @Daminox Because in right way `FrameView` and `GoogleMap` should be one composite custom view: `setMap()` is working, but not very nice method. And there is no need to create new `Point` object on every `point2LatLng()` call and `"#83000000"` - bad constant, and dark frame around blue rectangle and so on :) – Andrii Omelchenko Nov 08 '17 at 18:47
  • Ok, so in this case I should not use MapFragment but a custom fragment. Is it right ? – Daminox Nov 09 '17 at 09:03
  • @Daminox Yes, custom map fragment. – Andrii Omelchenko Nov 09 '17 at 09:12