仿9GAG制作过程(四)

  • 有话要说
  • 成果
  • 实现方式
    • 页面布局
    • 下拉刷新
    • 上拉加载
      • 注意点
    • 使用上拉加载
  • 参考
  • 结束语

有话要说

这次主要讲述主页面下拉刷新和上拉加载功能的实现。

主要是使用了SwipeRefreshLayout的布局方式,并在此基础上通过RecyclerView的特性增加了上拉加载的功能。

成果

实现方式

页面布局

<android.support.v4.widget.SwipeRefreshLayout xmlns:android="http://schemas.android.com/apk/res/android"android:id="@+id/swipeRefreshView"android:layout_width="match_parent"android:layout_height="match_parent"><android.support.v7.widget.RecyclerViewandroid:id="@+id/recyclerView"android:background="#f0f0f0"android:layout_width="match_parent"android:layout_height="match_parent"/>
</android.support.v4.widget.SwipeRefreshLayout>

通过SwipeRefreshLayout来实现下拉刷新功能。


下拉刷新

SwipeRefreshLayout swipeRefreshLayout;
// 下拉刷新控件
swipeRefreshLayout = getView().findViewById(R.id.swipeRefreshView);
// 设置下拉控件背景色
swipeRefreshLayout.setProgressBackgroundColorSchemeColor(Color.WHITE);
// 设置下来控件主色
swipeRefreshLayout.setColorSchemeResources(R.color.colorAccent);
// 设置下拉刷新事件
swipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {@Overridepublic void onRefresh() {new Thread(new Runnable() {@Overridepublic void run() {try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}String url = baseUrl + (++currentPage);OkHttpClient client = new OkHttpClient();Request request = new Request.Builder().url(url).build();try {Response response = client.newCall(request).execute();String json = response.body().string();if (json != null) {Gson gson = new Gson();List<NewsBean> newDatas = gson.fromJson(json, new TypeToken<List<NewsBean>>(){}.getType());if (newsBeans != null && newsBeans.size() > 0) {newsBeans.addAll(0, newDatas);}}Message message = new Message();message.what = UPDATE_NEWS;handler.sendMessage(message);} catch (IOException e) {e.printStackTrace();}}}).start();}
});

通过setProgressBackgroundColorSchemeColor来设置下拉控件的背景色,也就是圈圈的主体颜色。

通过setColorSchemeResources来设置下拉控件中间的线条颜色。

通过setOnRefreshListener来定义下拉刷新事件。

然后通过currentPage来实现下拉刷新之后获取的数据是下一页的数据,再添加到集合开头。

private Handler handler = new Handler() {@Overridepublic void handleMessage(Message msg) {switch (msg.what) {case QUERY_NEWS:recyclerView.getAdapter().notifyDataSetChanged();break;case UPDATE_NEWS:recyclerView.getAdapter().notifyDataSetChanged();swipeRefreshLayout.setRefreshing(false);break;case LOAD_MORE:((NewsAdapter)recyclerView.getAdapter()).changeStatus(NewsAdapter.UNLOADING);currentState = NewsAdapter.UNLOADING;break;}}
};

刷新完成之后,通过notifyDataSetChanged告诉RecyclerView数据改变了,进而更改页面显示。通过setRefreshing来控制下拉刷新控件的显示。

由此,完成了下拉刷新的实现。


上拉加载

由于SwipeRefreshLayout并不提供上拉加载的功能,于是准备利用RecyclerView灵活的特性来实现上拉加载功能。

