需求
效果图如下 :
这个ui看起来简单, 其实要实现几个功能点
1. json数据的遍历
2. RecyclerView实现循环的列表
3. 每块元素里的元素点击 : 未选中的话, 首次点击显示"selected", 点击"selected"则进行下一步数据处理
4. 设置默认的选择的元素, 显示selected
代码
1. layout/item_region.xml 组件元素
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="50dp"> // 这里的高度需要注意, 就是每个需要遍历的元素的高度, 千万要写成不match_parent
<LinearLayout
android:id="@+id/item_region"
android:layout_width="match_parent"
android:layout_height="50dp"
android:background="@drawable/bottom_border_white"
android:gravity="center_vertical">
<TextView
android:id="@+id/regionName"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginLeft="20dp"
android:layout_weight="2"
android:text="China"
android:textColor="@color/colorPrimary"
android:textSize="16sp" />
<LinearLayout
android:layout_width="0dp"
android:layout_height="50dp"
android:layout_weight="1"
android:gravity="center_vertical"
android:orientation="horizontal">
<TextView
android:id="@+id/selectedBtn"
android:layout_width="80dp"
android:layout_height="wrap_content"
android:text="Selected"
android:textColor="@color/colorPrimary"
android:textSize="16sp"
android:visibility="invisible"
/>
<ImageView
android:layout_width="10dp"
android:layout_height="15dp"
android:layout_marginLeft="15dp"
android:src="@drawable/right_arrow" />
</LinearLayout>
</LinearLayout>
</LinearLayout>
2. activity_update_region.xml 主页面
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/main_bg_color"
android:orientation="vertical"
>
<LinearLayout
android:id="@+id/updateArea_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="50dp"
android:layout_marginLeft="20dp"
android:layout_marginTop="40dp"
android:gravity="center_vertical"
android:text="All regions"
android:textColor="@color/colorPrimary"
android:textSize="16sp"
android:textStyle="bold" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/regionListRecyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
/>
</LinearLayout>
</RelativeLayout>
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<Country> = 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<Country>) :
RecyclerView.Adapter<SimpleAdapter.SimpleViewHolder>() {
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一样操作数据, 逻辑性会更强一些