Kotlin开发第三天,UI开发

完整代码Gitee地址:kotlin-demo: 15天Kotlin学习计划

第三天学习内容代码:Chapter3

目录

知识点1:公共标题栏

知识点2:自定义标题栏控件

知识点3:RecyclerView

①标准写法     

②使用框架

知识点4:编写精美的聊天对话界面

①标准写法-多布局

②使用框架-多布局


知识点1:公共标题栏

         市场上应用的界面顶部有一个标题栏,标题栏上会有一到两个按钮可用于返回或其他操作(iPhone没有专门的返回键)。虽然Android系统已经给每个Activity提供了标题栏功能,但样式有很大局限性,我们自定义一个标题栏,新建item_title布局。 




    

        
            
        

        

        

    

在activity_learn3布局中引用:

运行效果如下:

Kotlin开发第三天,UI开发_第1张图片

        可以看到,我们在LinearLayout中分别加入了两个TextView和一个LinearLayout包裹ImageView,左边的LinearLayout可用于返回,右边的TextView可用于编辑,中间的TextView则可以显示一段标题文本。

知识点2:自定义标题栏控件

        引入布局的技巧确实解决了重复编写布局代码的问题,但是如果布局中有一些控件要求能够响应事件,我们还是需要在每个Activity中为这些控件单独编写一次事件注册的代码。比如标题栏中的返回按钮,其实不管是在哪一个Activity中,这个按钮的功能都是相同的,即销毁当前Activity。而如果在每一个Activity中都需要重新注册一遍返回按钮的点击事件,无疑会增加很多重复代码,这种情况最好是使用自定义控件的方式来解决。

        新建TitleLayout继承自LinearLayout,代码如下:

class TitleLayout(context: Context, attrs: AttributeSet) : LinearLayout(context, attrs) {
    //init结构体中需要对标题栏布局进行动态加载
    init {
        val view = LayoutInflater.from(context).inflate(R.layout.item_title, this)
        //为标题栏中的按钮注册点击事件
        val llyBack: LinearLayout = view.findViewById(R.id.lly_back)
        llyBack.setOnClickListener {
            val activity = context as Activity
            activity.finish()
        }
    }
}

        现在自定义控件已经创建好了,接下来我们需要在布局文件中添加这个自定义控件,修改activity_learn3.xml中的代码,如下所示:



    

    

重新运行程序,和使用引入布局方式的效果是一样的。

知识点3:RecyclerView

        ListView由于强大的功能,在过去的Android开发当中可以说是贡献卓越,直到今天仍然还有不计其数的程序在使用ListView。不过ListView并不是完美无缺的,比如如果不使用一些技巧来提升它的运行效率,那么ListView的性能就会非常差。还有,ListView的扩展性也不够好,它只能实现数据纵向滚动的效果,如果我们想实现横向滚动的话,ListView是做不到的。

        它可以说是一个增强版的ListView,不仅可以轻松实现和ListView同样的效果,还优化了ListView存在的各种不足之处。目前Android官方更加推荐使用RecyclerView:

新建item_rcy_cont作为RecyclerView每项Item局部:




    

    

        

        
    

新建实体类UserBean,作为数据存储映射实体:

class UserBean(val herd: Int, val name: String, val phone: String)

修改activity_learn3.xml中的代码,如下所示:




    

    

预览效果如下:

Kotlin开发第三天,UI开发_第2张图片

①标准写法     

        接下来需要为RecyclerView准备一个适配器,新建UserAdapter类,让这个适配器继承自RecyclerView.Adapter,并将泛型指定为UserAdapter.ViewHolder。其中,ViewHolder是我们在UserAdapter中定义的一个内部类,代码如下所示:

//让这个适配器继承自RecyclerView.Adapter,并将泛型指定为FruitAdapter.ViewHolder。
class UserAdapter(private val userList: List) :
    RecyclerView.Adapter() {

    //内部类绑定控件
    inner class ViewHolder(view: View) : RecyclerView.ViewHolder(view) {
        val nameText: TextView = view.findViewById(R.id.tv_name)
        val phoneText: TextView = view.findViewById(R.id.tv_phone)
        val ivHerd: ImageView = view.findViewById(R.id.iv_herd)
    }

    //创建布局
    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
        val view =
            LayoutInflater.from(parent.context).inflate(R.layout.item_rcy_cont, parent, false)
        return ViewHolder(view)
    }

    //展示布局数量
    override fun getItemCount(): Int {
        return userList.size
    }

    //给控件赋值与样式
    override fun onBindViewHolder(holder: ViewHolder, position: Int) {
        holder.nameText.text = userList[position].name
        holder.phoneText.text = userList[position].phone
        holder.ivHerd.setImageResource(userList[position].herd)
    }
}

        虽然看上去好像多了好几个方法,但其实它比ListView的适配器要更容易理解。适配器准备好了之后,我们就可以开始使用RecyclerView了,修改Learn3Activity中的代码,如下所示:

class Learn3Activity : BaseActivity() {

