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

Android基于JSON表单:EditText与RadioButton的RecyclerView绑定实现

Android表单数据绑定:EditText与RadioButton的实现方案

嘿,你已经搞定了RecyclerView的问题标签绑定,剩下的EditText和RadioButton数据收集其实没那么复杂,我给你一步步拆解实现思路和代码示例:

1. 先搞定数据模型(对应JSON结构)

首先得把JSON里的问题结构转换成Java/Kotlin数据类,每个问题至少要包含:唯一标识key(用来做最终输出的键)、问题标题title、类型type(区分是文本输入还是单选)、单选问题的选项列表options(文本问题可以忽略)。

比如用Kotlin的数据类(Java的话用Bean类加getter/setter):

data class Question(
    val key: String, // 对应最终输出的[key]
    val title: String, // 问题标签
    val type: String, // 可选值:"text" 或 "radio"
    val options: List<String>? = null // 单选问题的选项,文本问题为null
)

解析JSON的时候用Gson/Moshi把服务器返回的JSON数组转成List<Question>就行,这个你应该已经有基础了。

2. RecyclerView Adapter区分视图类型

因为有两种不同的输入组件,所以Adapter要处理多视图类型:

第一步:定义视图类型常量

在Adapter里加两个常量:

private const val TYPE_TEXT = 0
private const val TYPE_RADIO = 1

第二步:重写getItemViewType方法

根据当前Question的类型返回对应的视图类型:

override fun getItemViewType(position: Int): Int {
    return if (questionList[position].type == "text") TYPE_TEXT else TYPE_RADIO
}

第三步:创建两个ViewHolder

分别对应EditText和RadioButton组:

文本输入的ViewHolder

class TextViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
    val etAnswer: EditText = itemView.findViewById(R.id.et_answer)
    // 用来保存当前问题的key,方便后续收集数据
    lateinit var questionKey: String
}

单选输入的ViewHolder

class RadioViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
    val rgOptions: RadioGroup = itemView.findViewById(R.id.rg_options)
    val tvTitle: TextView = itemView.findViewById(R.id.tv_question_title)
    lateinit var questionKey: String
}

第四步:在onCreateViewHolder里创建对应视图

根据视图类型加载不同的item布局:

override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
    val inflater = LayoutInflater.from(parent.context)
    return if (viewType == TYPE_TEXT) {
        TextViewHolder(inflater.inflate(R.layout.item_text_question, parent, false))
    } else {
        RadioViewHolder(inflater.inflate(R.layout.item_radio_question, parent, false))
    }
}

3. 绑定数据+实时保存输入

在onBindViewHolder里,不仅要渲染问题标题,还要给输入组件添加监听,实时保存用户的输入:

首先,我们需要在Adapter里维护一个答案映射表,用来存储每个问题的输入值:

private val answerMap = mutableMapOf<String, String>()

然后处理两种ViewHolder的绑定:

绑定文本输入项

override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
    val question = questionList[position]
    when (holder) {
        is TextViewHolder -> {
            holder.questionKey = question.key
            holder.itemView.findViewById<TextView>(R.id.tv_question_title).text = question.title
            // 恢复之前的输入(如果有)
            holder.etAnswer.setText(answerMap[question.key])
            // 添加文本变化监听,实时保存输入
            holder.etAnswer.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?) {
                    answerMap[question.key] = s.toString().trim()
                }
            })
        }
        // 处理单选项
        is RadioViewHolder -> {
            holder.questionKey = question.key
            holder.tvTitle.text = question.title
            // 先清空之前的RadioButton
            holder.rgOptions.removeAllViews()
            // 动态生成RadioButton选项
            question.options?.forEach { option ->
                val radioBtn = RadioButton(holder.itemView.context)
                radioBtn.text = option
                radioBtn.id = View.generateViewId()
                holder.rgOptions.addView(radioBtn)
                // 恢复之前的选中状态
                if (answerMap[question.key] == option) {
                    radioBtn.isChecked = true
                }
            }
            // 添加单选选中监听
            holder.rgOptions.setOnCheckedChangeListener { _, checkedId ->
                val selectedBtn = holder.rgOptions.findViewById<RadioButton>(checkedId)
                answerMap[question.key] = selectedBtn.text.toString().trim()
            }
        }
    }
}

4. 收集并格式化输出答案

最后,给Adapter加一个方法,用来获取整理好的答案,转成你需要的「[key]: [value]」格式:

fun getFormattedAnswers(): String {
    return answerMap.entries.joinToString("\n") { "${it.key}: ${it.value}" }
}

比如调用这个方法后,输出会是:

name: 张三
age: 25
gender: 男
...

一些注意事项

  • 确保JSON里的每个问题都有唯一的key字段,不然答案会被覆盖
  • 单选问题的options字段要是非空数组,不然动态生成RadioButton会报错
  • 如果需要保存用户中途输入的内容,可以把answerMap持久化到SharedPreferences或者本地文件里

内容的提问来源于stack exchange,提问作者Reynaldo Leoricci Mikhael

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.25 06:24:00