MapView Polygon
This example shows how to add Polygons in MapView
-
Add Polygon from a set of Latlng
-
Query Visible Polygon in Rect
-
Set Polygon stroke
-
Set Polygon color
For all code examples, refer to Android Maps SDK Code Examples
activity_polygon.xml view source
1<?xml version="1.0" encoding="utf-8"?>2<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"3xmlns:app="http://schemas.android.com/apk/res-auto"4xmlns:tools="http://schemas.android.com/tools"5android:layout_width="match_parent"6android:layout_height="match_parent"7tools:context=".PolygonActivity">89<ai.nextbillion.maps.core.MapView10android:id="@+id/map_view"11android:layout_width="match_parent"12android:layout_height="match_parent"13app:nbmap_cameraTargetLat="53.5493093866953"14app:nbmap_cameraTargetLng="10.031835837897463"15app:nbmap_cameraZoom="10"16app:nbmap_uiAttribution="false" />1718<androidx.core.widget.NestedScrollView19android:id="@+id/bottomSheet"20android:layout_width="match_parent"21android:layout_height="wrap_content"22android:background="@color/white"23app:behavior_hideable="true"24app:layout_behavior="com.google.android.material.bottomsheet.BottomSheetBehavior">2526<LinearLayout27android:layout_width="match_parent"28android:layout_height="wrap_content"29android:orientation="vertical">3031<TextView32android:layout_width="68dp"33android:layout_height="1dp"34android:layout_gravity="center_horizontal"35android:layout_marginTop="13dp"36android:background="@drawable/nbmap_radius_10_grey_bg" />3738<TextView39android:layout_width="wrap_content"40android:layout_height="wrap_content"41android:layout_marginTop="13dp"42android:paddingHorizontal="16dp"43android:text="@string/polygonSetting"44android:textColor="@color/black"45android:textSize="24sp" />4647<ai.nextbillion.view.SettingSwitchView48android:id="@+id/pointEnable"49android:layout_width="match_parent"50android:layout_height="wrap_content"51android:layout_marginLeft="16dp"52android:layout_marginRight="16dp" />5354<ai.nextbillion.view.ColorSelectorView55android:id="@+id/polygon_color"56android:layout_width="match_parent"57android:layout_height="wrap_content"58android:layout_marginTop="10dp" />5960<ai.nextbillion.view.ColorSelectorView61android:id="@+id/polygon_stroke_Color"62android:layout_width="match_parent"63android:layout_height="wrap_content"64android:layout_marginTop="10dp" />6566<ai.nextbillion.view.SliderBarView67android:id="@+id/lineWidth"68android:layout_width="match_parent"69android:layout_height="wrap_content"70android:layout_marginBottom="10dp" />7172</LinearLayout>737475</androidx.core.widget.NestedScrollView>7677<com.google.android.material.floatingactionbutton.FloatingActionButton78android:id="@+id/fb_clean"79android:layout_width="wrap_content"80android:layout_height="wrap_content"81android:layout_gravity="right"82android:layout_marginTop="120dp"83android:layout_marginRight="16dp"84android:backgroundTint="@color/purple_200"85android:src="@android:drawable/ic_menu_close_clear_cancel"86android:tooltipText="Clean"87app:fabSize="mini" />8889<TextView90android:id="@+id/fb_check"91android:layout_width="40dp"92android:layout_height="40dp"93android:layout_gravity="right"94android:layout_marginTop="170dp"95android:layout_marginRight="16dp"96android:background="@drawable/shape_circle_40_md_grey_400"97android:gravity="center"98android:text="@string/polygonStrokeCheck" />99100101<com.google.android.material.floatingactionbutton.FloatingActionButton102android:id="@+id/fb_expand"103android:layout_width="wrap_content"104android:layout_height="wrap_content"105android:layout_gravity="right|bottom"106android:layout_marginRight="16dp"107android:layout_marginBottom="56dp"108android:backgroundTint="@color/purple_200"109android:src="@android:drawable/ic_dialog_info"110android:tooltipText="Create"111android:visibility="gone"112app:fabSize="mini" />113114<ImageView115android:id="@+id/iv_back"116android:layout_width="40dp"117android:layout_height="40dp"118android:layout_gravity="top|left"119android:layout_marginLeft="16dp"120android:layout_marginTop="16dp"121android:background="@drawable/circle_white_bg"122android:src="@drawable/icon_back"123app:tint="@color/color_back_icon" />124125</androidx.coordinatorlayout.widget.CoordinatorLayout>
PolygonActivity view source
1public class PolygonActivity extends AppCompatActivity implements View.OnClickListener {23private NextbillionMap mMap;4private MapView mapView;5private BottomSheetBehavior bottomSheetBehavior;6private Polygon polygon;7// for stroke8private Polyline polyline;910// polygon11private List<LatLng> polygonPoints = new ArrayList<>();12private List<Marker> polygonMarkers = new ArrayList<>();13private LatLngBounds latLngBounds;14private Marker clickMarker;1516// menu17private ColorSelectorView polygonColorSelectorView;18private ColorSelectorView polygonStrokeColorSelectorView;19private SliderBarView polygonStrokeWidthSliderBarView;20private SettingSwitchView pointSettingSwitchView;21private FloatingActionButton fbInfoFloatingActionButton;22private TextView fbNoticeButton;2324private String polygonColor = "#1E58A5";25private String polygonStrokeColor = "#FF0000";26private float stockWidth = 2;27private int polygonIndex = 1;28private boolean showPolygonVertex = true;2930@Override31protected void onCreate(Bundle savedInstanceState) {32super.onCreate(savedInstanceState);33setContentView(R.layout.activity_polygon);34mapView = findViewById(R.id.map_view);35mapView.onCreate(savedInstanceState);36mapView.getMapAsync(this::onMapSync);37// button38findViewById(R.id.fb_clean).setOnClickListener(this);39fbInfoFloatingActionButton = findViewById(R.id.fb_expand);40fbInfoFloatingActionButton.setOnClickListener(this);41fbNoticeButton = findViewById(R.id.fb_check);42fbNoticeButton.setOnClickListener(this);43// menu44polygonColorSelectorView = findViewById(R.id.polygon_color);45polygonStrokeColorSelectorView = findViewById(R.id.polygon_stroke_Color);46polygonStrokeWidthSliderBarView = findViewById(R.id.lineWidth);47pointSettingSwitchView = findViewById(R.id.pointEnable);48findViewById(R.id.iv_back).setOnClickListener(this);49initData();50initBottomSheet();51}5253private void initData() {54polygonColorSelectorView.setTitle(getResources().getString(R.string.polygonColor));55polygonColorSelectorView.initColor(polygonColor);56polygonStrokeColorSelectorView.setTitle(getResources().getString(R.string.polygonStrokeColor));57polygonStrokeColorSelectorView.initColor(polygonStrokeColor);58polygonStrokeWidthSliderBarView.setTitle(getResources().getString(R.string.polygonStrokeWidth));59polygonStrokeWidthSliderBarView.initSeekBar(2, 0, 20, "px", 1);60pointSettingSwitchView.setTitle(getResources().getString(R.string.polygon_point_show));61pointSettingSwitchView.defaultValue(true);62polygonColorSelectorView.setOnColorChangedListener(new ColorSelectorView.OnColorChangedListener() {63@Override64public void onColorChanged(@NonNull String color) {65polygonColor = color;66if (polygon != null) {67polygon.setFillColor(Color.parseColor(color));68}69}70});71polygonStrokeColorSelectorView.setOnColorChangedListener(new ColorSelectorView.OnColorChangedListener() {72@Override73public void onColorChanged(@NonNull String color) {74polygonStrokeColor = color;75int colorHex = Color.parseColor(color);76if (polyline != null) {77polyline.setColor(colorHex);78}79}80});81polygonStrokeWidthSliderBarView.setOnSliderChangedListener(new SliderBarView.OnSliderChangedListener() {82@Override83public void onSliderChanged(float value) {84stockWidth = value;85if (polyline != null) {86polyline.setWidth(value);87}88}89});9091pointSettingSwitchView.setOnSwitchChangedLister(new SettingSwitchView.OnSwitchChangedLister() {92@Override93public void onSwitchChanged(boolean status) {94showPolygonVertex = status;95upDataMarkerBySwitchState();96}97});98}99100private void upDataMarkerBySwitchState() {101if (polygonMarkers == null || polygonMarkers.isEmpty()) {102return;103}104for (Marker marker : polygonMarkers) {105marker.setIcon(IconFactory.getInstance(PolygonActivity.this)106.fromResource((showPolygonVertex || polygonPoints.size() < 3) ? R.mipmap.ic_blue_dot : R.mipmap.ic_marker_transparent));107}108}109110private void onMapSync(NextbillionMap map) {111mMap = map;112addMapListener();113mMap.setStyle( Style.Builder().fromUri(StyleConstants.LIGHT))114}115116private void addMapListener() {117mMap.addOnMapLongClickListener(new NextbillionMap.OnMapLongClickListener() {118@Override119public boolean onMapLongClick(@NonNull LatLng latLng) {120polygonPoints.add(latLng);121MarkerOptions markerOptions = new MarkerOptions()122.setTitle(String.valueOf(polygonIndex))123.position(latLng)124.setIcon(IconFactory.getInstance(PolygonActivity.this)125.fromResource((showPolygonVertex || polygonPoints.size() < 3) ? R.mipmap.ic_blue_dot : R.mipmap.ic_marker_transparent));126polygonMarkers.add(mMap.addMarker(markerOptions));127polygonIndex ++;128if (polygonPoints.size() > 2) {129createPolygon();130}131return false;132}133});134mMap.addOnMapClickListener(new NextbillionMap.OnMapClickListener() {135@Override136public boolean onMapClick(@NonNull LatLng latLng) {137if (clickMarker != null) {138mMap.removeMarker(clickMarker);139}140clickMarker = mMap.addMarker(latLng);141Point clickPoint = new Point(latLng.getLongitude(),latLng.getLatitude());142List<Point> polygonLngLatPoints = new ArrayList<>();143for (LatLng point : polygonPoints) {144polygonLngLatPoints.add(new Point(point.getLongitude(),point.getLatitude()));145}146boolean isPointInPolygon = PolygonUtils.isPointInPolygon(clickPoint,PolygonUtils.getPolygon(true,polygonLngLatPoints));147if (isPointInPolygon) {148Toast.makeText(PolygonActivity.this, "this point is in polygon", Toast.LENGTH_SHORT).show();149}150return false;151}152});153mMap.addOnMoveListener(new NextbillionMap.OnMoveListener() {154@Override155public void onMoveBegin(@NonNull MoveGestureDetector moveGestureDetector) {156157}158159@Override160public void onMove(@NonNull MoveGestureDetector moveGestureDetector) {161162}163164@Override165public void onMoveEnd(@NonNull MoveGestureDetector moveGestureDetector) {166boolean isPolygonInScreen = checkPolygonVisibility();167if (isPolygonInScreen) {168fbNoticeButton.setBackgroundResource(R.drawable.shape_circle_40_purple_200);169} else {170fbNoticeButton.setBackgroundResource(R.drawable.shape_circle_40_md_grey_400);171}172}173});174mMap.setOnMarkerClickListener(new NextbillionMap.OnMarkerClickListener() {175@Override176public boolean onMarkerClick(@NonNull Marker marker) {177if (marker == clickMarker) {178mMap.removeMarker(clickMarker);179clickMarker = null;180}181return false;182}183});184}185186private boolean checkPolygonVisibility() {187if (mMap == null || mMap.getProjection() == null || latLngBounds == null) {188return false;189}190LatLngBounds isInScreen = mMap.getProjection().getVisibleRegion().latLngBounds.intersect(latLngBounds);191return isInScreen != null;192}193194private void cleanPolygon() {195if (mMap == null || polygon == null) {196Toast.makeText(PolygonActivity.this, "No polygon need remove", Toast.LENGTH_SHORT).show();197return;198}199mMap.removePolygon(polygon);200polygon = null;201polygonPoints.clear();202latLngBounds = null;203// polygon marker204for (Marker marker : polygonMarkers) {205mMap.removeMarker(marker);206}207polygonMarkers.clear();208209// line210if (polyline != null) {211mMap.removePolyline(polyline);212polyline = null;213}214}215216private void createPolygon() {217// check map218if (mMap == null) {219Toast.makeText(this, getResources().getString(R.string.waite_notice), Toast.LENGTH_SHORT).show();220return;221}222// check data223if (polygonPoints.isEmpty()) {224Toast.makeText(this, getResources().getString(R.string.polygon_empty_point_notice), Toast.LENGTH_SHORT).show();225return;226}227228if (polyline != null) {229mMap.removePolyline(polyline);230}231232if (polygon != null) {233mMap.removePolygon(polygon);234}235// update marker show style236upDataMarkerBySwitchState();237238// add polygon239latLngBounds = new LatLngBounds.Builder().includes(polygonPoints).build();240PolygonOptions polygonOptions = new PolygonOptions();241polygonOptions.addAll(polygonPoints)242.fillColor(Color.parseColor(polygonColor))243.strokeColor(Color.parseColor(polygonStrokeColor));244polygon = mMap.addPolygon(polygonOptions);245246// add polygon stroke by polyline247List<LatLng> polylinePoints = new ArrayList<>(polygonPoints);248polylinePoints.add(polygonPoints.get(0));249polylinePoints.add(polygonPoints.get(1));250PolylineOptions polylineOptions = new PolylineOptions()251.addAll(polylinePoints)252.color(Color.parseColor(polygonStrokeColor))253.width(stockWidth);254polyline = mMap.addPolyline(polylineOptions);255// change check button color256fbNoticeButton.setBackgroundResource(R.drawable.shape_circle_40_purple_200);257}258259private void initBottomSheet() {260bottomSheetBehavior = BottomSheetBehavior.from(findViewById(R.id.bottomSheet));261bottomSheetBehavior.setState(BottomSheetBehavior.STATE_EXPANDED);262bottomSheetBehavior.setPeekHeight((int) Utils.dpToPx(60));263bottomSheetBehavior.addBottomSheetCallback(new BottomSheetBehavior.BottomSheetCallback() {264@Override265public void onStateChanged(@NonNull View bottomSheet, int newState) {266if (newState == BottomSheetBehavior.STATE_HIDDEN) {267fbInfoFloatingActionButton.setVisibility(View.VISIBLE);268} else {269fbInfoFloatingActionButton.setVisibility(View.GONE);270}271}272273@Override274public void onSlide(@NonNull View bottomSheet, float slideOffset) {275276}277});278}279280///////////////////////////////////////////////////////////////////////////281// Lifecycle282///////////////////////////////////////////////////////////////////////////283284@Override285protected void onStart() {286super.onStart();287mapView.onStart();288}289290@Override291protected void onResume() {292super.onResume();293mapView.onResume();294}295296@Override297protected void onPause() {298super.onPause();299mapView.onPause();300}301302@Override303protected void onStop() {304super.onStop();305mapView.onStop();306}307308@Override309protected void onSaveInstanceState(@NonNull Bundle outState) {310super.onSaveInstanceState(outState);311mapView.onSaveInstanceState(outState);312}313314@Override315protected void onDestroy() {316super.onDestroy();317mapView.onDestroy();318}319320@Override321public void onLowMemory() {322super.onLowMemory();323mapView.onLowMemory();324}325326@Override327public void onClick(View v) {328if (v.getId() == R.id.fb_clean) {329cleanPolygon();330} else if (v.getId() == R.id.fb_expand) {331bottomSheetBehavior.setState(BottomSheetBehavior.STATE_EXPANDED);332} else if (v.getId() == R.id.fb_check) {333boolean isPolygonInScreen = checkPolygonVisibility();334String message = getResources().getString(R.string.polygin_visibility_notice);335if (!isPolygonInScreen) {336message = getResources().getString(R.string.polygon_invisibility_notice);337}338Toast.makeText(PolygonActivity.this, message, Toast.LENGTH_SHORT).show();339} else if (v.getId() == R.id.iv_back) {340finish();341}342}343}
initData
-
Initialises the data for the polygon activity.
-
Sets up various UI components such as color selectors, slider bars, and switch views. It also defines listeners for these components to handle user interactions and update the corresponding data values.
addMapListener
-
Adds listeners to the map.
-
Sets up event listeners for various map interactions such as long clicks, clicks, moves, and marker clicks. These listeners perform actions such as adding markers, creating polygons, checking polygon visibility, and removing markers and polygons.
checkPolygonVisibility
- Checks if the polygon is currently visible on the map. It relies on the map's projection and the bounds of the polygon to determine if the polygon is within the visible region of the map. It returns a boolean value indicating the visibility status of the polygon.
createPolygon
- Creates a polygon on the map. It checks if the necessary data, such as the map and polygon points, are available. It removes any existing polyline and polygon from the map. It updates the marker show style based on the switch state. Then it adds a polygon and a polyline to the map using the provided polygon points, colors, and stroke width.
cleanPolygon
- Removes the polygon and related markers from the map. It checks if the map and polygon are available and removes them from the map. It also clears the polygon points, marker list, and polyline if they exist.
These methods are part of the PolygonActivity class and are used to initialize and manage the polygon functionality in the corresponding Android activity.
The code also includes various lifecycle methods (onStart, onResume, onPause, onStop, onSaveInstanceState, onDestroy, onLowMemory) that should be implemented when using the MapView to properly manage its lifecycle and handle configuration changes.
Note: The code uses the Nextbillion Maps SDK, which provides map-related functionalities. It also utilizes the LatLng class to represent geography.