本文将详细介绍如何使用DialogX库实现一个iOS风格的底部弹窗,包含图标、文本和Toggle开关的列表项。
实现步骤
1. 添加依赖
在build.gradle文件中添加:
implementation 'com.github.kongzue.DialogX:DialogX:0.0.49.beta14'
implementation 'com.github.kongzue.DialogX:DialogXIOSStyle:0.0.49.beta14'
implementation 'androidx.recyclerview:recyclerview:1.3.2'
2. 创建布局文件
底部弹窗主布局 (dialog_bottom_toggle.xml)
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:background="@drawable/bg_bottom_dialog_round_top">
<TextView
android:id="@+id/tv_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="16dp"
android:textSize="18sp"
android:textStyle="bold"/>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:maxHeight="400dp"/>
<Button
android:id="@+id/btn_cancel"
android:layout_width="match_parent"
android:layout_height="48dp"
android:text="取消"
android:background="?attr/selectableItemBackground"/>
</LinearLayout>
列表项布局 (item_toggle.xml)
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="56dp"
android:orientation="horizontal"
android:paddingStart="24dp"
android:paddingEnd="16dp"
android:gravity="center_vertical">
<ImageView
android:id="@+id/iv_icon"
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_marginEnd="16dp"/>
<TextView
android:id="@+id/tv_title"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:textSize="16sp"/>
<androidx.appcompat.widget.SwitchCompat
android:id="@+id/switch_toggle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</LinearLayout>
3. 实现工具类
import android.content.Context
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Button
import android.widget.ImageView
import android.widget.TextView
import androidx.appcompat.widget.SwitchCompat
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.kongzue.dialogx.dialogs.CustomDialog
import com.kongzue.dialogx.interfaces.OnBindView
import com.kongzue.dialogx.style.IOSStyle
import smartconnection.com.smartconnect.R
object BottomToggleDialog {
data class ToggleItem(
val iconRes: Int,
val title: String,
var isChecked: Boolean = false,
val onToggleChanged: ((Boolean) -> Unit)? = null
)
/**
* 使用CustomDialog的可靠实现
*/
fun show(
context: Context,
title: String? = null,
items: List<ToggleItem>
) {
CustomDialog.build()
.setCustomView(object : OnBindView<CustomDialog>(R.layout.dialog_bottom_toggle) {
override fun onBind(dialog: CustomDialog?, view: View?) {
view?.apply {
// 绑定视图
val recyclerView = findViewById<RecyclerView>(R.id.recyclerView)
val tvTitle = findViewById<TextView>(R.id.tv_title)
val btnCancel = findViewById<Button>(R.id.btn_cancel)
// 设置标题
title?.let { tvTitle.text = it } ?: run { tvTitle.visibility = View.GONE }
// 配置列表
recyclerView.layoutManager = LinearLayoutManager(context)
recyclerView.adapter = ToggleAdapter(items).apply {
onItemClick = { position, isChecked ->
items[position].isChecked = isChecked
items[position].onToggleChanged?.invoke(isChecked)
}
}
// 取消按钮
btnCancel.setOnClickListener { dialog?.dismiss() }
}
}
})
.setStyle(IOSStyle.style())
.setAlign(CustomDialog.ALIGN.BOTTOM)
.setCancelable(true)
.show()
}
private class ToggleAdapter(private val items: List<ToggleItem>) :
RecyclerView.Adapter<ToggleAdapter.ViewHolder>() {
var onItemClick: ((Int, Boolean) -> Unit)? = null
class ViewHolder(view: View) : RecyclerView.ViewHolder(view) {
val ivIcon: ImageView = view.findViewById(R.id.iv_icon)
val tvTitle: TextView = view.findViewById(R.id.tv_title)
val switch: SwitchCompat = view.findViewById(R.id.switch_toggle)
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val view = LayoutInflater.from(parent.context)
.inflate(R.layout.item_toggle, parent, false)
return ViewHolder(view)
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val item = items[position]
holder.ivIcon.setImageResource(item.iconRes)
holder.tvTitle.text = item.title
holder.switch.isChecked = item.isChecked
holder.switch.setOnCheckedChangeListener { _, isChecked ->
onItemClick?.invoke(position, isChecked)
}
holder.itemView.setOnClickListener {
holder.switch.toggle()
}
}
override fun getItemCount() = items.size
}
}
使用示例
// 准备数据
val items = listOf(
BottomToggleDialog.ToggleItem(
iconRes = R.drawable.ic_notification,
title = "消息通知",
isChecked = true
) { isChecked ->
Toast.makeText(this, "通知状态: $isChecked", Toast.LENGTH_SHORT).show()
},
BottomToggleDialog.ToggleItem(
iconRes = R.drawable.ic_dark_mode,
title = "暗黑模式",
isChecked = false
) { isChecked ->
Toast.makeText(this, "暗黑模式: $isChecked", Toast.LENGTH_SHORT).show()
}
)
// 显示弹窗
BottomToggleDialog.show(
context = this,
title = "功能设置",
items = items
)
关键点说明
1.底部显示控制:
setAlignBottom() 确保内容对齐底部
自定义动画实现滑动效果
顶部圆角背景优化视觉效果
2.数据绑定:
使用RecyclerView实现高效列表
通过回调处理Toggle状态变化