在现版本中,滚动控件有多种,而相比于ListView,GridView,RecyclerView的用途更广,所以将前二者做为Adapter适配器的引入,再对RecyclerView进行简单讲解。html
为了方便理解,这里介绍一下Android应用设计的基础,也就是MVC架构,如图。java
控制器(Controller)- 可看做一个中间桥梁,响应来自View的用户交互,经过对View设定的事件逻辑修改Model,再回传实现View的数据刷新。android
视图(View) - 用户看到的图形界面,由界面设计人员负责。程序员
模型(Model) - 保存数据状态,其中由程序员编写程序应有的功能(实现算法等等)、数据库专家进行数据管理和数据库设计(能够实现具体的功能)。算法
MVC架构:Model(数据)以Controller(控制器)设定的方式呈如今View(用户界面)中。数据库
简而言之:Adapter在其中充当Controller(控制器)的角色,在其中设定每个元素长什么样子,怎么排列各个元素的逻辑,再把包含代码逻辑的复杂数据按设定好的样式给View。其中自带的BaseAdapter用得最多。设计模式
常见用法是新建一个类继承自BaseAdapter,重写其中的方法并构造新的方法,结合ListView、GridView控件使用。ListView和GridView的用法类似,只是功能不一样,下面以ListView为例共同进行讲解架构
ListView是一种用于垂直显示的列表控件,若是显示内容过多,则会出现垂直滚动条。样式可参考某宝上购物列表的样子。GridView是以网格的形式排列显示的控件,样式能够类比手机桌面图标的排列。mvc
下面以ListView的Adapter适配器为例(新建类MyListAdapter.java文件源码部分),就如下几个方面进行代码说明:app
public class MyListAdapter extends BaseAdapter { private Context mContext; private LayoutInflater mLayoutInflater; MyListAdapter(Context context) { this.mContext = context; mLayoutInflater = LayoutInflater.from(context); //加载布局管理器 } @Override public int getCount() { //返回值 定义列表Item个数,即列表长度 return 10; } @Override public Object getItem(int position) { //根据position返回对应Item return null; } @Override public long getItemId(int position) { //根据position返回对应Item的Id return 0; } static class ViewHolder { //为了方便复用,Item中元素抽象出来,新建了一个静态类ViewHolder, public ImageView imageView; public TextView tvTitle, tvTime, tvContent; } @Override public View getView(int position, View convertView, ViewGroup parent) { //position 当前Item是界面中的第几个(从0计数) //convertView 展现在界面上的Item //parent convertView的父控件,这里指ListView // 该方法将xml布局转换为view对象 // 经过控件重用减小内存占用,好比一共new convertView x 1000 ,一次性全加载完确定不够用 //这段代码让滑出屏幕的convertView在新滑进来的Item中从新使用,只需修改各控件的值 //未显示的Item保存在构件Recycler里 ViewHolder holder = null; if (convertView == null) { //没有供复用的convertView,新建一个 convertView = mLayoutInflater.inflate(R.layout.layout_list_item, null); holder=new ViewHolder(); holder.imageView = convertView.findViewById(R.id.iv); holder.tvTitle=convertView.findViewById(R.id.tv_title); holder.tvTime=convertView.findViewById(R.id.tv_time); holder.tvContent=convertView.findViewById(R.id.tv_content); convertView.setTag(holder); //Tag不像ID是用标示view的。Tag从本质上来说是就是相关联的view的额外的信息。 //贴上一个标签,这个标签就是ViewHolder实例化后对象的一个属性,标示此时带有holder的convertView //以后对于ViewHolder实例化的对象holder的操做, //都会由于java的引用机制而一直存活并改变convertView的内容 } else{ //有供复用的convertView,给控件重赋值,setText()自定义文本内容 holder= (ViewHolder) convertView.getTag(); 取到此时带有holder的convertView } holder.tvTitle.setText("这是标题"); holder.tvTime.setText("2020-02-18"); holder.tvContent.setText("这是内容"); return convertView; }}
官方定义为: A flexible view for providing a limited window into a large data set.
RecyclerView可以灵活展现大数据集,视图的复用管理比前二者(ListView、GridView)更好,经过加载不一样的布局管理器(LayoutManager)可显示列表(LinerLayoutManager)、网格(GridLayoutManager)、瀑布流(StaggeredGridLayoutManager)等形式,且不一样ViewHolder可实现item多元化的功能。标准化了ViewHolder,编写Adapter面向的是ViewHolder而再也不是View,使得复用的逻辑被封装,写起来更加简单,并且直接省去了listview中convertView.setTag(holder)和convertView.getTag()这些繁琐的步骤。
RecyclerView的四大组成是:
设计demo以下,采用LinearLayoutManager,和ListView效果相同,单数和双数采用不一样的holder,实现了点击和长按事件
首先须要在app/build.gradle中
引入包,版本自定
(androidx为 implementation 'androidx.recyclerview:recyclerview:1.0.0'
)
或者导入design库,版本自定
(androidx为implementation 'com.google.android.material:material:1.1.0-alpha09'
)
分别设置Activity(LinearRecyclerViewActivity)和Item(layout_linear_item)的布局文件
指定布局管理器LayoutManager ,用于肯定RecyclerView中Item的展现方式以及决定什么时候复用已经不可见的Item,避免重复建立以及执行高成本的findViewById()方法。
mRvMain.setLayoutManager(new LinearLayoutManager(LinearRecyclerViewActivity.this));
设置装饰样式
addItemDecoration能够容许应用给Adapter中来的View加特效和布局偏移,这对于在View间加分割线,高亮显示,可视化分组都颇有用。
能够看做是给View加特技,一个个加的过程当中若是加相同的特技,就起到分隔的做用;若是这几个加一种特技,另外几个加别的特技,就能够起到分组的做用;若是某几个加特技,就能够起到高亮的做用。
mRvMain.addItemDecoration(new MyDecoration()); class MyDecoration extends RecyclerView.ItemDecoration{ //可从新定义如下三种方法中的任一种 public void onDraw(Canvas c, RecyclerView parent, State state) //在Canvas上绘制内容,在绘制Item以前调用。 //(若是没有经过getItemOffsets设置偏移的话,Item的内容会将其覆盖) public void onDrawOver(Canvas c, RecyclerView parent, State state) //在Canvas上绘制内容,在Item以后调用。(画的内容会覆盖在Item的上层) public void getItemOffsets(Rect outRect, View view, RecyclerView parent, State state) //经过Rect为每一个Item设置偏移,用于绘制Decoration。 }
RecyclerView的背景、onDraw绘制的内容、Item、onDrawOver绘制的内容,各层级关系以下:
指定适配器Adapter继承自RecyclerView.Adapter类
public class LinearAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> //也可建立静态内部类ViewHolder继承自RecyclerView.ViewHolder
RecyclerView将ListView中getView()的功能拆分红了onCreateViewHolder()
和 onBindViewHolder()
。
实现3个方法
天哥的视频演示中跳过了长按事件的代码,这里做下补充
LinearAdapter.java中
private OnItemLongClickListener mLongListener; //新建私有变量用于保存监听器及set方法,这里的set方法统一放在下面的Adapter里了 public LinearAdapter(Context context, OnItemClickListener listener, OnItemLongClickListener Longlistener) { ... this.mLongListener = Longlistener; //至关于setOnItemLongClickListener()方法 } public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, final int position) { ... holder.itemView.setOnLongClickListener(new View.OnLongClickListener() { //实现回调 @Override public boolean onLongClick(View v) { mLongListener.onLongClick(position); Toast.makeText(mContext,"长按 pos:"+position,Toast.LENGTH_SHORT).show(); //另外一种方法是在相应的Activity中设置Toast return true; //源码这里已经给出解释,若是返回值设为true,则系统消耗掉长按事件,这样就不会和点击事件冲突 } }); } public interface OnItemLongClickListener { void onLongClick(int pos);//新建内部接口 }
另外一种方法,上述代码中的Toast语句删去。
还需在LinearRecyclerViewActivity.java添加
mRvMain.setAdapter(new LinearAdapter(LinearRecyclerViewActivity.this, new LinearAdapter.OnItemClickListener() {...}, new LinearAdapter.OnItemLongClickListener(){ @Override public void onLongClick(int pos) { Toast.makeText(LinearRecyclerViewActivity.this,"longClick"+pos,Toast.LENGTH_SHORT).show(); }}));
Android 经常使用控件及使用方法
Android Activity,Adapter基础讲解|菜鸟教程
https://www.runoob.com/android/android-acitivities.html
https://www.runoob.com/w3cnote/android-tutorial-adapter.html
Android与MVC设计模式
Android MVC 模式的介绍与实战
BaseAdapter中getView()里的3个参数是什么意思https://zhidao.baidu.com/question/1382059394224466060.html?qbl=relate_question_1&word=public%20View%20getView%28int%20position%2C%20View%20convertView%2C%20ViewGroup%20parent%29
对convertView的理解
convertView&setTag方法的一点理解
Android Adapter以及getView()方法的理解
Android 控件 RecyclerView
ItemDecoration学习
RecyclerView:打造悬浮效果
探究onCreateViewHolder和onBindViewHolder二者关系和调用次数
揭开RecyclerView的神秘面纱(二):处理RecyclerView的点击事件