有没有办法在 android 中的底部 Sheet 对话框中创建多 Select 对话框

Is there a way to create Multi Select Dialog inside a Bottom Sheet Dialog in android

我正在尝试将我的对话框移动到底部 sheet 对话框。但我面临的问题是底部 sheet 对话框没有像警报对话框中那样的生成器,看起来是这样。我也找不到底部的多选对话框sheet。

val dialogBuilder = MaterialAlertDialogBuilder(this)
    dialogBuilder.setTitle(title)
    dialogBuilder.setCancelable(false)
    dialogBuilder.background =
        AppCompatResources.getDrawable(this, R.drawable.bg_white_round_red_ripple)
    dialogBuilder.setMultiChoiceItems(
        StringArray, booleanArray
    ) { _, i, b ->
        if (b) {
            integerArrayList.add(i)
            integerArrayList.sort()
        } else {
            integerArrayList.remove(i)
        }
        
    }
    dialogBuilder.setPositiveButton("OK") { dialog, which ->
        val stringBuilder = StringBuilder()
        if (integerArrayList.size > 0) {
            for (j in 0 until integerArrayList.size) {
                stringBuilder.append(StringArray[integerArrayList[j]])
                if (j != integerArrayList.size - 1) {
                    stringBuilder.append(", ")
                }
            }
            textView.text = stringBuilder.toString()
        } else {
            textView.text = title
        }
    }
    dialogBuilder.setNegativeButton(
        "Cancel"
    ) { dialogInterface, _ -> // dismiss dialog
        dialogInterface.dismiss()
    }
    val alertDialog = dialogBuilder.create()

    alertDialog.show()

有没有办法在底部 sheet 中执行此操作,或者我是否必须创建一个行为如下的自定义底部 sheet?有样式解决方案吗?

很多天后,我决定从头开始制作一个带有底部 Sheet 的自定义 multiSelectDialog。

@AndroidEntryPoint
class MultiSelectDialog (private val title: String?,
                         private val list: ArrayList<String>,
                         private var selectedItems: SparseBooleanArray,
                         val returnVal: (selectedItems: SparseBooleanArray) -> Unit
) : BottomSheetDialogFragment(), MultiSelectDialogListener {

    private var _binding: DialogMultiSelectBinding? = null
    private val binding get() = _binding!!
    val viewModel: MultiSelectDialogViewModel by viewModels()

    private lateinit var adapter : MultiSelectDialogRecyclerViewAdapter

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        _binding = DialogMultiSelectBinding.inflate(inflater, container, false)
        return binding.root
    }
    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        binding.viewmodel = viewModel
        viewModel.multiSelectDialogListener = this
        binding.rvCheckList.layoutManager = LinearLayoutManager(requireContext())
        init()
    }

    private fun populateRecyclerView() {
        adapter = MultiSelectDialogRecyclerViewAdapter(requireContext(), list, selectedItems,
            object : MultiSelectDialogRecyclerViewAdapter.OnItemClickListener{
                override fun onItemClick(isCheckedList: SparseBooleanArray, position: Int) {
                    selectedItems = isCheckedList
                }
            })
        binding.rvCheckList.adapter = adapter
    }

    private fun init(){
        populateRecyclerView()
        if (!title.isNullOrEmpty()) {
            binding.tvTitle.visibility = View.VISIBLE
            viewModel.title = title
        }
        else{
            binding.tvTitle.visibility = View.GONE
        }

        dialog?.setOnKeyListener { _, keyCode, _ ->
            if (keyCode == KeyEvent.KEYCODE_BACK) {
                if (dialog!!.isShowing) {
                    dialog!!.cancel()
                }
            }
            true
        }
    }

    override fun onPositiveClick() {
        returnVal(selectedItems)
        dialog?.dismiss()
    }

    override fun onNegativeClick() {
        dialog?.cancel()
    }

    override fun onNeutralClick() {
        selectedItems.clear()
        adapter.setData(selectedItems)
    }

    override fun onCheckedChangedListener() {
        requireView().snackbar("Items Changed")
    }
    override fun getTheme(): Int {
        return R.style.AppBottomSheetDialogTheme
    }

}

这个视图模型是

@HiltViewModel
class MultiSelectDialogViewModel @Inject constructor() : ViewModel() {
    var title: String? = null
    var multiSelectDialogListener: MultiSelectDialogListener? = null

