第一行代码第四章主要介绍了常用控件和常用布局的使用方式。
思考:既然打算尝试写博客,作为开发小白一开始的内容只能是搬运的书本,而这些基础琐碎的知识点在官方文档和其他的书本都比比皆是,那我记录这些东西的意义有多大呢?如何才能不只是书本的搬运工,这是我作为一个开发和博客新手面临的问题。
基础控件
对于基础控件,只记录他的名称和其较为特有的设置。
控件共有属性
android.layout_widthandroid.layout_heightandroid.idandroid.visibility: 可设置为 VISIBLE/INVISIBLE/GONE
TextView
android.text设置文本内容android.gravity文本对齐方式(默认为左上角对齐)android.textColor字体颜色android.textSize字体大小
Button
android.textAllCaps设置按钮上英文是否全部大写- 添加
onClickListener: 对Button设置setOnClickListener或者继承View.onClickListener接口并实现函数onClick
EditText
android.hint设置提示性文字android.maxLine设置最大显示行数- 获取text中内容:
editTextView.text.toString(),利用Kotlin语法糖简化getText()函数
在实践中发现无法通过实现onClick()函数实现监听了,因为没有了对应注解
ImageView
android.src指定展示的图片- 通过代码动态更改
ImageView中的图片:imageView.setImageResource(newResource)
ProcessBar
android.style调整进度条形态- 设置进度显示:
android.max设置总进度+通过progressBarView.progress设置当前进度
AlertDialog
AlterDialog可在当前界面上弹出对话框并屏蔽其他交互控件,一般用于警告或提示。另外,这种View是要在Activity的代码中设置的,一般用于响应某种情况下的交互。
三种基本布局
布局layout是一种用于放置各种空间的容器,其继承自UI类View和ViewGroup,且布局的内部也可放置布局形成嵌套。
LinearLayout
将所有控件在线性方向上排列
android.orientation设置排列的方向,要注意内部控件的width和height的设置 内部控件的设置android.layout_gravity设置内部控件在布局中的对齐方式android.layout_weight通过比例的形式这只内部控件的黛奥
RelativeLayout
通过相对定位的方式让控件出现在布局的任何位置。
内部控件的设置:
- 相对上层View
android.alignParentTopandroid.alignParentBottomandroid.alignParentLeftandroid.alignParentRightandroid.centerInParent
2,相对内部其他控件
android.layout_aboveandroid.layout_belowandroid.layout_toLeftOfandroid.layout_toRightOfandroid.layout_alignLeftandroid.layout_alignRightandroid.layout_alignTopandroid.layout_alignBottom
FrameLayout
控件默认摆放在左上角,可通过android.layout_gravity摆放控件
自定义控件
- 通过引入布局的方式引入常用的空间布局,从而减少重复代码。(include)
- 创建布局,例如标题栏布局
title.xml。在布局中放置一组控件。 - 在主layout中引入该布局。即添加代码
<include layout="@layout/title" />
- 创建自定义控件,单独编写事件注册代码,减少逻辑代码的重复。
- 新建布局类TitleLayout并继承LinearLayout
- 在TitleLayout类中通过init{LayoutInflater}的方式在初始化阶段动态加载布局R.layout.title,即方法一中的没有设置监听的标题栏布局
- 在主Layout中加入TitleLayout控件(布局)。
- 在TitleLayout类中添加对控件的监听。(通过context as Activity的方式获取对Activity的控制)
复杂控件
接下来介绍两种用于滚动展示的复杂控件,控件内部会包含子项控件。
ListView
ListView是一种用来滑动展示数据的控件,但集合中的数据无法直接传递给它,需要借助适配器完成,下面以ArrayAdapter为例展示定制ListView的流程。
- 定义展示的实体类:
Fruit - 自定义ListView的子项item布局:fruit_item.xml
- 创建自定义适配器
FruitAdapter并继承父类ArrayAdapter,重写getView()方法,通过LayoutInflater获取fruit_item布局的控制,并使用FruitList,position绑定布局中的控件与资源。 - 在Activity代码中初始化FruitList与FruitAdapter,随后将ListView的adapter设置为FruitAdapter。
ListView的效率优化
- 使用
convertView在函数getView()中复用之前加载好的缓存布局,从而避免多次使用LayoutInflater - 自定义内部类
inner class ViewHolder用于缓存内部控件实例,将viewHolder存储在view.tag中并使用viewHolder对内部控件进行操作,从而减少findViewById()的调用。
ListView的点击事件
- 使用
ListView.setOnItemClickListener()方法和四大参数{parent, view, position, id}进行操作。
RecyclerView
相较于ListView,RecyclerView可以实现更灵活的多方向的滑动展示,并且通过内置viewHolder提高了运行效率,同时使控制逻辑更加清晰。
RecyclerView的基本使用流程
- 在项目的build.gradle中添加dependency
- 在主layout中加入控件
<androidx.recyclerview.widget.RecyclerView> - 为RecyclerView准备适配器,新建类
FruitAdapter并继承自RecyclerView.Adapter - 在MainActivity中初始化数据,为recyclerView指定layoutManager从而确定滑动方式,为recyclerView创建并指定adapter。
Adapter
我认为Adapter就是为滑动控件RecyclerView指定子控件或布局item,并对item中的控件添加配置,例如监听器,随后通过ViewHolder等方式提高运行效率。
- 在适配器类
FruitAdapter中自定义内部类inner class viewHolder并继承RecyclerView.ViewHolder,用于存放item中的控件 - 在
onCreateViewHolder中通过LayoutInlfater加载子布局item,随后通过itemView初始化ViewHolder - 在
onBindViewHolder中根据holder和position将List中的数据加载入item的子控件中。
LayoutManager
在RecyclerView中,通过指定Layoutmanager指定布局的排列方式。常用的内置布局方式有LinearLayoutManager,GridLayoutManager,StaggeredGridLayoutManager。
RecyclerView的点击事件
在RecyclerView中需要自定义View的点击注册事件,也就是在Adapter的onCreateViewHolder()中,在完成初始化viewHolder后,通过viewHolder子控件设置Listenre。
The priority of listener
from StackOverFlow: Only one listener work at a time, the deeptest child get the priority over it's parents.
对比ListView与RecyclerView的不同
| ListView | RecyclerView | |
|---|---|---|
| 前置依赖 | 无 | 需要 |
| 布局管理 | 自身管理 | LayoutManager |
| 加载布局方式 | 重写getView() | 重写onCreateViewHolder() |
| 控件获取 | findViewById() | viewHolder.targetView |
| 点击事件 | listView.setItemListener() | viewHolder.button.setOnClickListener |
对最佳实战的分析
实战中创建了类似微信聊天的对话框,那么如何在一个RecyclerView中动态加载两种item布局就成了主要问题。 解决步骤:
- 在基础类
Msg中设置常量TYPE用于指定消息的类型RECEIVED/SENT。 - 在RecyclerView的适配器
MsgAdapter中创建两种ViewHolder分别用于缓存left_item.xml和right_item.xml布局中的控件。 - 重写
getItemViewType(position: Int)函数,返回msgList[positon]中Msg的TYPE - 在
onCreateViewHolder()函数中根据viewType创建对应的ViewHolder - 在
onBindViewHolder中根据holder的类型(LeftViewHolder/RightViewHolder)和Msg设置内部控件。