在现版本中,滚动控件有多种,而相比于ListView,GridView,RecyclerView的用途更广,因此将前两者作为Adapter适配器的引入,再对RecyclerView进行简单讲解。

MVC & Adapter

为了方便理解,这里介绍一下Android应用设计的基础,也就是MVC架构,如图。

  • 控制器(Controller)- 可看作一个中间桥梁,响应来自View的用户交互,通过对View设定的事件逻辑修改Model,再回传实现View的数据刷新。

  • 视图(View) - 用户看到的图形界面,由界面设计人员负责。

  • 模型(Model) - 保存数据状态,其中由程序员编写程序应有的功能(实现算法等等)、数据库专家进行数据管理和数据库设计(可以实现具体的功能)。

MVC架构:Model(数据)以Controller(控制器)设定的方式呈现在View(用户界面)中。

简而言之:Adapter在其中充当Controller(控制器)的角色,在其中设定每一个元素长什么样子,怎么排列各个元素的逻辑,再把包含代码逻辑的复杂数据按设定好的样式给View。其中自带的BaseAdapter用得最多。

常见用法是新建一个类继承自BaseAdapter,重写其中的方法并构造新的方法,结合ListView、GridView控件使用。ListView和GridView的用法相似,只是功能不同,下面以ListView为例共同进行讲解

ListView & GridView

ListView是一种用于垂直显示的列表控件,如果显示内容过多,则会出现垂直滚动条。样式可参考某宝上购物列表的样子。GridView是以网格的形式排列显示的控件,样式可以类比手机桌面图标的排列。

下面以ListView的Adapter适配器为例(新建类MyListAdapter.java文件源码部分),就以下几个方面进行代码说明:

  • 重写的两个方法 getCount(),getView() getItemId(),getItem()保持默认
  • getView()参数说明及原理
  • setTag()和getTag()原理简述
  1. public class MyListAdapter extends BaseAdapter {
  2. private Context mContext;
  3. private LayoutInflater mLayoutInflater;
  4. MyListAdapter(Context context) {
  5. this.mContext = context;
  6. mLayoutInflater = LayoutInflater.from(context);
  7. //加载布局管理器
  8. }
  9. @Override
  10. public int getCount() {
  11. //返回值 定义列表Item个数,即列表长度
  12. return 10;
  13. }
  14. @Override
  15. public Object getItem(int position) {
  16. //根据position返回对应Item
  17. return null; }
  18. @Override
  19. public long getItemId(int position) {
  20. //根据position返回对应Item的Id
  21. return 0; }
  22. static class ViewHolder {
  23. //为了方便复用,Item中元素抽象出来,新建了一个静态类ViewHolder,
  24. public ImageView imageView;
  25. public TextView tvTitle, tvTime, tvContent; }
  26. @Override
  27. public View getView(int position, View convertView, ViewGroup parent) {
  28. //position 当前Item是界面中的第几个(从0计数)
  29. //convertView 展示在界面上的Item
  30. //parent convertView的父控件,这里指ListView
  31. // 该方法将xml布局转换为view对象
  32. // 通过控件重用减少内存占用,比如一共new convertView x 1000 ,一次性全加载完肯定不够用
  33. //这段代码让滑出屏幕的convertView在新滑进来的Item中重新使用,只需修改各控件的值
  34. //未显示的Item保存在构件Recycler里
  35. ViewHolder holder = null;
  36. if (convertView == null) {
  37. //没有供复用的convertView,新建一个
  38. convertView = mLayoutInflater.inflate(R.layout.layout_list_item, null);
  39. holder=new ViewHolder();
  40. holder.imageView = convertView.findViewById(R.id.iv);
  41. holder.tvTitle=convertView.findViewById(R.id.tv_title);
  42. holder.tvTime=convertView.findViewById(R.id.tv_time);
  43. holder.tvContent=convertView.findViewById(R.id.tv_content);
  44. convertView.setTag(holder);
  45. //Tag不像ID是用标示view的。Tag从本质上来讲是就是相关联的view的额外的信息。
  46. //贴上一个标签,这个标签就是ViewHolder实例化后对象的一个属性,标示此时带有holder的convertView
  47. //之后对于ViewHolder实例化的对象holder的操作,
  48. //都会因为java的引用机制而一直存活并改变convertView的内容
  49. }
  50. else{
  51. //有供复用的convertView,给控件重赋值,setText()自定义文本内容
  52. holder= (ViewHolder) convertView.getTag();
  53. 取到此时带有holderconvertView
  54. }
  55. holder.tvTitle.setText("这是标题");
  56. holder.tvTime.setText("2020-02-18");
  57. holder.tvContent.setText("这是内容");
  58. return convertView; }}