    fun onPositiveClick(view: View) {
        multiSelectDialogListener?.onPositiveClick()
    }
    fun onNegativeClick(view: View) {
        multiSelectDialogListener?.onNegativeClick()
    }
    fun onNeutralClick(view: View) {
        multiSelectDialogListener?.onNeutralClick()
    }
    fun onSelectedItemsChanged(){
        multiSelectDialogListener?.onCheckedChangedListener()
    }
}

也是听众

interface MultiSelectDialogListener {
    fun onPositiveClick()
    fun onNegativeClick()
    fun onNeutralClick()
    fun onCheckedChangedListener()
}

回收器视图适配器

class MultiSelectDialogRecyclerViewAdapter(
    val context: Context,
    private var arrayList: ArrayList<String>,
    private var isCheckedList: SparseBooleanArray,
    private var onItemClickListener: OnItemClickListener
    ):
RecyclerView.Adapter<MultiSelectDialogRecyclerViewAdapter.ViewHolder>(){

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
        val v = LayoutInflater.from(parent.context)
            .inflate(R.layout.item_check_box_list_dialog, parent, false)
        return ViewHolder(v)
    }

    override fun onBindViewHolder(holder: ViewHolder, position: Int) {
        holder.bind(position)
    }

    override fun getItemCount(): Int {
        return arrayList.size
    }

    fun setData(mIsCheckedList: SparseBooleanArray) {
        isCheckedList = mIsCheckedList
        notifyDataSetChanged()
    }

    inner class ViewHolder internal constructor(itemView: View): RecyclerView.ViewHolder(itemView)
    {
        val checkbox_list_dialog: MaterialCheckBox by lazy { itemView.findViewById<MaterialCheckBox>(R.id.checkbox_list_dialog) }
        val btn_positive: Button by lazy { itemView.findViewById<Button>(R.id.btn_positive) }
        val btn_negative: Button by lazy { itemView.findViewById<Button>(R.id.btn_negative) }
        val btn_neutral: Button by lazy { itemView.findViewById<Button>(R.id.btn_neutral) }
        val cl_multi_select_dialog_root: ConstraintLayout by lazy { itemView.findViewById<ConstraintLayout>(R.id.cl_multi_select_dialog_root) }
        init {
            checkbox_list_dialog.setOnClickListener{
                onClick(it)
            }
        }
        fun bind(position: Int) {
            // use the sparse boolean array to check
            checkbox_list_dialog.isChecked = isCheckedList.get(position, false)
            checkbox_list_dialog.text = arrayList[position]
        }
        fun onClick(v: View?) {
            val adapterPosition = absoluteAdapterPosition
            if (!isCheckedList.get(adapterPosition, false)) {
                checkbox_list_dialog.isChecked = true
                isCheckedList.put(adapterPosition, true)
            } else {
                checkbox_list_dialog.isChecked = false
                isCheckedList.put(adapterPosition, false)
            }
            onItemClickListener.onItemClick(isCheckedList,adapterPosition)
        }
    }
    interface OnItemClickListener {
        fun onItemClick(isCheckedList: SparseBooleanArray, position: Int)
    }
}

和这个

的布局文件
<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools">
    <data>
        <variable
            name="viewmodel"
            type="xxx.MultiSelectDialogViewModel" />
    </data>
    <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/cl_multi_select_dialog_root"
        tools:context=".ui.dialogs.multi_select.MultiSelectDialog">
        <androidx.appcompat.widget.AppCompatTextView
            android:id="@+id/tv_title" />
        <androidx.recyclerview.widget.RecyclerView
            android:id="@+id/rv_check_list" />
        <androidx.appcompat.widget.AppCompatButton
            android:id="@+id/btn_positive"/>
        <androidx.appcompat.widget.AppCompatButton
            android:id="@+id/btn_negative" />
        <androidx.appcompat.widget.AppCompatButton
            android:id="@+id/btn_neutral" />
    </androidx.constraintlayout.widget.ConstraintLayout>
</layout>

还有风格

<style name="AppBottomSheetDialogTheme"
        parent="Theme.MaterialComponents.Light.BottomSheetDialog">
        <item name="android:colorAccent">@color/onta_red</item>
        <item name="bottomSheetStyle">@style/CustomBottomSheetStyle</item>
    </style>
    <style name="CustomBottomSheetStyle"
        parent="Widget.Design.BottomSheet.Modal">
        <item name="android:background">@drawable/bg_white_bottom_sheet</item>
    </style>