Multiple Surfaces
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
- Get your Magic Lane API key token: if you do not have a token, see the Getting Started guide.
- Download the Maps & Navigation SDK for Android archive file.
- Download the HelloFragment project archive file or clone the project with git.
- See the Configure Android Example guide.
Run the example
In Android Studio, from the File
menu, select Sync Project with Gradle Files
.




- An android device should be connected via USB cable.
- Press
SHIFT+F10
to compile, install and run the example on the android device. - Click the envelope in the lower right corner to continue.
- Click NEXT
- 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. - 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.
// 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.