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.
Asked
Active
Viewed 436 times
1 Answers
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:
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