RecyclerView

官方定义为: 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的四大组成是:

  • Layout Manager:Item的布局。
  • Adapter:为Item提供数据。
  • Item Decoration:Item之间的划分样式Divider。
  • Item Animator:添加、删除Item动画。

设计demo如下,采用LinearLayoutManager,和ListView效果相同,单数和双数采用不同的holder,实现了点击和长按事件

使用步骤(以列表视图为例)

  1. 首先需要在app/build.gradle中

    引入包,版本自定

    (androidx为 implementation 'androidx.recyclerview:recyclerview:1.0.0')

    或者导入design库,版本自定

    (androidx为implementation 'com.google.android.material:material:1.1.0-alpha09')

  2. 分别设置Activity(LinearRecyclerViewActivity)和Item(layout_linear_item)的布局文件

  3. 指定布局管理器LayoutManager ,用于确定RecyclerView中Item的展示方式以及决定何时复用已经不可见的Item,避免重复创建以及执行高成本的findViewById()方法。

    1. mRvMain.setLayoutManager(new LinearLayoutManager(LinearRecyclerViewActivity.this));
  4. 设置装饰样式

    addItemDecoration可以允许应用给Adapter中来的View加特效和布局偏移,这对于在View间加分割线,高亮显示,可视化分组都很有用。

    可以看作是给View加特技,一个个加的过程中如果加相同的特技,就起到分隔的作用;如果这几个加一种特技,另外几个加别的特技,就可以起到分组的作用;如果某几个加特技,就可以起到高亮的作用。

    1. mRvMain.addItemDecoration(new MyDecoration());
    2. class MyDecoration extends RecyclerView.ItemDecoration{
    3. //可重新定义以下三种方法中的任一种
    4. public void onDraw(Canvas c, RecyclerView parent, State state)
    5. //在Canvas上绘制内容,在绘制Item之前调用。
    6. //(如果没有通过getItemOffsets设置偏移的话,Item的内容会将其覆盖)
    7. public void onDrawOver(Canvas c, RecyclerView parent, State state)
    8. //在Canvas上绘制内容,在Item之后调用。(画的内容会覆盖在Item的上层)
    9. public void getItemOffsets(Rect outRect, View view, RecyclerView parent, State state)
    10. //通过Rect为每个Item设置偏移,用于绘制Decoration。
    11. }

    RecyclerView的背景、onDraw绘制的内容、Item、onDrawOver绘制的内容,各层级关系如下:

  5. 指定适配器Adapter继承自RecyclerView.Adapter类

    1. public class LinearAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
    2. //也可创建静态内部类ViewHolder继承自RecyclerView.ViewHolder
  6. RecyclerView将ListView中getView()的功能拆分成了onCreateViewHolder()onBindViewHolder()

  7. 实现3个方法

    • onCreateViewHolder(@NonNull ViewGroup parent, int viewType)

      把View直接封装在ViewHolder中,负责每个Item的布局
    • onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, final int position)

      主要用于适配渲染数据到View中,该方法使用ViewHolder而不是原来的convertView。
    • getItemCount()

      类似于BaseAdapter的getCount(),即定义总共有多少个Item。

长按事件的代码补充

天哥的视频演示中跳过了长按事件的代码,这里作下补充

