目录
1、如何创建自定义的控件
2、ListView的使用(inne内部类r 、lateinit延迟加载 关键词)
3、RecyclerView的使用
4、sealed密封关键词的作用
-
1、如何创建自定义的控件
简单的封装个头部的view,来看一下跟Java的区别吧。
1.1 layout
<?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="match_parent"
android:orientation="horizontal">
<Button
android:id="@+id/btBack"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Back" />
<Button
android:id="@+id/btContent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="标题" />
<Button
android:id="@+id/btEntry"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Entry" />
</LinearLayout>
1.2 创建自定义view继承LinearLayout
class TitleLayout(context: Context?, attrs: AttributeSet?) : LinearLayout(context, attrs) {
init {
LayoutInflater.from(context).inflate(R.layout.module_title_back_base, this)
btBack.setOnClickListener {
val activity = context as Activity
activity.finish()
}
btEntry.setOnClickListener {
Toast.makeText(
context, "this is a entry", Toast.LENGTH_SHORT
).show()
}
}
fun setTitle(titleContent: String) {
btContent.setText(titleContent)
}
}
继承LinearLayout之后, 会跟Java一样重写构造方法。自己选择即可。我选择的 俩方法的,具体的对应的方法意义跟Java一样
1.3 主布局引用
<com.hdsx.orrvideenvironment.view.TitleLayout
android:id="@+id/titleLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintBottom_toTopOf="@+id/guideline5"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
override fun onPostCreate(savedInstanceState: Bundle?) {
super.onPostCreate(savedInstanceState)
btContent.setText("首页")
}
theme是noActionbar的。init表示加载这个类的时候优先走的方法。
-
2、ListView的使用(inne内部类r 、lateinit延迟加载 关键词)
2.1 声明控件view 、item 自定义布局
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".ui.MainActivity">
<com.hdsx.orrvideenvironment.view.TitleLayout
android:id="@+id/titleLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<ListView
android:id="@+id/lv_list"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="visible" />
</LinearLayout>
//item的展示的layout
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:id="@+id/tvLeft"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:padding="20dp"
android:text="item"
android:textSize="16sp" />
</RelativeLayout>
2.2 adapter书写
我这边就整个String的list的集合,展示一下即可
class ListViewAdapter(context: Context, val resource: Int, data: ArrayList<String>) :
ArrayAdapter<String>(context, resource, data) {
override fun getView(position: Int, convertView: View?, parent: ViewGroup): View {
val view: View
val viewHolder: ViewHolder
if (null == convertView) {
view = LayoutInflater.from(parent.context).inflate(resource, parent, false)
viewHolder = ViewHolder(view)
view.tag = viewHolder
} else {
view = convertView
viewHolder = view.tag as ViewHolder
}
val item = getItem(position)
viewHolder.tv.text = item
return view
}
inner class ViewHolder(view: View) {
val tv: TextView = view.findViewById(R.id.tvLeft)
}
}
inner关键字表示,这是个内部类。我重写的ArrayAdapter。
复用方式跟Java差不多, 就是打tag的时候 是通过自己定义的view,如果直接给convertView 赋值,提示val cannot be reassigned:不能重新定义。
2.3 使用
private var adapter: ListViewAdapter? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main_test)
initDatas()//初始化数据
adapter = ListViewAdapter(this, R.layout.item_fruit, listDatas)
lv_list.adapter = adapter
lv_list.setOnItemClickListener { parent, view, position, id ->
Toast.makeText(this, "当前是$position 位置", Toast.LENGTH_SHORT).show()
adapter?.notifyDataSetChanged()
}
}
private fun initDatas() {
for (i in 0..10) {
listDatas.add(i.toString())
}
}
这块有个点就是 如果是成员变量的话, 就要先给adapter赋值一个null,而且之后再调用刷新的话,都需要 ?.来判定非空。除了这种写法,还有一种延迟初始化的声明方式。
2.4 延迟初始化lateinit
加上lateinit关键字就可,来看下区别吧
private lateinit var adapter: ListViewAdapter
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main_test)
initDatas()//初始化数据
if (!::adapter.isInitialized) {
adapter = ListViewAdapter(this, R.layout.item_fruit, listDatas)
}
lv_list.adapter = adapter
lv_list.setOnItemClickListener { parent, view, position, id ->
Toast.makeText(this, "当前是$position 位置", Toast.LENGTH_SHORT).show()
adapter.notifyDataSetChanged()
}
}
当然这种延迟初始化的话 可能会存在忘记 初始化的情况。Kotlin对此还提供
!::.xxx. isInitialized
来检查当前的控件是否已经完成初始化了。
-
3、RecyclerView的使用
为了更全面的展示,我这里直接放最终的版本。
包括多布局、密封类sealed 、
3.1 导入依赖 和声明布局
implementation "androidx.recyclerview:recyclerview:1.1.0"
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".ui.MainActivity">
<com.hdsx.orrvideenvironment.view.TitleLayout
android:id="@+id/titleLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="visible" />
</LinearLayout>
3.2 多布局的准备工作
class MsgBean(val content: String, val type: Int) {
companion object {
const val TYPE_ONE = 1
const val TYPE_TWO = 2
}
}
声明个数据类, 并且加 假静态方式。const是定义常量的关键字。
3.3 adapter的书写
class MsgAdapter(val msgList: ArrayList<MsgBean>) :
RecyclerView.Adapter<MySealViewHolder>() {
override fun getItemViewType(position: Int): Int {
val msgBean = msgList[position]
return msgBean.type
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) =
if (viewType == MsgBean.TYPE_ONE) {
val leftView =
LayoutInflater.from(parent.context).inflate(R.layout.item_fruit, parent, false)
leftView.tvLeft.setOnClickListener {
Toast.makeText(parent.context, "this left", Toast.LENGTH_SHORT).show()
}
LeftViewHolder(leftView)
} else {
val rightView = LayoutInflater.from(parent.context)
.inflate(R.layout.item_fruit_right, parent, false)
rightView.tvRight.setOnClickListener {
Toast.makeText(parent.context, "this right", Toast.LENGTH_SHORT).show()
}
RightViewHolder(rightView)
}
override fun getItemCount(): Int = msgList.size
override fun onBindViewHolder(holder: MySealViewHolder, position: Int) {
val msgBean = msgList[position]
when (holder) {
is LeftViewHolder -> holder.tvLeft.text = msgBean.content
is RightViewHolder -> holder.tvRight.text = msgBean.content
}
}
}
3.4 MySealViewHolder密封类 ->MySealViewHolder.kt
sealed class MySealViewHolder(view: View) : RecyclerView.ViewHolder(view)
class LeftViewHolder(view: View) : MySealViewHolder(view) {
val tvLeft: TextView = view.findViewById(R.id.tvLeft)
}
class RightViewHolder(view: View) : MySealViewHolder(view) {
val tvRight: TextView = view.findViewById(R.id.tvRight)
}
sealed关键词就是指的是密封类。密封类的作用下面会单独介绍。
3.5 使用
private val listData = ArrayList<MsgBean>()
// private var frultAdapter: FrultAdapter? = null
private lateinit var msgAdapter: MsgAdapter//延迟初始化
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main_test)
initMsg()
if (!::msgAdapter.isInitialized) {
//检查是否完成了初始化
msgAdapter = MsgAdapter(listData)
}
val linearLayoutManager = LinearLayoutManager(this)
recyclerView.layoutManager = linearLayoutManager
recyclerView.adapter = msgAdapter
}
fun initMsg() {
val msgBean1 = MsgBean("this one", MsgBean.TYPE_ONE)
val msgBean2 = MsgBean("this one", MsgBean.TYPE_ONE)
val msgBean6 = MsgBean("this two", MsgBean.TYPE_TWO)
val msgBean7 = MsgBean("this two", MsgBean.TYPE_TWO)
listData.add(msgBean1)
listData.add(msgBean2)
listData.add(msgBean6)
listData.add(msgBean7)
}
这边是整了个LinearLayoutManager,网格 横向跟Java的一样。此处不讲解
-
4、sealed密封关键词的作用
4.1 举例接口
interface SealedInterface {
class onSuccess(string: String) : SealedInterface
class onFaled(string: String) : SealedInterface
}
4.2 使用
fun testSealed(s: SealedInterface) = when (s) {
is onSuccess -> "success"
is onFaled -> "failed"
else -> "must be else"
}
在使用的时候会发现,必须重写else。不重写的话编译器都过去,
所以密封sealed的关键词的作用就体现出来了。
被修饰的类,在when的时候,只会有当前类的条件,不会默认走else
override fun onBindViewHolder(holder: MySealViewHolder, position: Int) {
val msgBean = msgList[position]
when (holder) {
is LeftViewHolder -> holder.tvLeft.text = msgBean.content
is RightViewHolder -> holder.tvRight.text = msgBean.content
}
}
总结
看自定义控件,数据适配器差别还是挺大的。