Multiple Surfaces ¶
Setup ¶
First, get an API key token, see the Getting Started guide.
Download the Maps & Navigation SDK for Android archive file
Download the
MultipleSurfacesInFragment
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
|
|
|
|
Click NEXT
Click the green + in the lower right corner to add a fragment with a map.
How it works ¶

You can open the MainActivity.kt file to see how to render multiple maps.
1// Kotlin code
2
3class FirstFragment : Fragment()
4{
5 override fun onCreateView(
6 inflater: LayoutInflater, container: ViewGroup?,
7 savedInstanceState: Bundle?
8 ): View? {
9 return inflater.inflate(R.layout.fragment_first, container, false)
10 }
11 override fun onViewCreated(view: View, savedInstanceState: Bundle?)
12 {
13 super.onViewCreated(view, savedInstanceState)
14 view.findViewById<Button>(R.id.button_first).setOnClickListener
15 {
16 findNavController().navigate(R.id.action_FirstFragment_to_SecondFragment)
17 }
18 }
19}
app/res/navigation/nav_graph.xml
in the project.
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.
1class SecondFragment : Fragment()
2{
3 private val maps = mutableMapOf<Long, MapView?>()
4 private val maxSurfacesCount = 9
5 override fun onCreateView(
6 inflater: LayoutInflater, container: ViewGroup?,
7 savedInstanceState: Bundle?
8 ): View? {
9 return inflater.inflate(R.layout.fragment_second, container, false)
10 }
11 override fun onViewCreated(view: View, savedInstanceState: Bundle?)
12 {
13 super.onViewCreated(view, savedInstanceState)
14 view.findViewById<Button>(R.id.button_second).setOnClickListener
15 {
16 findNavController().navigate(R.id.action_SecondFragment_to_FirstFragment)
17 }
18 val leftBtn = view.findViewById<FloatingActionButton>(R.id.bottomLeftButton)
19 leftBtn.visibility = View.VISIBLE
20 ButtonsDecorator.buttonAsDelete(requireContext(), leftBtn)
21 {
22 deleteLastSurface()
23 }
24 val rightBtn = view.findViewById<FloatingActionButton>(R.id.bottomRightButton)
25 rightBtn.visibility = View.VISIBLE
26 ButtonsDecorator.buttonAsAdd(requireContext(), rightBtn)
27 {
28 addSurface()
29 }
30 addSurface()
31 }
app/res/navigation/nav_graph.xml
in the project.
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.
1private fun buttonAsAdd(context: Context,
2 button: FloatingActionButton?, action: () -> Unit) {
3 button ?: return
4 val tag = "add"
5 val backgroundTintList =
6 AppCompatResources.getColorStateList(context, R.color.green)
7 val drawable = ContextCompat.getDrawable(context, android.R.drawable.ic_input_add)
8 button.tag = tag
9 button.setOnClickListener { action() }
10 button.setImageDrawable(drawable)
11 button.backgroundTintList = backgroundTintList
12 }
13 private fun buttonAsDelete(
14 context: Context,
15 button: FloatingActionButton?,
16 action: () -> Unit
17 ) {
18 button ?: return
19 val tag = "delete"
20 val backgroundTintList =
21 AppCompatResources.getColorStateList(context, R.color.red)
22 val drawable = ContextCompat.getDrawable(context, android.R.drawable.ic_delete)
23 button.tag = tag
24 button.setOnClickListener { action() }
25 button.setImageDrawable(drawable)
26 button.backgroundTintList = backgroundTintList
27}
SecondFragment
also has a green + and a red x button to add or
remove maps, respectively, using the
addSurface()
and
deleteLastSurface()
functions.
1 private fun addSurface()
2 {
3 val linearLayout = view?.findViewById<LinearLayout>(R.id.scrolledLinearLayout) ?: return
4 if (linearLayout.childCount >= maxSurfacesCount)
5 {
6 return
7 }
8 val surface = GemSurfaceView(requireContext())
9 surface?.layoutParams = ViewGroup.LayoutParams(
10 ViewGroup.LayoutParams.MATCH_PARENT,
11 ViewGroup.LayoutParams.MATCH_PARENT
12 )
13 surface.onDefaultMapViewCreated = onDefaultMapViewCreated@{
14 val screen = surface.gemScreen ?: return@onDefaultMapViewCreated
15 // Add the map view to the collection of displayed maps.
16 maps[screen.address] = it
17 }
18 val params = FrameLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, 400)
19 params.setMargins(50)
20 val frame = FrameLayout(requireContext())
21 frame.layoutParams = params
22 frame.addView(surface)
23 linearLayout.addView(frame)
24 }
25 private fun deleteLastSurface()
26 {
27 val linearLayout = view?.findViewById<LinearLayout>(R.id.scrolledLinearLayout) ?: return
28 if (linearLayout.childCount == 0)
29 return
30 val lastIndex = linearLayout.childCount - 1
31 val frame = (linearLayout[lastIndex] as FrameLayout)
32 val lastSurface = frame[0] as GemSurfaceView
33 SdkCall.execute
34 {
35 val mapsId = lastSurface.getScreen()?.address()
36 // Release the map view.
37 maps[mapsId]?.release()
38 // Remove the map view from the collection of displayed maps.
39 maps.remove(mapsId)
40 }
41 linearLayout.removeView(frame)
42 }
43}
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
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)
1override fun onCreate(savedInstanceState: Bundle?) {
2 super.onCreate(savedInstanceState)
3 setContentView(R.layout.activity_main)
4}
MainActivity
overrides the
onCreate()
which loads the first
fragment, as defined in
app/res/layout/activity_main.xml
file in this project.