有没有办法在 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>
我正在尝试将我的对话框移动到底部 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>