Skip to main content
GuidesAPI ReferenceExamples

Multiple Surfaces

Estimated reading time: 5 minutes

In this guide you will learn how to render an interactive map centered on a desired location. The map is fully 3D, supporting pan, pinch-zoom, rotate and tilt.

Setup

  1. Get your Magic Lane API key token: if you do not have a token, see the Getting Started guide.
  2. Download the Maps & Navigation SDK for Android archive file.
  3. Download the HelloFragment project archive file or clone the project with git.
  4. See the Configure Android Example guide.

Run the example

In Android Studio, from the File menu, select Sync Project with Gradle Files.



  1. An android device should be connected via USB cable.
  2. Press SHIFT+F10 to compile, install and run the example on the android device.
  3. Click the envelope in the lower right corner to continue.
  4. Click NEXT
  5. Click the green + in the lower right corner to add a fragment with a map. Each map can show a different location. Try to pan and zoom each map.
  6. Click the red - in the lower left corner to remove the last added fragment.

How it works

You can open the MainActivity.kt file to see how to render multiple maps.

How it works

// Kotlin code

class FirstFragment : Fragment()
{
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
return inflater.inflate(R.layout.fragment_first, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?)
{
super.onViewCreated(view, savedInstanceState)
view.findViewById<Button>(R.id.button_first).setOnClickListener
{
findNavController().navigate(R.id.action_FirstFragment_to_SecondFragment)
}
}
}

The first fragment.
Each of the 2 fragments has a button to navigate to the other fragment, see app/res/navigation/nav_graph.xml in the project. In onViewCreated(), a click listener is set for the button to go to the second fragment, as defined in app/res/layout/fragment_first.xml file in this project.

class SecondFragment : Fragment()
{
private val maps = mutableMapOf<Long, MapView?>()
private val maxSurfacesCount = 9
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
return inflater.inflate(R.layout.fragment_second, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?)
{
super.onViewCreated(view, savedInstanceState)
view.findViewById<Button>(R.id.button_second).setOnClickListener
{
findNavController().navigate(R.id.action_SecondFragment_to_FirstFragment)
}
val leftBtn = view.findViewById<FloatingActionButton>(R.id.bottomLeftButton)
leftBtn.visibility = View.VISIBLE
ButtonsDecorator.buttonAsDelete(requireContext(), leftBtn)
{
deleteLastSurface()
}
val rightBtn = view.findViewById<FloatingActionButton>(R.id.bottomRightButton)
rightBtn.visibility = View.VISIBLE
ButtonsDecorator.buttonAsAdd(requireContext(), rightBtn)
{
addSurface()
}
addSurface()
}

The second fragment.
Each of the 2 fragments has a button to navigate to the other fragment, see app/res/navigation/nav_graph.xml in the project. In onViewCreated(), a click listener is set for the button to go to the first fragment, as defined in app/res/layout/fragment_second.xml file in this project.

private fun buttonAsAdd(context: Context,
button: FloatingActionButton?, action: () -> Unit) {
button ?: return
val tag = "add"
val backgroundTintList =
AppCompatResources.getColorStateList(context, R.color.green)
val drawable = ContextCompat.getDrawable(context, android.R.drawable.ic_input_add)
button.tag = tag
button.setOnClickListener { action() }
button.setImageDrawable(drawable)
button.backgroundTintList = backgroundTintList
}
private fun buttonAsDelete(
context: Context,
button: FloatingActionButton?,
action: () -> Unit
) {
button ?: return
val tag = "delete"
val backgroundTintList =
AppCompatResources.getColorStateList(context, R.color.red)
val drawable = ContextCompat.getDrawable(context, android.R.drawable.ic_delete)
button.tag = tag
button.setOnClickListener { action() }
button.setImageDrawable(drawable)
button.backgroundTintList = backgroundTintList
}

The SecondFragment also has a green + and a red x button to add or remove maps, respectively, using the addSurface() and deleteLastSurface() functions.

 private fun addSurface()
{
val linearLayout = view?.findViewById<LinearLayout>(R.id.scrolledLinearLayout) ?: return
if (linearLayout.childCount >= maxSurfacesCount)
{
return
}
val surface = GemSurfaceView(requireContext())
surface?.layoutParams = ViewGroup.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT
)
surface.onDefaultMapViewCreated = onDefaultMapViewCreated@{
val screen = surface.gemScreen ?: return@onDefaultMapViewCreated
// Add the map view to the collection of displayed maps.
maps[screen.address] = it
}
val params = FrameLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, 400)
params.setMargins(50)
val frame = FrameLayout(requireContext())
frame.layoutParams = params
frame.addView(surface)
linearLayout.addView(frame)
}
private fun deleteLastSurface()
{
val linearLayout = view?.findViewById<LinearLayout>(R.id.scrolledLinearLayout) ?: return
if (linearLayout.childCount == 0)
return
val lastIndex = linearLayout.childCount - 1
val frame = (linearLayout[lastIndex] as FrameLayout)
val lastSurface = frame[0] as GemSurfaceView
SdkCall.execute
{
val mapsId = lastSurface.getScreen()?.address()
// Release the map view.
maps[mapsId]?.release()
// Remove the map view from the collection of displayed maps.
maps.remove(mapsId)
}
linearLayout.removeView(frame)
}
}

The addSurface() function adds a map to the new surface, and also stores the map in a map container, like a list, to enable removing it later:

  • val mapView = MapView.produce(screen, mainViewRect)
  • maps[screen.address()] = mapView

The deleteLastSurface() function deletes the current map and removes it from the map container/list.

  • val mapsId = lastSurface.getScreen()?.address()
  • maps[mapsId]?.release()
  • maps.remove(mapsId)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
}

MainActivity overrides the onCreate() which loads the first fragment, as defined in app/res/layout/activity_main.xml file in this project.

Android Examples

Maps SDK for Android Examples can be downloaded or cloned with Git.