Multiple Surfaces in Fragment Recycler¶
In this guide you will learn how to add/remove
multiple fragment surfaces, each of which can contain
an interactive map centered on a different desired location.
The maps are fully 3D, supporting pan, pinch-zoom, rotate and tilt.
Setup¶
First, get an API key token, see the Getting Started guide.
Download the Maps & Navigation SDK for Android archive fileDownload the MultipleSurfacesInFragmentRecycler 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 NEXT to go to the second screen
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 or zoom each map.
Click the red - in the lower left corner to remove the last added fragment.
Click PREVIOUS to go back to the first screen.
How it works¶
You can open the MainActivity.kt file to see how to render multiple maps, and add or remove maps.
1class FirstFragment : Fragment()
2{
3 override fun onCreateView(
4 inflater: LayoutInflater, container: ViewGroup?,
5 savedInstanceState: Bundle?
6 ): View? {
7 return inflater.inflate(R.layout.fragment_first, container, false)
8 }
9 override fun onViewCreated(view: View, savedInstanceState: Bundle?)
10 {
11 super.onViewCreated(view, savedInstanceState)
12 view.findViewById<Button>(R.id.button_first).setOnClickListener
13 {
14 findNavController().navigate(R.id.action_FirstFragment_to_SecondFragment)
15 }
16 }
17}
The first fragment. When the first fragment instantiation is complete, a click listener is added to the button to go to the second fragment.
1override fun onCreateView(
2 inflater: LayoutInflater, container: ViewGroup?,
3 savedInstanceState: Bundle?
4 ): View? {
5 return inflater.inflate(R.layout.fragment_second, container, false)
6 }
7 override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
8 super.onViewCreated(view, savedInstanceState)
9 view.findViewById<Button>(R.id.button_second).setOnClickListener {
10 findNavController().navigate(R.id.action_SecondFragment_to_FirstFragment)
11 }
12 recycler = view.findViewById<RecyclerView>(R.id.list).apply {
13 itemAnimator = null
14 layoutManager = LinearLayoutManager(requireContext())
15 adapter = CustomAdapter(list)
16 }
17 val leftBtn = view.findViewById<FloatingActionButton>(R.id.bottomLeftButton)
18 leftBtn.visibility = View.VISIBLE
19 buttonAsDelete(requireContext(), leftBtn) {
20 deleteLastSurface()
21 }
22 val rightBtn = view.findViewById<FloatingActionButton>(R.id.bottomRightButton)
23 rightBtn.visibility = View.VISIBLE
24 buttonAsAdd(requireContext(), rightBtn) {
25 addSurface()
26 }
27}
The second fragment.
Each of the 2 fragments has a button to navigate to the other fragment,
see res/navigation/nav_graph.xml in the project.
1private fun addSurface() {
2 if (list.size >= maxSurfacesCount) {
3 return
4 }
5 list.add(list.lastIndex + 1)
6 recycler.adapter?.notifyItemInserted(list.lastIndex)
7 }
8 private fun deleteLastSurface() {
9 if (list.size == 0) return
10 list.removeLast()
11 recycler.adapter?.notifyItemRemoved(list.lastIndex + 1)
12 }
13 private fun buttonAsAdd(context: Context, button: FloatingActionButton?, action: () -> Unit) {
14 button ?: return
15 val tag = "add"
16 val backgroundTintList =
17 AppCompatResources.getColorStateList(context, R.color.green)
18 val drawable = ContextCompat.getDrawable(context, android.R.drawable.ic_input_add)
19 button.tag = tag
20 button.setOnClickListener { action() }
21 button.setImageDrawable(drawable)
22 button.backgroundTintList = backgroundTintList
23 }
24 private fun buttonAsDelete(
25 context: Context,
26 button: FloatingActionButton?,
27 action: () -> Unit
28 ) {
29 button ?: return
30 val tag = "delete"
31 val backgroundTintList =
32 AppCompatResources.getColorStateList(context, R.color.red)
33 val drawable = ContextCompat.getDrawable(context, android.R.drawable.ic_delete)
34 button.tag = tag
35 button.setOnClickListener { action() }
36 button.setImageDrawable(drawable)
37 button.backgroundTintList = backgroundTintList
38 }
The
SecondFragment
also has a green + and a red x button to add or
remove maps, respectively, using the addSurface()
and
deleteLastSurface()
functions. 1class CustomAdapter(private val dataSet: ArrayList<Int>) :
2 RecyclerView.Adapter<CustomAdapter.ViewHolder>() {
3 class ViewHolder(view: View) : RecyclerView.ViewHolder(view)
4 override fun onCreateViewHolder(viewGroup: ViewGroup, viewType: Int): ViewHolder {
5 val view = LayoutInflater.from(viewGroup.context)
6 .inflate(R.layout.map_layout, viewGroup, false)
7 val result = ViewHolder(view)
8 result.setIsRecyclable(false)
9 return result
10 }
11 override fun getItemCount() = dataSet.size
12 override fun onBindViewHolder(viewHolder: ViewHolder, position: Int) = Unit
13}
The
SecondFragment
has a custom adapter container
where the maps are stored. 1class MainActivity : AppCompatActivity() {
2 override fun onCreate(savedInstanceState: Bundle?) {
3 super.onCreate(savedInstanceState)
4 setContentView(R.layout.activity_main)
5 }
6 override fun onDestroy() {
7 super.onDestroy()
8 // Deinitialize the SDK.
9 GemSdk.release()
10 }
11 override fun onBackPressed() {
12 finish()
13 }
14}
MainActivity
overrides the onCreate()
function and sets
the initial screen to setContentView(R.layout.activity_main)
where activity_main`` is defined in res/layout
in the
project. This is the first fragment above, which has the
NEXT button to go to the second fragment where the maps and
red and green buttons are shown.