Kotlin+Firebase:点击地图Marker时在BottomSheet展示对应数据
实现方案
核心思路
通过Google Map Marker自带的tag属性绑定对应任务的唯一标识postid,点击Marker时将postid传入BottomSheet,再通过该标识查询Firebase对应数据渲染UI即可。
步骤1:修正导包错误
你当前代码导入了错误的Marker类,先替换导包:
// 删除错误导包 // import com.airbnb.lottie.model.Marker // 导入地图Marker类 import com.google.android.gms.maps.model.Marker
步骤2:给Marker绑定postid
在添加Marker的逻辑中,将任务的postid存入Marker的tag属性:
dbref.addValueEventListener(object : ValueEventListener { override fun onDataChange(snapshot: DataSnapshot) { if (snapshot.exists()) { for (missionSnapshot in snapshot.children) { val lat: String = missionSnapshot.child("latitude").value.toString() val lng: String = missionSnapshot.child("longitude").value.toString() val latitude = lat.toDouble() val longitude = lng.toDouble() val loc = LatLng(latitude, longitude) val idMission = missionSnapshot.child("postid").value.toString() // 接收addMarker返回的Marker对象 val marker = googleMap.addMarker( MarkerOptions().position(loc) .title(idMission).icon( BitmapDescriptorFactory.fromResource(R.drawable.pinroll)) ) // 绑定postid到Marker marker?.tag = idMission } } } override fun onCancelled(error: DatabaseError) { TODO("Not yet implemented") } })
步骤3:点击Marker时传参到BottomSheet
修改Marker点击监听逻辑,将绑定的postid传入BottomSheet:
googleMap.setOnMarkerClickListener(GoogleMap.OnMarkerClickListener { marker -> // 取出Marker绑定的postid val postId = marker.tag?.toString() ?: return@OnMarkerClickListener false // 通过newInstance方法传参创建BottomSheet实例 val bottomSheet = BottomsheetMissionMap.newInstance(postId) bottomSheet.show(requireFragmentManager(), "BottomSheet") false })
步骤4:BottomSheet接收参数并查询渲染数据
你的BottomsheetMissionMap实现参考如下:
class BottomsheetMissionMap : BottomSheetDialogFragment() { private lateinit var dbRef: DatabaseReference companion object { // 传参key常量 private const val ARG_POST_ID = "post_id" // 统一实例创建方法,封装传参逻辑 fun newInstance(postId: String): BottomsheetMissionMap { val args = Bundle() args.putString(ARG_POST_ID, postId) val fragment = BottomsheetMissionMap() fragment.arguments = args return fragment } } override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? ): View? { // 替换为你自己的BottomSheet布局id return inflater.inflate(R.layout.bottom_sheet_mission, container, false) } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) // 获取传入的postid val postId = arguments?.getString(ARG_POST_ID) ?: return dbRef = FirebaseDatabase.getInstance().getReference("Mission") // 查询对应postid的任务数据 dbRef.orderByChild("postid").equalTo(postId) .addListenerForSingleValueEvent(object : ValueEventListener { override fun onDataChange(snapshot: DataSnapshot) { if (snapshot.exists()) { for (missionSnap in snapshot.children) { // 取出字段赋值到布局控件,示例如下,替换为你自己的字段和控件id val missionTitle = missionSnap.child("title").value.toString() val missionDesc = missionSnap.child("description").value.toString() val missionPoint = missionSnap.child("point").value.toString() view.findViewById<TextView>(R.id.tv_mission_title).text = missionTitle view.findViewById<TextView>(R.id.tv_mission_desc).text = missionDesc view.findViewById<TextView>(R.id.tv_mission_point).text = "${missionPoint}积分" // 其余字段同理赋值即可 } } } override fun onCancelled(error: DatabaseError) { // 按需添加查询失败的处理逻辑 } }) } }
可选优化
如果不想每次点击Marker都查询数据库,可以提前在MapFragment中定义一个mutableMapOf<String, Mission>(),遍历Firebase数据时将所有任务数据存入Map,点击时直接取出对应Mission对象,通过Parcelable序列化后传给BottomSheet,减少数据库请求次数。
参考图示
- Mission数据库结构:

- BottomSheet展示效果:

内容的提问来源于stack exchange,提问作者Yam Re
相关产品推荐
相关产品推荐