package com.example.lanxingren.imitating9gag.adapter;import android.content.Context;
import android.support.annotation.NonNull;
import android.support.v7.widget.CardView;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;import com.example.lanxingren.imitating9gag.R;
import com.example.lanxingren.imitating9gag.bean.NewsBean;
import com.example.lanxingren.imitating9gag.util.GlideApp;import java.util.List;public class NewsAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {private List<NewsBean> myNewsList;private Context myContext;// 是否加载public static final int LOADING = 1;public static final int UNLOADING = 2;private int mStatus = UNLOADING;// 当前加载状态// item的viewTypeprivate final int ITEM = 1;private final int FOOTER = 2;static class NewsHolder extends RecyclerView.ViewHolder {CardView cardView;TextView titleView;ImageView imageView;TextView pointView;ImageView likeImageView;ImageView unlikeImageView;private NewsHolder (View view) {super(view);cardView = (CardView) view;titleView = view.findViewById(R.id.item_title);imageView = view.findViewById(R.id.item_image);pointView = view.findViewById(R.id.item_point);likeImageView = view.findViewById(R.id.item_like);unlikeImageView = view.findViewById(R.id.item_unlike);}}static class FooterHolder extends RecyclerView.ViewHolder {CardView cardView;private FooterHolder (View view) {super(view);cardView = view.findViewById(R.id.cardView_footer);}}public NewsAdapter (List<NewsBean> newsList) {this.myNewsList = newsList;}@Overridepublic int getItemCount() {int count = 0;if (myNewsList != null) {count = myNewsList.size() + 1;}return count;}@NonNull@Overridepublic RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {if (myContext == null) {myContext = parent.getContext();}if (viewType == ITEM) {View view = LayoutInflater.from(myContext).inflate(R.layout.item_news, parent, false);return new NewsHolder(view);} else {View view = LayoutInflater.from(myContext).inflate(R.layout.item_footer, parent, false);return new FooterHolder(view);}}@Overridepublic void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {if (holder instanceof NewsHolder) {final NewsHolder newsHolder = (NewsHolder)holder;final NewsBean newsBean = myNewsList.get(position);// 设置标题String title = "9GAG#" + newsBean.getId();if (newsBean.getTitle() != null && newsBean.getTitle().length() > 0) {title = newsBean.getTitle();}newsHolder.titleView.setText(title);// 屏幕宽度int screenWidth = myContext.getResources().getDisplayMetrics().widthPixels;// 屏幕高度int screenHeight = myContext.getResources().getDisplayMetrics().heightPixels;// 设置图片,不知道为什么override这样设置就可以让图片正正好显示,有时间研究一下?if (newsBean.getUrls() != null && newsBean.getUrls().size() > 0) {GlideApp.with(myContext).load(newsBean.getUrls().get(0)).override(screenWidth, screenHeight).into(newsHolder.imageView);}// 设置点赞数String point = Integer.toString(newsBean.getLike() - newsBean.getUnlike());newsHolder.pointView.setText(point);// 设置点赞图标显示int accentColor = myContext.getResources().getColor(R.color.colorAccent);int defaultColor = myContext.getResources().getColor(R.color.defaultColor);switch (newsBean.getIsLiked()) {case -1:newsHolder.likeImageView.setColorFilter(defaultColor);newsHolder.unlikeImageView.setColorFilter(accentColor);break;case 0:newsHolder.likeImageView.setColorFilter(defaultColor);newsHolder.unlikeImageView.setColorFilter(defaultColor);break;case 1:newsHolder.likeImageView.setColorFilter(accentColor);newsHolder.unlikeImageView.setColorFilter(defaultColor);break;}// 初始化监听事件newsHolder.likeImageView.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {newsBean.setIsLiked(1);notifyDataSetChanged();}});newsHolder.unlikeImageView.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {newsBean.setIsLiked(-1);notifyDataSetChanged();}});} else if (holder instanceof FooterHolder) {switch (mStatus) {case UNLOADING:((FooterHolder) holder).cardView.setVisibility(View.GONE);break;case LOADING:((FooterHolder) holder).cardView.setVisibility(View.VISIBLE);break;}}}@Overridepublic int getItemViewType(int position) {if (position + 1 == getItemCount()) {return FOOTER;} else {return ITEM;}}public void changeStatus(int status) {this.mStatus = status;notifyDataSetChanged();}
}

在适配器中定义了两个布局,一个是普通布局,一个是尾布局(footer)。

下面是footer的具体布局:

<android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="wrap_content"xmlns:app="http://schemas.android.com/apk/res-auto"android:layout_marginTop="10dp"android:layout_marginBottom="0dp"app:cardCornerRadius="0dp"android:elevation="0dp"android:id="@+id/cardView_footer"><ProgressBarandroid:layout_width="wrap_content"android:layout_height="100dp"android:layout_gravity="center_horizontal"/>
</android.support.v7.widget.CardView>

