Android Google Maps Load SupportMapFragment in AlertDialog DialogFragment (Kotlin)

July 23, 2018

LocationPickerDialog

  • Include Intent to pass lat, lng for marker position
  • Implement AlertDialog with onOk and onCancel listener
  • Add SupportMapFragment dynamically, else map is not loaded when dialog open for the second time.
class LocationPickerDialog : DialogFragment() {
    companion object {
        private const val TAG = "LocationPickerDialog"

        private const val EXTRA_LAT = "lat"
        private const val EXTRA_LNG = "lng"

        private const val DEFAULT_ZOOM = 15f

        fun newInstance(lat: Double? = null, lng: Double? = null): LocationPickerDialog {
            val dialog = LocationPickerDialog()
            val args = Bundle().apply {
                lat?.let { putDouble(EXTRA_LAT, it) }
                lng?.let { putDouble(EXTRA_LNG, it) }
            }
            dialog.arguments = args
            return dialog
        }
    }

    lateinit var customView: View
    private var mapFragment: SupportMapFragment? = null
    private var googleMap: GoogleMap? = null

    private val okButton: Button by lazy {
        (dialog as AlertDialog).getButton(AlertDialog.BUTTON_POSITIVE)
    }
    private val cancelButton: Button by lazy {
        (dialog as AlertDialog).getButton(AlertDialog.BUTTON_NEGATIVE)
    }

    onOk: (() -> Unit)? = null
    onCancel: (() -> Unit)? = null


    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
        return customView
    }

    override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
        // StackOverflowError
        // customView = layoutInflater.inflate(R.layout.dialog_edit_text, null)
        customView = activity!!.layoutInflater.inflate(R.layout.dialog_location_picker, null)

        val builder = AlertDialog.Builder(context!!)
                .setView(customView)
                .setPositiveButton(android.R.string.ok, null)
                .setNegativeButton(android.R.string.cancel, null)
        val dialog = builder.create()

        return dialog
    }

    override fun onStart() {
        super.onStart()

        okButton.setOnClickListener {
            onOk?.invoke()
        }

        cancelButton.setOnClickListener {
            onCancel?.invoke()
        }

        okButton.isEnabled = false
        cancelButton.isEnabled = false
    }

    override fun onActivityCreated(savedInstanceState: Bundle?) {
        super.onActivityCreated(savedInstanceState)

        // if onCreateView didn't return view
        // java.lang.IllegalStateException: Fragment does not have a view
        mapFragment = childFragmentManager.findFragmentByTag("map") as SupportMapFragment?
        if (mapFragment == null) {
            Log.d(TAG, "SupportMapFragment.newInstance")
            mapFragment = SupportMapFragment.newInstance()
            childFragmentManager.beginTransaction().replace(R.id.map, mapFragment, "map").commit()
        }


        mapFragment?.let { mapFragment ->
            mapFragment.getMapAsync { map ->
                googleMap = map

                map.setOnMapLoadedCallback {

                    val lat = arguments?.getDouble(EXTRA_LAT)
                    val lng = arguments?.getDouble(EXTRA_LNG)
      

                    if (lat != null && lng != null) {
                        val latLng = LatLng(lat, lng)

                        map.addMarker(MarkerOptions()
                                .position(latLng)
                                )

                        map.moveCamera(CameraUpdateFactory.newLatLngZoom(latLng, DEFAULT_ZOOM))
                    }
                }
            }
        }
    }
}

Layout

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    xmlns:app="http://schemas.android.com/apk/res-auto">


    <FrameLayout
        android:id="@+id/map"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

    <!--
    <fragment
        android:id="@+id/map"
        android:visibility="gone"
        android:name="com.google.android.gms.maps.SupportMapFragment"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        />
        -->

</RelativeLayout>

Show dialog

val dialog = LocationPickerDialog.newInstance(lat, lng)

dialog.onOK {
    // do something
    dialog.dismiss()
}

dialog.show(supportFragmentManager, "editLocation")
This work is licensed under a
Creative Commons Attribution-NonCommercial 4.0 International License.