效果图如下 :
这个ui看起来简单, 其实要实现几个功能点
1. json数据的遍历
2. RecyclerView实现循环的列表
3. 每块元素里的元素点击 : 未选中的话, 首次点击显示"selected", 点击"selected"则进行下一步数据处理
4. 设置默认的选择的元素, 显示selected
1. layout/item_region.xml 组件元素
// 这里的高度需要注意, 就是每个需要遍历的元素的高度, 千万要写成不match_parent
2. activity_update_region.xml 主页面
3. Myactivity.kt
import kotlinx.android.synthetic.main.activity_update_area.regionListRecyclerView data class Country(val name: String, val code: Int, var selected: Boolean) /** * 设置页 */ class AreaupdateActivity : AppCompatActivity() { private lateinit var adapter: SimpleAdapter override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_update_area) // 读取文件内容 val jsonString = loadJsonFromAssets(this, "country.json") val gson = Gson() val countryName = "China" val countrys: List = gson.fromJson(jsonString, type) // 设置默认的被选中的countryName selected if (countryName != null) { for (item in countrys) { if (item.name == countryName){ item.selected = true } } } regionListRecyclerView.layoutManager = LinearLayoutManager(this) adapter = SimpleAdapter(countrys) regionListRecyclerView.adapter = adapter // 元素的点击事件 adapter.setOnItemClickListener(object : SimpleAdapter.OnItemClickListener { override fun onItemClick(position: Int, item: Country) { println("我点击的$item") adapter.notifyItemChanged(position, item) // .indexOf(item) } }) } // 如果JSON文件位于assets目录下, 这是处理非代码资源文件(如文本、JSON等)的方式。通过AssetManager来访问这些文件。 fun loadJsonFromAssets(context: Context, fileName: String): String { val assetManager = context.assets val reader: BufferedReader var jsonString: String = "" try { reader = BufferedReader(InputStreamReader(assetManager.open(fileName))) jsonString = reader.use { it.readText() } } catch (e: Exception) { e.printStackTrace() // 处理异常情况 } return jsonString } // SimpleAdapter 适配器, 监听列表元素 // 为了代码的优雅, 应该单独写在Adapter里 class SimpleAdapter(private val countrys: List) : RecyclerView.Adapter() { private var selectedPosition = RecyclerView.NO_POSITION inner class SimpleViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { val regionName: TextView = itemView.findViewById(R.id.regionName) val selectedBtn: TextView = itemView.findViewById(R.id.selectedBtn) init { itemView.setOnClickListener { // 在这里处理点击事件 onItemClickListener?.let { listener -> selectedPosition = adapterPosition notifyDataSetChanged() if (selectedPosition != RecyclerView.NO_POSITION) { listener.onItemClick(selectedPosition, getItem(selectedPosition)) } } } } } override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): SimpleViewHolder { val view = LayoutInflater.from(parent.context) .inflate(R.layout.item_region, parent, false) return SimpleViewHolder(view) } interface OnItemClickListener { fun onItemClick(position: Int, item: Country) } private var onItemClickListener: OnItemClickListener? = null fun setOnItemClickListener(listener: OnItemClickListener) { onItemClickListener = listener } override fun onBindViewHolder(holder: SimpleViewHolder, position: Int) { val currentItem = getItem(position) holder.regionName.text = countrys[position].name // 点击的显示selected, 其他隐藏 holder.selectedBtn.visibility = if (position == selectedPosition) View.VISIBLE else View.INVISIBLE // 初始化数据 currentItem.selected为true的显示 // 点击的时候 原currentItem.selected为true的变为false, 点击的这个元素selected显示 if (currentItem.selected) { currentItem.selected = !currentItem.selected holder.selectedBtn.visibility = View.VISIBLE println("我显示着") } // 点击selected holder.selectedBtn.setOnClickListener { var countryStr = currentItem.name CoroutineScope(Dispatchers.IO).launch { updateInfo(countryStr) // 更新用户数据(自定义function) } } } override fun getItemCount(): Int = countrys.size fun getItem(position: Int): Country { return countrys[position] } } }
4. assets/country.json (示例)
[{ "selected": false, "country_id": 100006, "country_code": 244, "name": "Angola", "country_name_cn": "安哥拉", "ab": "AO" }, { "selected": false, "country_id": 100008, "country_code": 355, "name": "Albania", "country_name_cn": "阿尔巴尼亚", "ab": "AL" }]
完成!
其中难点是上述第3条功能, 因为需要操作item里的元素, 相比item, 里面的元素更难获取和操作, 其次是selected的初始化和两次点击的操作, 还有点击时其他selected的隐藏
对比uniapp的感受 :
① 组件的适配器和数据监听交给开发者去写, 此为难度一, 而uniapp仅需一个v-for完成遍历
② 点击事件的处理, Android需要开发者自己找到选中的元素及其子元素, 再对其及其兄弟元素操作, 有点类似jquery, 操作dom节点, 而非vue一样操作数据, 逻辑性会更强一些