    private val userList = ArrayList()
    private lateinit var mAdapter: UserNewAdapter

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_learn3)
        //3、RecyclerView控件
        recyclerView()
    }

    private fun recyclerView() {
        //初始化用户数据
        initUser()
        val recyclerView: RecyclerView = findViewById(R.id.recyclerView)
        //①标准写法,使用适配器
        recyclerView.layoutManager = LinearLayoutManager(this)
        recyclerView.adapter = UserAdapter(userList)
    }

    private fun initUser() {
        repeat(2) {
            userList.add(UserBean(R.mipmap.image_nv,"迪丽不热", "17321341289"))
            userList.add(UserBean(R.mipmap.image_nan,"杀手不冷", "17377621412"))
            userList.add(UserBean(R.mipmap.image_nv,"赵思露", "19987878221"))
            userList.add(UserBean(R.mipmap.image_nv,"井川里予", "13612344637"))
            userList.add(UserBean(R.mipmap.image_nan,"阿斯顿", "13635465678"))
            userList.add(UserBean(R.mipmap.image_nan,"没啥用科技", "13801940921"))
            userList.add(UserBean(R.mipmap.image_nv,"阿瑟东", "16622348923"))
        }
    }
}

        这里使用了initUser()方法,用于初始化所有的用户数据。接着在onCreate()方法中先创建了一个LinearLayoutManager对象,并将它设置到RecyclerView当中。LayoutManager用于指定RecyclerView的布局方式,这里使用的LinearLayoutManager是线性布局的意思,可以实现和ListView类似的效果。接下来我们创建了UserAdapter的实例,并将水果数据传入UserAdapter的构造函数中,最后调用RecyclerView的setAdapter()方法来完成适配器设置,这样RecyclerView和数据之间的关联就建立完成了。现在运行一下程序,如下所示。

Kotlin开发第三天,UI开发_第3张图片

        当然这只是RecyclerView的基本用法而已,还有更多用法,比如实现横向滚动和瀑布流布局,这个也并不复杂,与Java写法类似。

②使用框架

        BaseRecyclerViewAdapterHelper是一个比较成熟的框架,代码书写简洁很大提升开发效率,接下来我们用Kotlin写法使用它,在app目录下的build.gradle添加依赖:

/* 灵活的RecyclerView框架 */
implementation 'com.github.CymChad:BaseRecyclerViewAdapterHelper:3.0.4'

创建适配器UserNewAdapter:

class UserNewAdapter :
    BaseQuickAdapter(R.layout.item_rcy_cont) {
    override fun convert(holder: BaseViewHolder, item: UserBean) {
        //获取控件ID
        val icon = holder.getView(R.id.iv_herd)
        //展示图片
        icon.setImageResource(item.herd)
        //直接设置文本内容
        holder.setText(R.id.tv_name, item.name)
        holder.setText(R.id.tv_phone, item.phone)
    }
}

        适配器准备好了之后,我们就可以开始使用RecyclerView了,修改Learn3Activity中的代码,如下所示:

private fun recyclerView() {
    //初始化用户数据
    initUser()
    val recyclerView: RecyclerView = findViewById(R.id.recyclerView)

    //②使用框架,BaseRecyclerViewAdapterHelper
    mAdapter = UserNewAdapter()
    recyclerView.layoutManager = LinearLayoutManager(this)
    recyclerView.adapter = mAdapter
    mAdapter.addData(userList)//添加数据
}

 总体来看框架写法更简单,运行效果与标准写法一样。

知识点4:编写精美的聊天对话界面

        下面我们来编写一个聊天界面,需要用到.9图片,如何制作这里不做讲解,图片资源可去顶部gitee获取。我们在主界面中放置了一个RecyclerView用于显示聊天的消息内容,定义消息的实体类,新建MsgBean,代码如下所示:

//content表示消息的内容,type表示消息的类型
class MsgBean(val content: String, val itemType: Int) {
    companion object {
        //定义常量的关键字是const
        //表示这是一条收到的消息
        const val TYPE_LEFT = 0
        //表示这是一条发出的消息
        const val TYPE_RIGHT = 1
    }
}

        MsgBean类中只有两个字段:content表示消息的内容,type表示消息的类型。其中消息类型有两个值可选:TYPE_LEFT 表示这是一条收到的消息,TYPE_RIGHT表示这是一条发出的消息。定义常量的关键字是const,注意只有在单例类、companion object或顶层方法中才可以使用const关键字。

新建子项布局,左边显示item_msg_left.xml,代码如下所示:




    

    

        

    

预览效果:

新建子项布局,右边显示item_msg_right.xml,代码如下所示:




    

        

    

    


预览效果:

①标准写法-多布局

接下来需要创建RecyclerView的适配器类,新建类MsgAdapter,代码如下所示:

