前言
眼下都2020年了,你不会还在使用ListView吧?
正文
因为最近写的一个项目里面有关于列表的编辑相关的功能,其实也是类似与腾讯视频的观看历史的列表操作,你可以先尝试一下,写这个主要是业务逻辑要清晰,否则你很容易就会陷进去,走死胡同的。
效果图如下:
迫不及待想要自己运行在AS中的小伙伴可以直接下载或者克隆,打开即可,想了解具体开发流程和详细的业务逻辑的小伙伴,可以继续往下看,本章很长,请在流量和时间充足的前提下观看,如有问题,评论即可,我会尽快解决,多说无益,开搞~
开发
① 新建项目
这一步没有什么好说的,但是你也要注意自己的Android Studio和Gradle的版本,我的是3.5.2。点击项目创建
② 配置build.gradle
第一步
在工程级别的build.gradle文件中的allprojects{} 闭包中添加maven库
maven { url "https://jitpack.io" }
第二步
在项目级别的build.gradle文件中的android{}闭包中,配置JDK的版本
compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 }
然后在dependencies{}闭包中添加第三方的依赖库
//绑定视图 implementation 'com.jakewharton:butterknife:10.2.1' annotationProcessor 'com.jakewharton:butterknife-compiler:10.2.1' //RecyclerView implementation 'androidx.recyclerview:recyclerview:1.1.0' //下拉刷新 implementation 'com.scwang.smartrefresh:SmartRefreshLayout:1.1.0-alpha-14' //RecyclerView适配器 implementation 'com.github.CymChad:BaseRecyclerViewAdapterHelper:2.9.22' //热门强大的图片加载器 implementation 'com.github.bumptech.glide:glide:4.9.0'
然后右上角 Sync Now,点击同步你的项目配置文件,同步会下载第三方的库文件,等待完成进行下一步。
③ 修改布局
在此之前,为了增加点击效果,在res → drawable 下创建rounded_corners.xml文件
代码如下:
<?xml version="1.0" encoding="utf-8"?> <selector xmlns:android="http://schemas.android.com/apk/res/android"> <item android:state_pressed="true"> <shape android:shape="rectangle"> <solid android:color="#18ffc400"/> </shape> </item> <item android:state_focused="true" android:state_enabled="true"> <shape android:shape="rectangle"> <solid android:color="#0f000000"/> </shape> </item> </selector>
然后在res下新建一个drawable-v21的文件夹,在文件夹中创建bg_white.xml文件,代码如下:
<?xml version="1.0" encoding="utf-8"?> <ripple xmlns:android="http://schemas.android.com/apk/res/android" android:color="#20000000" android:drawable="@drawable/rounded_corners"/>
在drawable文件下再创建一个shape_blue_bg_5.xml
代码如下:
<?xml version="1.0" encoding="utf-8"?> <shape xmlns:android="http://schemas.android.com/apk/res/android"> <corners android:radius="5dp"/> <solid android:color="#101B53"/> </shape>
然后是修改values文件夹下的colors.xml文件,修改原来的并增加几个颜色,
<?xml version="1.0" encoding="utf-8"?> <resources> <color name="colorPrimary">#1F2B5D</color> <color name="colorPrimaryDark">#1F2B5D</color> <color name="colorAccent">#D81B60</color> <color name="default_color">#48558C</color> <color name="selected_color">#009FE8</color> <color name="app_color">#1F2B5D</color> <color name="app_bg_color">#020C49</color> <color name="white">#FFFFFF</color> <color name="gray">#8A96A3</color> <color name="yellow">#F39700</color> </resources>
再修改一下styles.xml文件
布局中会用到下面的图片
icon_normal.png
icon_choose_selected.png
icon_choose_default.png
修改activity_main.xml文件,修改后如下图所示
代码如下,复制粘贴即可:
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout 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:background="@color/app_bg_color" android:fitsSystemWindows="true" tools:context=".MainActivity"> <!--头部--> <androidx.appcompat.widget.Toolbar android:id="@+id/toolbar" android:layout_width="match_parent" android:layout_height="?attr/actionBarSize" android:background="?attr/colorPrimary" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintTop_toTopOf="parent"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:text="RecyclerView Demo" android:textColor="@color/white" android:textSize="18sp" /> <TextView android:id="@+id/tv_edit" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="right" android:layout_marginRight="8dp" android:padding="8dp" android:text="编辑" android:textColor="@color/white" android:textSize="16sp" /> </androidx.appcompat.widget.Toolbar> <RelativeLayout android:layout_width="match_parent" android:layout_height="match_parent" android:layout_below="@+id/toolbar" android:layout_above="@+id/lay_bottom"> <!--无数据时的布局--> <LinearLayout android:id="@+id/rv_normal_show" android:layout_width="match_parent" android:layout_height="match_parent" android:gravity="center" android:orientation="vertical"> <ImageView android:layout_width="264dp" android:layout_height="140dp" android:background="@mipmap/icon_normal" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="@dimen/dp_10" android:text="空空如也" android:textColor="@color/gray" android:textSize="18sp" /> </LinearLayout> <!--没有数据时,下拉重新添加数据--> <com.scwang.smartrefresh.layout.SmartRefreshLayout android:id="@+id/refresh" android:layout_width="match_parent" android:layout_height="match_parent"> <!--展示数据的列表--> <androidx.recyclerview.widget.RecyclerView android:id="@+id/rv" android:layout_width="match_parent" android:layout_height="match_parent" android:padding="12dp" android:visibility="gone" /> </com.scwang.smartrefresh.layout.SmartRefreshLayout> </RelativeLayout> <!--底部--> <LinearLayout android:id="@+id/lay_bottom" android:layout_width="match_parent" android:layout_height="50dp" android:layout_alignParentBottom="true" android:background="@color/colorPrimary" android:orientation="horizontal" android:visibility="gone"> <TextView android:id="@+id/tv_check_all" android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1" android:foreground="@drawable/bg_white" android:gravity="center" android:text="全选" android:textColor="@color/white" android:textSize="@dimen/sp_14" /> <View android:layout_width="1dp" android:layout_height="match_parent" android:layout_marginTop="12dp" android:layout_marginBottom="12dp" android:background="@color/app_bg_color" /> <TextView android:id="@+id/tv_delete" android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1" android:foreground="@drawable/bg_white" android:gravity="center" android:text="删除" android:textColor="@color/yellow" android:textSize="14sp" /> </LinearLayout> </RelativeLayout>
然后是创建一个数据实体DataResponse.java
代码如下,复制粘贴即可:
package com.llw.recyclerviewusedemo; import java.util.List; /** * 数据实体 */ public class DataResponse { /** * data : [{"_id":"5e959250808d6d2fe6b56eda","author":"鸢媛","category":"Girl","createdAt":"2020-05-25 08:00:00","desc":"与其安慰自己平凡可贵,\n不如拼尽全力活得漂亮。 \u200b \u200b\u200b\u200b\u200b","images":["http://gank.io/images/f4f6d68bf30147e1bdd4ddbc6ad7c2a2"],"likeCounts":0,"publishedAt":"2020-05-25 08:00:00","stars":1,"title":"第96期","type":"Girl","url":"http://gank.io/images/f4f6d68bf30147e1bdd4ddbc6ad7c2a2","views":131},{"_id":"5e95923f808d6d2fe6b56ed8","author":"鸢媛","category":"Girl","createdAt":"2020-05-24 08:00:00","desc":"这世界总有人在笨拙地爱着你,想把全部的温柔都给你。 \u200b\u200b\u200b\u200b","images":["http://gank.io/images/dc75cbde1d98448183e2f9514b4d1320"],"likeCounts":0,"publishedAt":"2020-05-24 08:00:00","stars":1,"title":"第95期","type":"Girl","url":"http://gank.io/images/dc75cbde1d98448183e2f9514b4d1320","views":133},{"_id":"5e95922e808d6d2fe6b56ed6","author":"鸢媛","category":"Girl","createdAt":"2020-05-23 08:00:00","desc":"陪伴本来就是这世界上最了不起的安慰\u200b。","images":["http://gank.io/images/6b2efa591564475fb8bc32291fb0007c"],"likeCounts":0,"publishedAt":"2020-05-23 08:00:00","stars":1,"title":"第94期","type":"Girl","url":"http://gank.io/images/6b2efa591564475fb8bc32291fb0007c","views":135},{"_id":"5e959200ee6ba981da2af34d","author":"鸢媛","category":"Girl","createdAt":"2020-05-22 08:00:00","desc":"长不过执念,短不过善变。","images":["http://gank.io/images/d6bba8cf5b8c40f9ad229844475e9149"],"likeCounts":0,"publishedAt":"2020-05-22 08:00:00","stars":1,"title":"第93期","type":"Girl","url":"http://gank.io/images/d6bba8cf5b8c40f9ad229844475e9149","views":192},{"_id":"5e9591dcee6ba981da2af34b","author":"鸢媛","category":"Girl","createdAt":"2020-05-21 08:00:00","desc":"无论多么艰难的现在,终会翻篇。\n朝未来大步向前吧,别丧,别止步。","images":["http://gank.io/images/9fa43020cf724c69842eec3e13f6d21c"],"likeCounts":1,"publishedAt":"2020-05-21 08:00:00","stars":1,"title":"第92期","type":"Girl","url":"http://gank.io/images/9fa43020cf724c69842eec3e13f6d21c","views":176},{"_id":"5e9591c60bd5529b54e712af","author":"鸢媛","category":"Girl","createdAt":"2020-05-20 08:00:00","desc":"希望下一次,能喜欢上一个也喜欢自己的人 \u200b\u200b\u200b\u200b。","images":["http://gank.io/images/d237f507bf1946d2b0976e581f8aab9b"],"likeCounts":0,"publishedAt":"2020-05-20 08:00:00","stars":1,"title":"第91期","type":"Girl","url":"http://gank.io/images/d237f507bf1946d2b0976e581f8aab9b","views":180},{"_id":"5e9591b6808d6d2fe6b56ed5","author":"鸢媛","category":"Girl","createdAt":"2020-05-19 08:00:00","desc":"这个世界上,\n有些人有多冷漠,\n有些人就有多温暖,\n希望你总会遇到那些温暖对你的人。","images":["http://gank.io/images/25d3e3db2c1248bb917c09dc4f50a46f"],"likeCounts":0,"publishedAt":"2020-05-19 08:00:00","stars":1,"title":"第90期","type":"Girl","url":"http://gank.io/images/25d3e3db2c1248bb917c09dc4f50a46f","views":255},{"_id":"5e9591a2ee6ba981da2af34a","author":"鸢媛","category":"Girl","createdAt":"2020-05-18 08:00:00","desc":"以前对你的喜欢,\n是见你,念你,陪伴你。\n现在对你的喜欢,\n是不问,不看,不叨扰。","images":["http://gank.io/images/19c99c447e0a40a6b3ff89951957cfb1"],"likeCounts":0,"publishedAt":"2020-05-18 08:00:00","stars":1,"title":"第89期","type":"Girl","url":"http://gank.io/images/19c99c447e0a40a6b3ff89951957cfb1","views":240},{"_id":"5e959197808d6d2fe6b56ed4","author":"鸢媛","category":"Girl","createdAt":"2020-05-17 08:00:00","desc":"只要结局是喜剧,过程你要我怎么哭都行,幸福可以来的慢一些,\n只要它是真的,如果最后能在一起,晚点我真的无所谓的。","images":["http://gank.io/images/f0c192e3e335400db8a709a07a891b2e"],"likeCounts":0,"publishedAt":"2020-05-17 08:00:00","stars":1,"title":"第88期","type":"Girl","url":"http://gank.io/images/f0c192e3e335400db8a709a07a891b2e","views":275},{"_id":"5e95915f808d6d2fe6b56ed3","author":"鸢媛","category":"Girl","createdAt":"2020-05-16 08:00:00","desc":"若不是情深似海,思念又怎会泛滥成灾。","images":["http://gank.io/images/bdb35e4b3c0045c799cc7a494a3db3e0"],"likeCounts":0,"publishedAt":"2020-05-16 08:00:00","stars":1,"title":"第87期","type":"Girl","url":"http://gank.io/images/bdb35e4b3c0045c799cc7a494a3db3e0","views":437}] * page : 1 * page_count : 10 * status : 100 * total_counts : 96 */ private int page; private int page_count; private int status; private int total_counts; private List<DataBean> data; public int getPage() { return page; } public void setPage(int page) { this.page = page; } public int getPage_count() { return page_count; } public void setPage_count(int page_count) { this.page_count = page_count; } public int getStatus() { return status; } public void setStatus(int status) { this.status = status; } public int getTotal_counts() { return total_counts; } public void setTotal_counts(int total_counts) { this.total_counts = total_counts; } public List<DataBean> getData() { return data; } public void setData(List<DataBean> data) { this.data = data; } public static class DataBean { /** * _id : 5e959250808d6d2fe6b56eda * author : 鸢媛 * category : Girl * createdAt : 2020-05-25 08:00:00 * desc : 与其安慰自己平凡可贵, 不如拼尽全力活得漂亮。 * images : ["http://gank.io/images/f4f6d68bf30147e1bdd4ddbc6ad7c2a2"] * likeCounts : 0 * publishedAt : 2020-05-25 08:00:00 * stars : 1 * title : 第96期 * type : Girl * url : http://gank.io/images/f4f6d68bf30147e1bdd4ddbc6ad7c2a2 * views : 131 */ private String _id; private String author; private String category; private String createdAt; private String desc; private int likeCounts; private String publishedAt; private int stars; private String title; private String type; private String url; private int views; private List<String> images; private boolean select = false; public String get_id() { return _id; } public void set_id(String _id) { this._id = _id; } public String getAuthor() { return author; } public void setAuthor(String author) { this.author = author; } public String getCategory() { return category; } public void setCategory(String category) { this.category = category; } public String getCreatedAt() { return createdAt; } public void setCreatedAt(String createdAt) { this.createdAt = createdAt; } public String getDesc() { return desc; } public void setDesc(String desc) { this.desc = desc; } public int getLikeCounts() { return likeCounts; } public void setLikeCounts(int likeCounts) { this.likeCounts = likeCounts; } public String getPublishedAt() { return publishedAt; } public void setPublishedAt(String publishedAt) { this.publishedAt = publishedAt; } public int getStars() { return stars; } public void setStars(int stars) { this.stars = stars; } public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } public String getType() { return type; } public void setType(String type) { this.type = type; } public String getUrl() { return url; } public void setUrl(String url) { this.url = url; } public int getViews() { return views; } public void setViews(int views) { this.views = views; } public List<String> getImages() { return images; } public void setImages(List<String> images) { this.images = images; } public boolean isSelect() { return select; } public void setSelect(boolean select) { this.select = select; } } }
再创建一个JsonData.java,存放用于转换的JSON数据
代码如下,复制粘贴即可:
package com.llw.recyclerviewusedemo; public class JsonData { public static String JSON = "{\"data\":[{\"_id\":\"5e959250808d6d2fe6b56eda\",\"author\":\"\\u9e22\\u5a9b\",\"category\":\"Girl\",\"createdAt\":\"2020-05-25 08:00:00\",\"desc\":\"\\u4e0e\\u5176\\u5b89\\u6170\\u81ea\\u5df1\\u5e73\\u51e1\\u53ef\\u8d35\\uff0c\\n\\u4e0d\\u5982\\u62fc\\u5c3d\\u5168\\u529b\\u6d3b\\u5f97\\u6f02\\u4eae\\u3002 \\u200b \\u200b\\u200b\\u200b\\u200b\",\"images\":[\"http://gank.io/images/f4f6d68bf30147e1bdd4ddbc6ad7c2a2\"],\"likeCounts\":0,\"publishedAt\":\"2020-05-25 08:00:00\",\"stars\":1,\"title\":\"\\u7b2c96\\u671f\",\"type\":\"Girl\",\"url\":\"http://gank.io/images/f4f6d68bf30147e1bdd4ddbc6ad7c2a2\",\"views\":131},{\"_id\":\"5e95923f808d6d2fe6b56ed8\",\"author\":\"\\u9e22\\u5a9b\",\"category\":\"Girl\",\"createdAt\":\"2020-05-24 08:00:00\",\"desc\":\"\\u8fd9\\u4e16\\u754c\\u603b\\u6709\\u4eba\\u5728\\u7b28\\u62d9\\u5730\\u7231\\u7740\\u4f60\\uff0c\\u60f3\\u628a\\u5168\\u90e8\\u7684\\u6e29\\u67d4\\u90fd\\u7ed9\\u4f60\\u3002 \\u200b\\u200b\\u200b\\u200b\",\"images\":[\"http://gank.io/images/dc75cbde1d98448183e2f9514b4d1320\"],\"likeCounts\":0,\"publishedAt\":\"2020-05-24 08:00:00\",\"stars\":1,\"title\":\"\\u7b2c95\\u671f\",\"type\":\"Girl\",\"url\":\"http://gank.io/images/dc75cbde1d98448183e2f9514b4d1320\",\"views\":133},{\"_id\":\"5e95922e808d6d2fe6b56ed6\",\"author\":\"\\u9e22\\u5a9b\",\"category\":\"Girl\",\"createdAt\":\"2020-05-23 08:00:00\",\"desc\":\"\\u966a\\u4f34\\u672c\\u6765\\u5c31\\u662f\\u8fd9\\u4e16\\u754c\\u4e0a\\u6700\\u4e86\\u4e0d\\u8d77\\u7684\\u5b89\\u6170\\u200b\\u3002\",\"images\":[\"http://gank.io/images/6b2efa591564475fb8bc32291fb0007c\"],\"likeCounts\":0,\"publishedAt\":\"2020-05-23 08:00:00\",\"stars\":1,\"title\":\"\\u7b2c94\\u671f\",\"type\":\"Girl\",\"url\":\"http://gank.io/images/6b2efa591564475fb8bc32291fb0007c\",\"views\":135},{\"_id\":\"5e959200ee6ba981da2af34d\",\"author\":\"\\u9e22\\u5a9b\",\"category\":\"Girl\",\"createdAt\":\"2020-05-22 08:00:00\",\"desc\":\"\\u957f\\u4e0d\\u8fc7\\u6267\\u5ff5\\uff0c\\u77ed\\u4e0d\\u8fc7\\u5584\\u53d8\\u3002\",\"images\":[\"http://gank.io/images/d6bba8cf5b8c40f9ad229844475e9149\"],\"likeCounts\":0,\"publishedAt\":\"2020-05-22 08:00:00\",\"stars\":1,\"title\":\"\\u7b2c93\\u671f\",\"type\":\"Girl\",\"url\":\"http://gank.io/images/d6bba8cf5b8c40f9ad229844475e9149\",\"views\":192},{\"_id\":\"5e9591dcee6ba981da2af34b\",\"author\":\"\\u9e22\\u5a9b\",\"category\":\"Girl\",\"createdAt\":\"2020-05-21 08:00:00\",\"desc\":\"\\u65e0\\u8bba\\u591a\\u4e48\\u8270\\u96be\\u7684\\u73b0\\u5728\\uff0c\\u7ec8\\u4f1a\\u7ffb\\u7bc7\\u3002\\n\\u671d\\u672a\\u6765\\u5927\\u6b65\\u5411\\u524d\\u5427\\uff0c\\u522b\\u4e27\\uff0c\\u522b\\u6b62\\u6b65\\u3002\",\"images\":[\"http://gank.io/images/9fa43020cf724c69842eec3e13f6d21c\"],\"likeCounts\":1,\"publishedAt\":\"2020-05-21 08:00:00\",\"stars\":1,\"title\":\"\\u7b2c92\\u671f\",\"type\":\"Girl\",\"url\":\"http://gank.io/images/9fa43020cf724c69842eec3e13f6d21c\",\"views\":176},{\"_id\":\"5e9591c60bd5529b54e712af\",\"author\":\"\\u9e22\\u5a9b\",\"category\":\"Girl\",\"createdAt\":\"2020-05-20 08:00:00\",\"desc\":\"\\u5e0c\\u671b\\u4e0b\\u4e00\\u6b21\\uff0c\\u80fd\\u559c\\u6b22\\u4e0a\\u4e00\\u4e2a\\u4e5f\\u559c\\u6b22\\u81ea\\u5df1\\u7684\\u4eba \\u200b\\u200b\\u200b\\u200b\\u3002\",\"images\":[\"http://gank.io/images/d237f507bf1946d2b0976e581f8aab9b\"],\"likeCounts\":0,\"publishedAt\":\"2020-05-20 08:00:00\",\"stars\":1,\"title\":\"\\u7b2c91\\u671f\",\"type\":\"Girl\",\"url\":\"http://gank.io/images/d237f507bf1946d2b0976e581f8aab9b\",\"views\":180},{\"_id\":\"5e9591b6808d6d2fe6b56ed5\",\"author\":\"\\u9e22\\u5a9b\",\"category\":\"Girl\",\"createdAt\":\"2020-05-19 08:00:00\",\"desc\":\"\\u8fd9\\u4e2a\\u4e16\\u754c\\u4e0a\\uff0c\\n\\u6709\\u4e9b\\u4eba\\u6709\\u591a\\u51b7\\u6f20\\uff0c\\n\\u6709\\u4e9b\\u4eba\\u5c31\\u6709\\u591a\\u6e29\\u6696\\uff0c\\n\\u5e0c\\u671b\\u4f60\\u603b\\u4f1a\\u9047\\u5230\\u90a3\\u4e9b\\u6e29\\u6696\\u5bf9\\u4f60\\u7684\\u4eba\\u3002\",\"images\":[\"http://gank.io/images/25d3e3db2c1248bb917c09dc4f50a46f\"],\"likeCounts\":0,\"publishedAt\":\"2020-05-19 08:00:00\",\"stars\":1,\"title\":\"\\u7b2c90\\u671f\",\"type\":\"Girl\",\"url\":\"http://gank.io/images/25d3e3db2c1248bb917c09dc4f50a46f\",\"views\":255},{\"_id\":\"5e9591a2ee6ba981da2af34a\",\"author\":\"\\u9e22\\u5a9b\",\"category\":\"Girl\",\"createdAt\":\"2020-05-18 08:00:00\",\"desc\":\"\\u4ee5\\u524d\\u5bf9\\u4f60\\u7684\\u559c\\u6b22\\uff0c\\n\\u662f\\u89c1\\u4f60\\uff0c\\u5ff5\\u4f60\\uff0c\\u966a\\u4f34\\u4f60\\u3002\\n\\u73b0\\u5728\\u5bf9\\u4f60\\u7684\\u559c\\u6b22\\uff0c\\n\\u662f\\u4e0d\\u95ee\\uff0c\\u4e0d\\u770b\\uff0c\\u4e0d\\u53e8\\u6270\\u3002\",\"images\":[\"http://gank.io/images/19c99c447e0a40a6b3ff89951957cfb1\"],\"likeCounts\":0,\"publishedAt\":\"2020-05-18 08:00:00\",\"stars\":1,\"title\":\"\\u7b2c89\\u671f\",\"type\":\"Girl\",\"url\":\"http://gank.io/images/19c99c447e0a40a6b3ff89951957cfb1\",\"views\":240},{\"_id\":\"5e959197808d6d2fe6b56ed4\",\"author\":\"\\u9e22\\u5a9b\",\"category\":\"Girl\",\"createdAt\":\"2020-05-17 08:00:00\",\"desc\":\"\\u53ea\\u8981\\u7ed3\\u5c40\\u662f\\u559c\\u5267\\uff0c\\u8fc7\\u7a0b\\u4f60\\u8981\\u6211\\u600e\\u4e48\\u54ed\\u90fd\\u884c\\uff0c\\u5e78\\u798f\\u53ef\\u4ee5\\u6765\\u7684\\u6162\\u4e00\\u4e9b\\uff0c\\n\\u53ea\\u8981\\u5b83\\u662f\\u771f\\u7684\\uff0c\\u5982\\u679c\\u6700\\u540e\\u80fd\\u5728\\u4e00\\u8d77\\uff0c\\u665a\\u70b9\\u6211\\u771f\\u7684\\u65e0\\u6240\\u8c13\\u7684\\u3002\",\"images\":[\"http://gank.io/images/f0c192e3e335400db8a709a07a891b2e\"],\"likeCounts\":0,\"publishedAt\":\"2020-05-17 08:00:00\",\"stars\":1,\"title\":\"\\u7b2c88\\u671f\",\"type\":\"Girl\",\"url\":\"http://gank.io/images/f0c192e3e335400db8a709a07a891b2e\",\"views\":275},{\"_id\":\"5e95915f808d6d2fe6b56ed3\",\"author\":\"\\u9e22\\u5a9b\",\"category\":\"Girl\",\"createdAt\":\"2020-05-16 08:00:00\",\"desc\":\"\\u82e5\\u4e0d\\u662f\\u60c5\\u6df1\\u4f3c\\u6d77\\uff0c\\u601d\\u5ff5\\u53c8\\u600e\\u4f1a\\u6cdb\\u6ee5\\u6210\\u707e\\u3002\",\"images\":[\"http://gank.io/images/bdb35e4b3c0045c799cc7a494a3db3e0\"],\"likeCounts\":0,\"publishedAt\":\"2020-05-16 08:00:00\",\"stars\":1,\"title\":\"\\u7b2c87\\u671f\",\"type\":\"Girl\",\"url\":\"http://gank.io/images/bdb35e4b3c0045c799cc7a494a3db3e0\",\"views\":437}],\"page\":1,\"page_count\":10,\"status\":100,\"total_counts\":96}"; }
④ 创建列表的item布局文件
在layout文件下创建item_data_list.xml布局文件
代码如下:
<?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" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginBottom="12dp" android:orientation="vertical"> <LinearLayout android:id="@+id/item_data" android:foreground="@drawable/bg_white" android:layout_width="match_parent" android:layout_height="wrap_content" android:background="@drawable/shape_blue_bg_5" android:gravity="center_vertical" android:orientation="horizontal" android:padding="12dp"> <ImageView android:id="@+id/iv_check" android:layout_width="20dp" android:layout_height="20dp" android:layout_marginRight="12dp" android:background="@mipmap/icon_choose_default" android:button="@null" /> <ImageView android:id="@+id/iv_img" android:layout_width="150dp" android:layout_height="200dp" android:background="@drawable/ic_launcher_background" android:scaleType="centerCrop" /> <TextView android:id="@+id/tv_video_info" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginLeft="12dp" android:text="测试数据" android:textColor="@color/white" android:textSize="16sp" /> </LinearLayout> </LinearLayout>
⑤ 列表适配器
创建一个适配器DataAdapter.java
代码如下:
package com.llw.recyclerviewusedemo; import android.view.View; import android.widget.ImageView; import androidx.annotation.Nullable; import com.bumptech.glide.Glide; import com.chad.library.adapter.base.BaseQuickAdapter; import com.chad.library.adapter.base.BaseViewHolder; import java.util.List; /** * 适配器 */ public class DataAdapter extends BaseQuickAdapter<DataResponse.DataBean, BaseViewHolder> { private static final int STATE_DEFAULT = 0;//默认状态 int mEditMode = STATE_DEFAULT; public DataAdapter(int layoutResId, @Nullable List<DataResponse.DataBean> data) { super(layoutResId, data); } @Override protected void convert(BaseViewHolder helper, DataResponse.DataBean item) { //Glide加载网络图片 Glide.with(mContext).load(item.getUrl()).into((ImageView) helper.getView(R.id.iv_img)); //TextView赋值 helper.setText(R.id.tv_video_info, item.getAuthor()); helper.addOnClickListener(R.id.item_data);//添加item点击事件 if (mEditMode == STATE_DEFAULT) { //默认不显示 helper.getView(R.id.iv_check).setVisibility(View.GONE); } else { //显示 显示之后再做点击之后的判断 helper.getView(R.id.iv_check).setVisibility(View.VISIBLE); if (item.isSelect()) {//点击时,true 选中 helper.getView(R.id.iv_check).setBackgroundResource(R.mipmap.icon_choose_selected); } else {//false 取消选中 helper.getView(R.id.iv_check).setBackgroundResource(R.mipmap.icon_choose_default); } } } /** * 设置编辑状态 接收Activity中传递的值,并改变Adapter的状态 */ public void setEditMode(int editMode) { mEditMode = editMode; notifyDataSetChanged();//刷新 } }
⑥ 主要逻辑编写
进入到MainActivity.java
这里绑定一些控件并声明一些需要用到的变量
初始化列表数据
//初始化列表数据 private void initList() { mAdapter = new DataAdapter(R.layout.item_data_list, mList);//绑定视图和数据 rv.setLayoutManager(new LinearLayoutManager(this));//设置线性布局管理器 rv.setAdapter(mAdapter);//设置适配器 Gson gson = new Gson(); DataResponse dataBean = gson.fromJson(JsonData.JSON, DataResponse.class);//解析数据 List<DataResponse.DataBean> resultsBeans = dataBean.getData(); if (resultsBeans.size() > 0) { mList.clear(); mList.addAll(resultsBeans); mAdapter.notifyDataSetChanged();//刷新数据 rv.setVisibility(View.VISIBLE); rvNormalShow.setVisibility(View.GONE); } else { rv.setVisibility(View.GONE); rvNormalShow.setVisibility(View.VISIBLE); } refresh.finishRefresh();//数据加载出来之后,结束下拉动作 }
处理点击事件
//页面的点击事件 @OnClick({R.id.tv_edit, R.id.tv_check_all, R.id.tv_delete}) public void onViewClicked(View view) { switch (view.getId()) { case R.id.tv_edit://编辑 updateEditState(); break; case R.id.tv_check_all://全选 setAllItemChecked(); break; case R.id.tv_delete://删除 deleteCheckItem(); break; } }
改变编辑状态
//改变编辑状态 private void updateEditState() { mEditMode = mEditMode == STATE_DEFAULT ? STATE_EDIT : STATE_DEFAULT; if (mEditMode == STATE_EDIT) { tvEdit.setText("取消"); layBottom.setVisibility(View.VISIBLE); editorStatus = true;//处于编辑状态 } else { tvEdit.setText("编辑"); layBottom.setVisibility(View.GONE); editorStatus = false;//处于默认状态 setAllItemUnchecked();//取消全选 } mAdapter.setEditMode(mEditMode);//刷新Adapter mAdapter.setOnItemChildClickListener(new BaseQuickAdapter.OnItemChildClickListener() { @Override public void onItemChildClick(BaseQuickAdapter adapter, View view, int position) { if (editorStatus) {//编辑状态 DataResponse.DataBean dataBean = mList.get(position);//赋值 boolean isSelect = dataBean.isSelect(); if (!isSelect) { index++; dataBean.setSelect(true); } else { dataBean.setSelect(false); index--; } if (index == 0) {//当前选中item数量 tvDelete.setText("删除"); } else { tvDelete.setText("删除(" + index + ")"); } mAdapter.notifyDataSetChanged(); } } }); }
全部选中
//全部选中 private void setAllItemChecked() { if (mAdapter == null) return; for (int i = 0; i < mList.size(); i++) { mList.get(i).setSelect(true); } mAdapter.notifyDataSetChanged(); index = mList.size(); tvDelete.setText("删除(" + index + ")"); }
取消全部选中
//取消全部选中 private void setAllItemUnchecked() { if (mAdapter == null) return; for (int i = 0; i < mList.size(); i++) { mList.get(i).setSelect(false); } mAdapter.notifyDataSetChanged(); tvDelete.setText("删除"); index = 0; }
删除选中的item
//删除选中的item private void deleteCheckItem() { if (mAdapter == null) return; for (int i = mList.size() - 1; i >= 0; i--) { if (mList.get(i).isSelect() == true) { mList.remove(i); } } //删除选中的item之后判断是否还有数据,没有则退出编辑模式 if (mList.size() != 0) { index = 0;//删除之后置为0 tvDelete.setText("删除"); }else { tvEdit.setText("编辑"); layBottom.setVisibility(View.GONE); editorStatus = false; //没有数据自然也不存在编辑了 tvEdit.setVisibility(View.GONE); rvNormalShow.setVisibility(View.VISIBLE); //启用下拉 refresh.setEnableRefresh(true); //下拉刷新 refresh.setOnRefreshListener(refreshLayout -> { //重新装填数据 initList(); mEditMode = STATE_DEFAULT;//恢复默认状态 editorStatus = false;//恢复默认状态 tvEdit.setVisibility(View.VISIBLE);//显示编辑 }); } mAdapter.notifyDataSetChanged();//刷新 }
最后在onCreate()方法中使用
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); ButterKnife.bind(this); initList(); //禁用下拉和上拉 refresh.setEnableRefresh(false); refresh.setEnableLoadMore(false); }
做完这些基本上功能就已经都实现了,下面就是锦上添花了,增加动画效果,
⑦ 增加动画效果
列表的出现动画,在res下创建一个anim文件夹,这下面有两个xml文件
layout_animation_from_bottom.xml
<?xml version="1.0" encoding="utf-8"?> <layoutAnimation xmlns:android="http://schemas.android.com/apk/res/android" android:animation="@anim/item_animation_from_bottom" android:delay="15%" android:animationOrder="normal" />
item_animation_from_bottom.xml
<?xml version="1.0" encoding="utf-8"?> <set xmlns:android="http://schemas.android.com/apk/res/android" android:duration="500"> <translate android:fromYDelta="50%p" android:interpolator="@android:anim/accelerate_decelerate_interpolator" android:toYDelta="0" /> <alpha android:fromAlpha="0" android:interpolator="@android:anim/accelerate_decelerate_interpolator" android:toAlpha="1" /> </set>
然后创建一个动画类RecyclerViewAnimation.java,用来使用
代码如下:
package com.llw.recyclerviewusedemo; import android.content.Context; import android.view.animation.AnimationUtils; import android.view.animation.LayoutAnimationController; import androidx.recyclerview.widget.RecyclerView; /** * RecyclerView动画 */ public class RecyclerViewAnimation { //数据变化时显示动画 public static void runLayoutAnimation(final RecyclerView recyclerView) { final Context context = recyclerView.getContext(); final LayoutAnimationController controller = AnimationUtils.loadLayoutAnimation(context, R.anim.layout_animation_from_bottom); recyclerView.setLayoutAnimation(controller); recyclerView.getAdapter().notifyDataSetChanged(); recyclerView.scheduleLayoutAnimation(); } }
使用方法
import static com.llw.recyclerviewusedemo.RecyclerViewAnimation.runLayoutAnimation;//导入
MainActivity.java完整代码
package com.llw.recyclerviewusedemo; import android.os.Bundle; import android.view.View; import android.widget.LinearLayout; import android.widget.TextView; import androidx.appcompat.app.AppCompatActivity; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; import com.chad.library.adapter.base.BaseQuickAdapter; import com.google.gson.Gson; import com.scwang.smartrefresh.layout.SmartRefreshLayout; import java.util.ArrayList; import java.util.List; import butterknife.BindView; import butterknife.ButterKnife; import butterknife.OnClick; import static com.llw.recyclerviewusedemo.RecyclerViewAnimation.runLayoutAnimation; public class MainActivity extends AppCompatActivity { @BindView(R.id.tv_edit) TextView tvEdit;//编辑 @BindView(R.id.rv_normal_show) LinearLayout rvNormalShow;//没有数据时展示的布局 @BindView(R.id.rv) RecyclerView rv;//列表 @BindView(R.id.refresh) SmartRefreshLayout refresh;//刷新布局 @BindView(R.id.tv_check_all) TextView tvCheckAll;//全选 @BindView(R.id.tv_delete) TextView tvDelete;//删除 @BindView(R.id.lay_bottom) LinearLayout layBottom;//底部布局 private static final int STATE_DEFAULT = 0;//默认状态 private static final int STATE_EDIT = 1;//编辑状态 private int mEditMode = STATE_DEFAULT; private boolean editorStatus = false;//是否为编辑状态 private int index = 0;//当前选中的item数 List<DataResponse.DataBean> mList = new ArrayList<>();//列表 DataAdapter mAdapter;//适配器 @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); ButterKnife.bind(this); initList(); //禁用下拉和上拉 refresh.setEnableRefresh(false); refresh.setEnableLoadMore(false); } //初始化列表数据 private void initList() { mAdapter = new DataAdapter(R.layout.item_data_list, mList);//绑定视图和数据 rv.setLayoutManager(new LinearLayoutManager(this));//设置线性布局管理器 rv.setAdapter(mAdapter);//设置适配器 Gson gson = new Gson(); DataResponse dataBean = gson.fromJson(JsonData.JSON, DataResponse.class);//解析数据 List<DataResponse.DataBean> resultsBeans = dataBean.getData(); if (resultsBeans.size() > 0) { mList.clear(); mList.addAll(resultsBeans); mAdapter.notifyDataSetChanged();//刷新数据 runLayoutAnimation(rv);//动画显示 rv.setVisibility(View.VISIBLE); rvNormalShow.setVisibility(View.GONE); } else { rv.setVisibility(View.GONE); rvNormalShow.setVisibility(View.VISIBLE); } refresh.finishRefresh();//数据加载出来之后,结束下拉动作 } //页面的点击事件 @OnClick({R.id.tv_edit, R.id.tv_check_all, R.id.tv_delete}) public void onViewClicked(View view) { switch (view.getId()) { case R.id.tv_edit://编辑 updateEditState(); break; case R.id.tv_check_all://全选 setAllItemChecked(); break; case R.id.tv_delete://删除 deleteCheckItem(); break; } } //改变编辑状态 private void updateEditState() { mEditMode = mEditMode == STATE_DEFAULT ? STATE_EDIT : STATE_DEFAULT; if (mEditMode == STATE_EDIT) { tvEdit.setText("取消"); layBottom.setVisibility(View.VISIBLE); editorStatus = true; } else { tvEdit.setText("编辑"); layBottom.setVisibility(View.GONE); editorStatus = false; setAllItemUnchecked();//取消全选 } mAdapter.setEditMode(mEditMode); mAdapter.setOnItemChildClickListener(new BaseQuickAdapter.OnItemChildClickListener() { @Override public void onItemChildClick(BaseQuickAdapter adapter, View view, int position) { if (editorStatus) {//编辑状态 DataResponse.DataBean dataBean = mList.get(position); boolean isSelect = dataBean.isSelect(); if (!isSelect) { index++; dataBean.setSelect(true); } else { dataBean.setSelect(false); index--; } if (index == 0) { tvDelete.setText("删除"); } else { tvDelete.setText("删除(" + index + ")"); } mAdapter.notifyDataSetChanged(); } } }); } //全部选中 private void setAllItemChecked() { if (mAdapter == null) return; for (int i = 0; i < mList.size(); i++) { mList.get(i).setSelect(true); } mAdapter.notifyDataSetChanged(); index = mList.size(); tvDelete.setText("删除(" + index + ")"); } //取消全部选中 private void setAllItemUnchecked() { if (mAdapter == null) return; for (int i = 0; i < mList.size(); i++) { mList.get(i).setSelect(false); } mAdapter.notifyDataSetChanged(); tvDelete.setText("删除"); index = 0; } //删除选中的item private void deleteCheckItem() { if (mAdapter == null) return; for (int i = mList.size() - 1; i >= 0; i--) { if (mList.get(i).isSelect() == true) { mList.remove(i); } } //删除选中的item之后判断是否还有数据,没有则退出编辑模式 if (mList.size() != 0) { index = 0;//删除之后置为0 tvDelete.setText("删除"); }else { tvEdit.setText("编辑"); layBottom.setVisibility(View.GONE); editorStatus = false; //没有数据自然也不存在编辑了 tvEdit.setVisibility(View.GONE); rvNormalShow.setVisibility(View.VISIBLE); //启用下拉 refresh.setEnableRefresh(true); //下拉刷新 refresh.setOnRefreshListener(refreshLayout -> { //重新装填数据 initList(); index = 0; mEditMode = STATE_DEFAULT;//恢复默认状态 editorStatus = false;//恢复默认状态 tvDelete.setText("删除"); tvEdit.setVisibility(View.VISIBLE);//显示编辑 }); } mAdapter.notifyDataSetChanged(); runLayoutAnimation(rv);//动画显示 } }
尾声
感谢每一个阅读的人,写文章只为积累自己的经验,不至于忘记,如果能对看文章的您有帮助,那就更好了,我是初学者-Study,山高水长,后会有期~