LinearAdapter.java中

  1. private OnItemLongClickListener mLongListener;
  2. //新建私有变量用于保存监听器及set方法,这里的set方法统一放在下面的Adapter里了
  3. public LinearAdapter(Context context, OnItemClickListener listener, OnItemLongClickListener Longlistener) {
  4. ...
  5. this.mLongListener = Longlistener;
  6. //相当于setOnItemLongClickListener()方法
  7. }
  8. public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, final int position) {
  9. ...
  10. holder.itemView.setOnLongClickListener(new View.OnLongClickListener() {
  11. //实现回调
  12. @Override
  13. public boolean onLongClick(View v) {
  14. mLongListener.onLongClick(position);
  15. Toast.makeText(mContext,"长按 pos:"+position,Toast.LENGTH_SHORT).show();
  16. //另一种方法是在相应的Activity中设置Toast
  17. return true;
  18. //源码这里已经给出解释,如果返回值设为true,则系统消耗掉长按事件,这样就不会和点击事件冲突
  19. }
  20. });
  21. }
  22. public interface OnItemLongClickListener {
  23. void onLongClick(int pos);//新建内部接口
  24. }

另一种方法,上述代码中的Toast语句删去。

还需在LinearRecyclerViewActivity.java添加

  1. mRvMain.setAdapter(new LinearAdapter(LinearRecyclerViewActivity.this, new LinearAdapter.OnItemClickListener() {...},
  2. new LinearAdapter.OnItemLongClickListener(){
  3. @Override
  4. public void onLongClick(int pos) {
  5. Toast.makeText(LinearRecyclerViewActivity.this,"longClick"+pos,Toast.LENGTH_SHORT).show();
  6. }}));

参考资料

  1. Android 常用控件及使用方法

    https://wenku.baidu.com/view/70ca306225c52cc58bd6bec6.html

  2. Android Activity,Adapter基础讲解|菜鸟教程

    https://www.runoob.com/android/android-acitivities.html

    https://www.runoob.com/w3cnote/android-tutorial-adapter.html

  3. Android与MVC设计模式

    https://www.cnblogs.com/vi3nty/p/7593973.html

  4. Android MVC 模式的介绍与实战

    https://blog.csdn.net/qq_27061049/article/details/83061248

  5. BaseAdapter中getView()里的3个参数是什么意思https://zhidao.baidu.com/question/1382059394224466060.html?qbl=relate_question_1&word=public View getView(int position%2C View convertView%2C ViewGroup parent)

  6. 对convertView的理解

    https://www.cnblogs.com/tekkaman/p/6268337.html

  7. convertView&setTag方法的一点理解

    https://blog.csdn.net/xiao_ziqiang/article/details/50812471

  8. Android Adapter以及getView()方法的理解

    https://www.cnblogs.com/vice/p/9043086.html

  9. Android 控件 RecyclerView

    https://www.jianshu.com/p/4f9591291365

  10. ItemDecoration学习

    https://www.jianshu.com/p/986605949373

  11. RecyclerView:打造悬浮效果

    http://www.sohu.com/a/199914786_465908

  12. 探究onCreateViewHolder和onBindViewHolder两者关系和调用次数

    https://blog.csdn.net/csdn_aiyang/article/details/80094302

  13. 揭开RecyclerView的神秘面纱(二):处理RecyclerView的点击事件

    https://www.jianshu.com/p/f2e0463e5aef

  14. Android开发视频教程最新版 Android Studio开发

    https://www.bilibili.com/video/av38409964?t=2327&p=14