class MsgAdapter(private val msgList: List) :
    RecyclerView.Adapter() {

    inner class LeftViewHolder(view: View) : RecyclerView.ViewHolder(view) {
        val leftMsg: TextView = view.findViewById(R.id.tv_left)
    }

    inner class RightViewHolder(view: View) : RecyclerView.ViewHolder(view) {
        val rightMsg: TextView = view.findViewById(R.id.tv_right)
    }

    override fun getItemViewType(position: Int): Int {
        return msgList[position].itemType
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int):     
        RecyclerView.ViewHolder {
            return when (viewType) {
                MsgBean.TYPE_LEFT ->
                    LeftViewHolder(
                        LayoutInflater.from(parent.context)
                            .inflate(R.layout.item_msg_left, parent, false)
                    )
                MsgBean.TYPE_RIGHT ->
                    RightViewHolder(
                        LayoutInflater.from(parent.context)
                            .inflate(R.layout.item_msg_right, parent, false)
                    )
                else -> throw IllegalArgumentException()
        }
    }

    override fun getItemCount(): Int {
        return msgList.size
    }

    override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
        val msg = msgList[position]
        when (holder) {
            is LeftViewHolder -> holder.leftMsg.text = msg.content
            is RightViewHolder -> holder.rightMsg.text = msg.content
            else -> throw IllegalArgumentException()
        }
    }

}

        上述代码中用到了一个新的知识点:根据不同的viewType创建不同的界面。首先我们定义了LeftViewHolder和RightViewHolder这两个ViewHolder,分别用于缓存msg_left_item.xml和msg_right_item.xml布局中的控件。然后要重写getItemViewType()方法,并在这个方法中返回当前position对应的消息类型。

最后修改Learn3Activity中的代码:

class Learn3Activity : BaseActivity() {

    private val msgList = ArrayList()

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_learn3)

        //4、编写精美的聊天对话界面
        val tvTitle: TextView = findViewById(R.id.tv_title)
        tvTitle.text = "聊天室"
        recyclerNewView()
    }

    private fun initMsg() {
        repeat(1) {
            msgList.add(MsgBean("在吗?还记得我吗?",0))
            msgList.add(MsgBean("当然,初中坐我前排的班花,那时候我还扯过你的肩带",1))
            msgList.add(MsgBean("有啥事吗?",1))
            msgList.add(MsgBean("能借我200块钱吗",0))
            msgList.add(MsgBean("其实从初中开始我就一直暗恋你,没好意思跟你说,我们在一起吧",1))
            msgList.add(MsgBean("别吧我们都多久没联系了,都不了解对方,也不太熟悉‍",0))
            msgList.add(MsgBean("那你还好意思找我借钱?‍",1))
            msgList.add(MsgBean("?‍",0))
        }
    }

    private fun recyclerNewView() {
        initMsg()
        val recyclerView: RecyclerView = findViewById(R.id.recyclerView)
        //①标准写法,使用适配器
        recyclerView.layoutManager = LinearLayoutManager(this)
        recyclerView.adapter = MsgAdapter(msgList)
    }

}

        我们先在initMsg()方法中初始化了几条数据用于在RecyclerView中显示,接下来按照标准的方式构建RecyclerView,给它指定一个LayoutManager和一个适配器。运行程序之后,你将会看到非常美观的聊天界面:

Kotlin开发第三天,UI开发_第4张图片

②使用框架-多布局

        布局不变,MsgBean实体类继承MultiItemEntity ,类型必须命名为itemType,并设置关键字override,修改如下:

class MsgBean(val content: String,override val itemType: Int) : MultiItemEntity {
    companion object {
        //定义常量的关键字是const
        //表示这是一条收到的消息
        const val TYPE_LEFT = 0
        //表示这是一条发出的消息
        const val TYPE_RIGHT = 1
    }
}

        创建多布局的适配器,新建类MsgNewAdapter,继承BaseMultiItemQuickAdapter,代码如下所示:

class MsgNewAdapter(data: MutableList?) :
    BaseMultiItemQuickAdapter(data) {

    init {
        //必须绑定type和layout的关系
        addItemType(MsgBean.TYPE_LEFT, R.layout.item_msg_left)
        addItemType(MsgBean.TYPE_RIGHT, R.layout.item_msg_right)
    }

    override fun convert(holder: BaseViewHolder, item: MsgBean) {
        holder ?: return
        item ?: return
        when (holder.itemViewType) {
            MsgBean.TYPE_LEFT -> holder.setText(R.id.tv_left, item.content)
            MsgBean.TYPE_RIGHT -> holder.setText(R.id.tv_right, item.content)
            else -> throw IllegalArgumentException()
        }
    }
}

 最后修改Learn3Activity中的代码:

private fun recyclerNewView() {
    initMsg()
    val recyclerView: RecyclerView = findViewById(R.id.recyclerView)
    //②使用框架,BaseRecyclerViewAdapterHelper
    msgAdapter = MsgNewAdapter(msgList)
    recyclerView.layoutManager = LinearLayoutManager(this)
    recyclerView.adapter = msgAdapter
}

运行结果与标准写法一致。

你可能感兴趣的:(Kotlin10天开发计划,kotlin,开发语言,android)