You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android Kotlin实现Google Tasks式添加CheckBox及相关技术问题

实现类似Google Tasks的动态任务条目及相关问题解答

问题1:动态条目实现、CheckBox事件与持久化处理

1.1 动态生成带CheckBox和输入框的条目

核心思路是用一个垂直LinearLayout作为任务条目容器,点击加号按钮时动态创建横向布局(承载CheckBox和EditText),并添加到容器中。

布局文件示例(activity_main.xml)

<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:padding="16dp">

    <LinearLayout
        android:id="@+id/tasksContainer"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1"
        android:orientation="vertical"/>

    <Button
        android:id="@+id/addTaskBtn"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="+"
        android:layout_gravity="end"/>
</LinearLayout>

Activity中动态添加条目的代码

class MainActivity : AppCompatActivity() {
    private lateinit var tasksContainer: LinearLayout
    private val tasks = mutableListOf<Task>()

    data class Task(val content: String, val isChecked: Boolean)

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        tasksContainer = findViewById(R.id.tasksContainer)
        val addTaskBtn = findViewById<Button>(R.id.addTaskBtn)

        addTaskBtn.setOnClickListener {
            addNewTaskEntry()
        }

        // 启动时加载已保存的任务
        loadTasksFromPrefs()
    }

    private fun addNewTaskEntry(initialContent: String = "", initialChecked: Boolean = false) {
        // 创建横向布局承载CheckBox和EditText
        val taskRow = LinearLayout(this).apply {
            layoutParams = LinearLayout.LayoutParams(
                LinearLayout.LayoutParams.MATCH_PARENT,
                LinearLayout.LayoutParams.WRAP_CONTENT
            ).apply {
                setMargins(0, 8, 0, 8)
            }
            orientation = LinearLayout.HORIZONTAL
            gravity = Gravity.CENTER_VERTICAL
        }

        // 创建动态CheckBox
        val checkBox = CheckBox(this).apply {
            // 设置唯一ID,用时间戳避免重复冲突
            id = System.currentTimeMillis().toInt()
            isChecked = initialChecked
            // 处理勾选事件
            setOnCheckedChangeListener { _, isChecked ->
                val editText = taskRow.findViewById<EditText>(R.id.taskEditText)
                updateTaskStatus(editText.text.toString(), isChecked)
            }
        }

        // 创建输入框
        val editText = EditText(this).apply {
            id = R.id.taskEditText
            layoutParams = LinearLayout.LayoutParams(
                0,
                LinearLayout.LayoutParams.WRAP_CONTENT,
                1f
            ).apply {
                marginStart = 16
            }
            hint = "输入任务内容"
            setText(initialContent)
            // 监听文本变化,更新任务数据
            addTextChangedListener(object : TextWatcher {
                override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {}
                override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {}
                override fun afterTextChanged(s: Editable?) {
                    s?.toString()?.let { content ->
                        if (initialContent.isEmpty()) {
                            // 新任务添加到列表
                            tasks.add(Task(content, checkBox.isChecked))
                        } else {
                            // 更新已有任务内容
                            val index = tasks.indexOfFirst { it.content == initialContent }
                            if (index != -1) {
                                tasks[index] = tasks[index].copy(content = content)
                            }
                        }
                        saveTasksToPrefs()
                    }
                }
            })
        }

        taskRow.addView(checkBox)
        taskRow.addView(editText)
        tasksContainer.addView(taskRow)
    }

    private fun updateTaskStatus(content: String, isChecked: Boolean) {
        val index = tasks.indexOfFirst { it.content == content }
        if (index != -1) {
            tasks[index] = tasks[index].copy(isChecked = isChecked)
            saveTasksToPrefs()
        }
    }
}

1.2 动态CheckBox的ID与点击事件

  • ID设置:可以手动指定唯一ID(如示例中的时间戳转整数),确保每个CheckBox的ID不重复,后续可通过ID定位控件。
  • 事件处理:动态创建的CheckBox和静态控件完全一致,直接调用setOnCheckedChangeListener或setOnClickListener即可绑定事件,逻辑和静态控件无区别。

1.3 用SharedPreferences实现持久化

借助Gson将任务列表序列化为JSON字符串保存,读取时再解析为列表。

1. 添加Gson依赖(Module级build.gradle)

dependencies {
    implementation 'com.google.code.gson:gson:2.10.1'
}

2. 实现保存与加载方法

在Activity中添加以下代码:

private val prefs by lazy { getSharedPreferences("TasksStorage", MODE_PRIVATE) }
private val gson by lazy { Gson() }

private fun saveTasksToPrefs() {
    val tasksJson = gson.toJson(tasks)
    prefs.edit().putString("saved_tasks", tasksJson).apply()
}

private fun loadTasksFromPrefs() {
    val tasksJson = prefs.getString("saved_tasks", null) ?: return
    val taskType = object : TypeToken<MutableList<Task>>() {}.type
    tasks.clear()
    tasks.addAll(gson.fromJson(tasksJson, taskType))
    // 将加载的任务渲染到界面
    tasks.forEach { addNewTaskEntry(it.content, it.isChecked) }
}

问题2:获取Activity中所有CheckBox

无需手动维护列表,通过递归遍历Activity的视图树即可收集所有CheckBox实例:

private fun collectAllCheckBoxes(view: View): List<CheckBox> {
    val checkBoxList = mutableListOf<CheckBox>()
    when (view) {
        is CheckBox -> checkBoxList.add(view)
        is ViewGroup -> {
            for (i in 0 until view.childCount) {
                checkBoxList.addAll(collectAllCheckBoxes(view.getChildAt(i)))
            }
        }
    }
    return checkBoxList
}

// 使用示例:
val allCheckBoxes = collectAllCheckBoxes(findViewById(android.R.id.content))
allCheckBoxes.forEach { checkBox ->
    // 处理每个CheckBox,例如打印状态
    Log.d("CheckBoxInfo", "ID: ${checkBox.id}, 勾选状态: ${checkBox.isChecked}")
}

该方法会递归遍历整个界面的View层级,自动收集所有CheckBox。

内容的提问来源于stack exchange,提问作者nope

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.11 09:01:23