Android Studio 学习笔记(四):Adapter和RecyclerView说明的更多相关文章

  1. Android Studio 学习笔记(一)环境搭建、文件目录等相关说明

    Android Studio 学习笔记(一)环境搭建.文件目录等相关说明 引入 对APP开发而言,Android和iOS是两大主流开发平台,其中区别在于 Android用java语言,用Android ...

  2. Android Studio学习笔记

    转:http://stormzhang.com/devtools/2014/11/25/android-studio-tutorial1 背景 相信大家对Android Studio已经不陌生了,An ...

  3. Android Studio 学习笔记(1)

    最近从Eclipse转到Android Studio IDE,很多东西需要学习,本文是个记录. 项目结构 在Anroid Studio 中,一个Project 包括多个Module,每个Module下 ...

  4. Android Studio 学习笔记1.1 创建自己的第一个安卓项目并且打包APK

      自从上一次安装完安卓开发工具Android Studio后抽时间看视屏尝试编写自己的第一个安卓项目约两周的时间 每天下班后会花上1~2小时的时间去学习 目前的成果如下:次元宅的我.apk 嘛 总而 ...

  5. Android Studio 学习笔记(三):简单控件及实例

    控件.组件.插件概念区分 说到控件,就不得不区分一些概念. 控件(Control):编程中用到的部件 组件(Component):软件的组成部分 插件(plugin): 应用程序中已经预留接口的组件 ...

  6. Android Studio 学习笔记(二):布局简介和xmlns说明

    初学Android Studio,是在b站看的教程视频,这里的笔记也是以其为基础的,个人强烈安利: [天哥]Android开发视频教程最新版 Android Studio开发 Android 布局简介 ...

  7. Android Studio 学习笔记(五):WebView 简单说明

    Android中一个用于网页显示的控件,实际上,也可以看做一个功能最小化的浏览器,看起来类似于在微信中打开网页链接的页面.WebView主要用于在app应用中方便地访问远程网页或本地html资源.同时 ...

  8. Android Studio 学习(四) 数据库

    文件存储 写数据 String data = "Data ti save"; FileOutputStream out =null; BufferedWriter writer = ...

  9. Git for Android Studio 学习笔记

    http://learngitbranching.js.org/ 一个特别好的git学习教程 创建一个project,然后导入github

随机推荐

  1. 实验五:配置Eth-Trunk链路聚合(手工负载分担模式)

    1.配置图 2.配置命令 LSW1的eth trunk 1配置如下: 配置命令如下: [S1]Eth-Trunk1 创建Eth-Trunk1端口 [S1-Eth-Trunk1]mode lacp-st ...

  2. Kdenlive-简单的操作

    版权声明:原创文章,未经博主允许不得转载 前章:https://www.cnblogs.com/weilinfox/p/12246123.html 尽管是简单操作,但内容比较多.可以一边自己尝试编辑一 ...

  3. pc端的弹性布局适配方案

    方案及原理:使用rem单位,通过window.onresize来监听浏览器窗口,获取窗口宽度,并改变跟字体大小来达到弹性适配效果. function adaptor(){ //为了便于计算,这里以19 ...

  4. 【Nginx入门系列】第三章 通过端口号区分虚拟主机

    1.配置虚拟主机 (1)连接Nginx所在的服务器(我使用的是putty) (2)切换到nginx.conf 配置文件所在的目录,我目录是/usr/local/nginx/conf (3)增加一个虚拟 ...

  5. 前端入门nginx

    一.nginx是什么 NGINX is a free, open-source, high-performance HTTP server and reverse proxy, as well as ...

  6. 一次DB故障引起的反思和MySQL Operator选型

    前言 在一次数据库故障后,我们发现业务库会根据业务的等级会划分多个 MySQL 实例,许多业务库会同时属于一个 MySQL 实例,当一个库引发问题后整个实例的状态是不可控的.从而导致这个实例上的所有业 ...

  7. Android之SimpleAdapter简单实例和SimpleAdapter参数说明

    SimpleAdapter基本上认知了其参数含义 用起来就简单多了 SimpleAdapter的参数说明 第一个参数 表示访问整个android应用程序接口,基本上所有的组件都需要  第二个参数表示生 ...

  8. List<E> 、Set<E>和Map<K,E>的简单应用

    题目一: 创建两个线性表,分别存储{“chen”,“wang”,“liu”,“zhang”}和{“chen”,“hu”,“zhang”},求这两个线性表的交集和并集. 代码: List_Test.ja ...

  9. HDU_5057_分块

    http://acm.hdu.edu.cn/showproblem.php?pid=5057 分块,保存每个块中每位对应数字的和,复杂的是getmum,左右下标所在的块不能直接读取block数组,要重 ...

  10. Educational Codeforces Round 39 Editorial B(Euclid算法,连续-=与%=的效率)

    You have two variables a and b. Consider the following sequence of actions performed with these vari ...