Restrict map panning
Android Examples App Available
This example code is part of the Maps SDK for Android Examples App, a working Android project available on GitHub. Android developers are encouraged to run the examples app locally to interact with this example in an emulator and explore other features of the Maps SDK.
See our Run the Maps SDK for Android Examples App tutorial for step-by-step instructions.
package com.mapbox.maps.testapp.examples.camera
import android.annotation.SuppressLint
import android.graphics.Color
import android.os.Bundle
import android.view.Gravity
import android.view.Menu
import android.view.MenuItem
import android.view.View
import android.widget.FrameLayout
import androidx.appcompat.app.AppCompatActivity
import com.mapbox.geojson.FeatureCollection
import com.mapbox.geojson.Point
import com.mapbox.geojson.Polygon
import com.mapbox.maps.CameraBoundsOptions
import com.mapbox.maps.CoordinateBounds
import com.mapbox.maps.MapboxMap
import com.mapbox.maps.Style
import com.mapbox.maps.extension.style.sources.generated.GeoJsonSource
import com.mapbox.maps.extension.style.sources.generated.geoJsonSource
import com.mapbox.maps.extension.style.sources.getSource
import com.mapbox.maps.extension.style.style
import com.mapbox.maps.testapp.R
import com.mapbox.maps.testapp.databinding.ActivityRestrictBoundsBinding
/**
* Test activity showcasing restricting user gestures to a bounds around Iceland, almost worldview and IDL.
*/
class RestrictBoundsActivity : AppCompatActivity() {
private lateinit var mapboxMap: MapboxMap
private lateinit var binding: ActivityRestrictBoundsBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityRestrictBoundsBinding.inflate(layoutInflater)
setContentView(binding.root)
mapboxMap = binding.mapView.mapboxMap
mapboxMap.loadStyle(
style(Style.STANDARD) {
+geoJsonSource(BOUNDS_ID) {
featureCollection(FeatureCollection.fromFeatures(listOf()))
}
}
) { setupBounds(SAN_FRANCISCO_BOUND) }
showCrosshair()
}
override fun onCreateOptionsMenu(menu: Menu): Boolean {
menuInflater.inflate(R.menu.menu_bounds, menu)
return true
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
return when (item.itemId) {
R.id.menu_action_san_francisco_bounds -> {
setupBounds(SAN_FRANCISCO_BOUND)
true
}
R.id.menu_action_allmost_world_bounds -> {
setupBounds(ALMOST_WORLD_BOUNDS)
true
}
R.id.menu_action_cross_idl -> {
setupBounds(CROSS_IDL_BOUNDS)
true
}
R.id.menu_action_reset -> {
setupBounds(INFINITE_BOUNDS)
true
}
else -> {
super.onOptionsItemSelected(item)
}
}
}
private fun setupBounds(bounds: CameraBoundsOptions) {
mapboxMap.getStyle { style ->
mapboxMap.setBounds(bounds)
showBoundsArea(bounds, style)
}
}
private fun showBoundsArea(boundsOptions: CameraBoundsOptions, style: Style) {
val source = style.getSource(BOUNDS_ID) as GeoJsonSource
val bounds = boundsOptions.bounds
val list = mutableListOf<List<Point>>()
bounds?.let {
if (!it.infiniteBounds) {
val northEast = it.northeast
val southWest = it.southwest
val northWest = Point.fromLngLat(southWest.longitude(), northEast.latitude())
val southEast = Point.fromLngLat(northEast.longitude(), southWest.latitude())
list.add(
mutableListOf(northEast, southEast, southWest, northWest, northEast)
)
}
}
if (list.isNotEmpty()) {
source.geometry(
Polygon.fromLngLats(
list
)
)
}
}
private fun showCrosshair() {
val crosshair = View(this)
crosshair.layoutParams = FrameLayout.LayoutParams(10, 10, Gravity.CENTER)
crosshair.setBackgroundColor(Color.BLUE)
binding.mapView.addView(crosshair)
}
companion object {
private const val BOUNDS_ID = "BOUNDS_ID"
private val SAN_FRANCISCO_BOUND: CameraBoundsOptions = CameraBoundsOptions.Builder()
.bounds(
CoordinateBounds(
Point.fromLngLat(-122.66336, 37.492987),
Point.fromLngLat(-122.250481, 37.87165),
false
)
)
.minZoom(10.0)
.build()
private val ALMOST_WORLD_BOUNDS: CameraBoundsOptions = CameraBoundsOptions.Builder()
.bounds(
CoordinateBounds(
Point.fromLngLat(-170.0, -20.0),
Point.fromLngLat(170.0, 20.0),
false
)
)
.minZoom(2.0)
.build()
@SuppressLint("Range")
private val CROSS_IDL_BOUNDS: CameraBoundsOptions = CameraBoundsOptions.Builder()
.bounds(
CoordinateBounds(
Point.fromLngLat(170.0202020, -20.0),
Point.fromLngLat(190.0, 20.0),
false
)
)
.minZoom(2.0)
.build()
private val INFINITE_BOUNDS: CameraBoundsOptions = CameraBoundsOptions.Builder()
.bounds(
CoordinateBounds(
Point.fromLngLat(0.0, 0.0),
Point.fromLngLat(0.0, 0.0),
true
)
)
.build()
}
}
Was this example helpful?