注意点

  • 通过mStatus来判断尾布局是否展示
  • ITEM代表的是普通布局,即段子的布局;FOOTER代表的是尾布局
  • 由于增加了一个item,故getItemCount得在原先的基础上加上一
  • onCreateViewHolder中通过viewType来创建不同的viewHolder
  • 实现getItemViewType方法,根据position的值来确定viewType
  • onBindViewHolder中先判断viewHolder的类型,如果是尾布局(footer)的话,再根据mStatus来判断是否展示
  • changeStatus主要是给外面用的,通过该方法可以控制footer的显示

使用上拉加载

private void initLoadMoreListener() {recyclerView.setOnScrollListener(new RecyclerView.OnScrollListener() {@Overridepublic void onScrollStateChanged(final RecyclerView recyclerView, int newState) {super.onScrollStateChanged(recyclerView, newState);// 获取当前可见的item位置int lastVisiblePosition = 0;RecyclerView.LayoutManager layoutManager = recyclerView.getLayoutManager();if (layoutManager instanceof LinearLayoutManager) {lastVisiblePosition = ((LinearLayoutManager) layoutManager).findLastVisibleItemPosition();}// 当前加载状态是UNLOADING && 当前可见的item位置是最后一条时if (currentState == NewsAdapter.UNLOADING&& lastVisiblePosition + 1 == recyclerView.getAdapter().getItemCount()) {// 改变footer的可见性((NewsAdapter)recyclerView.getAdapter()).changeStatus(NewsAdapter.LOADING);currentState = NewsAdapter.LOADING;new Thread(new Runnable() {@Overridepublic void run() {try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}String url = baseUrl + (++currentPage);OkHttpClient client = new OkHttpClient();Request request = new Request.Builder().url(url).build();try {Response response = client.newCall(request).execute();String json = response.body().string();if (json != null) {Gson gson = new Gson();List<NewsBean> newDatas = gson.fromJson(json, new TypeToken<List<NewsBean>>(){}.getType());if (newsBeans != null && newsBeans.size() > 0) {newsBeans.addAll(newsBeans.size(), newDatas);}}Message message = new Message();message.what = LOAD_MORE;handler.sendMessage(message);} catch (IOException e) {e.printStackTrace();}}}).start();}}});
}

通过给recyclerView加上滚动事件来实现下拉加载功能,具体逻辑如下:

  1. 获取页面可见最下面的item位置
  2. 判断当前尾布局的加载状态
  3. 如果尾布局现在的状态是UNLOADING && item位置为最后一个,则开线程加载数据
  4. 将尾布局展示,即开始转圈动画
  5. 请求网络,获取数据,放入数据集
  6. 根据handler的处理,告诉RecyclerView数据改变,然后将footer隐藏

通过以上的过程就可以实现上拉加载的效果。

参考

  • SwipeRefreshLayout详解和自定义上拉加载更多
  • wipeRefreshLayout + RecyclerView 实现 上拉刷新 和 下拉刷新

结束语

本次学习了Android的下拉刷新以及上拉加载的实现,对RecyclerView有了进一步的了解。

接下来准备实现点赞功能以及GIF的暂停功能。

仿9GAG制作过程(四)相关推荐

  1. 织梦仿站系列教程第二十一讲——封面页制作(四)

    织梦搜索提示关键词不少于2个字节 织梦仿站系列教程第二十一讲--封面页制作(四) 看拳击在线的代码,晕,最新新闻和热门新闻竟然是JS调用,我们只好找到这个JS文件,转换成HTML,然后修改. 将如下代 ...

  2. 嘉立创电路板制作过程全流程详解(四):阻焊、字符、喷锡或沉金

    第1篇文章,点击这里:嘉立创电路板制作过程全流程详解(一):MI.钻孔 第2篇文章,点击这里:嘉立创电路板制作过程全流程详解二:沉铜.线路 第3篇文章,点击这里:嘉立创电路板制作过程全流程详解三:图电 ...

  3. ss570122的雕刻机制作过程

    ss570122的雕刻机制作过程1 作者注:我将以前发表过的几个有关机械和驱动电路的DIY帖子重新整理组合一下重新发表(并会适当增加电源和主轴的DIY内容),为的是方便初入雕刻机制作的网友能够方便的了 ...

  4. (转载)连连看游戏外挂详细制作过程

    标 题: [原创]新人入手第一个游戏外挂,附上详细制作过程 作 者: caigui 时 间: 2013-01-09,00:56:16 链 接: http://bbs.pediy.com/showthr ...

  5. 通过WiFi控制智能小车机器人制作过程详解

    之前发的作品都是基于蓝牙控制的智能小车机器人,由于蓝牙的传输范围比较小,所以控制距离的局限性比较大,并且通过蓝牙传输视频会明显出现卡屏的现象. 而通过WiFi方式控制智能小车机器人能达到100米左右的 ...

  6. uniapp、uniCloud实现微信公众号自动查询淘宝京东优惠券制作过程

    uniapp.uniCloud实现微信公众号自动查询淘宝京东优惠券制作过程 微信公众号自动查询淘宝京东优惠券机器人制作教程.服务器通过uniapp提供的uniCloud云服务搭建,建议使用阿里云,不要 ...

  7. 随着国产动漫的崛起,越来越好奇3D动漫的制作过程了

    我们首先来了解一下,3d动画的定义. 三维动画软件在计算机中首先建立一个虚拟的世界,设计师在这个虚拟的三维世界中按照要表现的对象的形状尺寸建立模型以及场景,再根据要求设定模型的运动轨迹.虚拟摄影机的运 ...

  8. 12年前的作品──《美绿中国象棋》制作过程及算法简介

    这个游戏是大学本科二年级时(1998年)修人工智能课程的功课 .这个游戏的「棋力」并不高,主要是因为没有花时间在调整的工作上.比较满意的部分是使用 OpenGL 做的使用者介面.本文将简单介绍制作本游 ...

  9. 嘉立创电路板制作过程全流程详解(五):测试、锣边、V-CUT、QC、发货

    第1篇文章,点击这里:嘉立创电路板制作过程全流程详解(一):MI.钻孔 第2篇文章,点击这里:嘉立创电路板制作过程全流程详解二:沉铜.线路 第3篇文章,点击这里:嘉立创电路板制作过程全流程详解三:图电 ...

  10. Android实训案例(九)——答题系统的思绪,自己设计一个题库的体验,一个思路清晰的答题软件制作过程

    Android实训案例(九)--答题系统的思绪,自己设计一个题库的体验,一个思路清晰的答题软件制作过程 项目也是偷师的,决心研究一下数据库.所以写的还是很详细的,各位看官,耐着性子看完,实现结果不重要 ...

最新文章

  1. 将页面转发到用户登录页面
  2. spring hsqldb_在Spring中嵌入HSQLDB服务器实例
  3. 清新淡雅水彩手绘花卉插画素材,psd分层好用!
  4. html表格隐藏1行,js控制隐藏或显示table的某一行
  5. C# in Depth
  6. 六、openstack安装之Horizon篇
  7. [源码和报告分享]基于Java的局域网聊天工具
  8. 利用FME对坐标文件进行坐标转换
  9. linux监控系统catic,网络设备监控-Catic添加H3C的监控图解
  10. 外牌年检车辆在上海办理年检
  11. #51CTO学院四周年#一路前行,一路陪伴
  12. SIM7600CE-CNSE 4G模组发送英文短信
  13. PCB 设计技巧一百问
  14. cmd命令导入.dmp文件
  15. 第二届同花顺算法大赛 | 2022 | AI算法
  16. 论坛IP签名档PHP源码,简单几步,教你制作自己的显IP签名档
  17. 《惢客创业日记》2019.01.21(周一)你还记得米卢吗?
  18. 递归方法求最大公约数,求最小公倍数
  19. 2019年如何抓住社交电商的风口
  20. Java 集合深入理解(13):Stack 栈

热门文章

  1. 人工智能——自然演绎推理
  2. 多节点服务器定时任务重复处理的问题
  3. 一文说清:可逆与不可逆加密算法,对称与非对称加密算法-据说BCrypt比MD5要好?
  4. 你为什么那么努力还是不开心!
  5. 屁孩君儿子讲解 2022 【例4.7】最小n值
  6. 关于 Could not find artifact ...:pom:1.0-SNAPSHOT 的问题!
  7. 2007word文档删除尾注线
  8. 推荐一个在线免费将word转换成pdf文件的方法
  9. mysql查询父子关系树_根据数据的父子关系创建树形结构并实现遍历
  10. python判断_python判断与或