如果想学习更多进阶知识,可以关注我的微信公众号:Android小菜。

也可以直接扫描二维码关注:

转载本专栏文章,请注明出处,尊重原创 。文章博客地址:道龙的博客

本篇是实现仿美团下拉刷新控件的第二篇,第一篇见:仿美团下拉刷新控件(一)

文本最终实现效果如下:

由于之前写过三篇自定义下拉刷新控件的文章,而且当时写的非常非常的细,本篇就不再浪费大家时间了,直接把重要的地方做一些解释,感兴趣的朋友可以直接下载源码。

1、创建一个自定义View类RefreshListView继承自ListView。

此时这个RefreshListView可以当做一个ListView来使用了。

2、在构造方法中初始化头布局

/*** 初始化头*/
private void initHearder() {mHeaderView = LayoutInflater.from(mContext).inflate(R.layout.layout_header,null);mFirstStepView = (RefreshFirstStepView) mHeaderView.findViewById(R.id.first_view);mSecondStepView = (RefreshSecondStepView) mHeaderView.findViewById(R.id.second_view);mThirdStepView = (RefreshThirdStepView) mHeaderView.findViewById(R.id.third_view);mTvDes = (TextView) mHeaderView.findViewById(R.id.tv_pull_to_refresh);mHeaderView.measure(0,0);mHeaderHeight = mHeaderView.getMeasuredHeight();//        Log.e(TAG,"头高度为:--->"+mHeaderHeight);mHeaderView.setPadding(0,-mHeaderHeight,0,0);addHeaderView(mHeaderView);
}

看到这里初始化了一个布局,布局样式:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="wrap_content"android:gravity="center"android:orientation="horizontal"><com.itydl.a05.view.RefreshFirstStepViewandroid:id="@+id/first_view"android:layout_width="45dp"android:layout_height="45dp"android:layout_marginTop="10dp"android:layout_marginBottom="5dp"/><com.itydl.a05.view.RefreshSecondStepViewandroid:id="@+id/second_view"android:layout_width="45dp"android:visibility="gone"android:layout_height="45dp"android:layout_marginTop="10dp"android:layout_marginBottom="5dp"/><com.itydl.a05.view.RefreshThirdStepViewandroid:id="@+id/third_view"android:layout_width="45dp"android:layout_height="45dp"android:visibility="gone"android:layout_marginTop="10dp"android:layout_marginBottom="5dp"/><TextViewandroid:id="@+id/tv_pull_to_refresh"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_marginLeft="10dp"android:text="下拉刷新"/></LinearLayout>

实现下拉刷新,肯定是要加一个头布局的嘛,这个头布局就作为下拉刷新的布局。通过打气筒拿到对应的View实例,然后拿到它的孩子控件,它里面有三个孩子控件,这三个孩子控件都是通过自定义View的方式引入的,具体的实现可见仿美团下拉刷新控件(一)
从上往下一次代表:下拉刷新状态展示()的布局,释放刷新状态展示的布局,正在刷新状态展示的布局。最底部的TextView就代表当前状态的文案。往下调用头布局的测量方法拿到头布局的高度,设置padding值后,就默认状态下把头布局隐藏起来了。然后通过addHeaderView()的方式把头布局添加到自定义的ListView当中:

3、重写onTouchEvent事件,处理交互:

    @Overridepublic boolean onTouchEvent(MotionEvent ev) {switch (ev.getAction()) {case MotionEvent.ACTION_DOWN:downY = ev.getY();break;case MotionEvent.ACTION_MOVE:if(downY == -1){downY = ev.getY();}float moveY = ev.getY();//如果当前处于下拉刷新状态,不去走下面的代码if(currentSatae == REFRESHING){return false;//如果当前处于正在刷新状态,取消后续的所有事件包括上滑和下滑}float instance = (moveY - downY)/3;if(getFirstVisiblePosition() == 0 && instance >= 0){//0item且下拉int topPadding = (int) (-mHeaderHeight + instance +0.5f);//计算padding值if(topPadding > -mHeaderHeight){//只有padding值大于-mHeaderHeight的时候才去自己处理事件if(topPadding < 0 && currentSatae != PULL_TO_REFRESH){
//                                Log.e(TAG,"下拉刷新状态");currentSatae = PULL_TO_REFRESH;}else if(topPadding >= 0 && currentSatae != RELEASE_TO_REFRESH){
//                                Log.e(TAG,"释放刷新状态");currentSatae = RELEASE_TO_REFRESH;}}mHeaderView.setPadding(0,topPadding,0,0);refreshState(instance);return true;//自己处理事件}break;case MotionEvent.ACTION_UP:downY = -1;if(currentSatae == RELEASE_TO_REFRESH){//当前状态是释放刷新,松手后是正在刷新状态currentSatae = REFRESHING;//还原Padding,使用Scroll平滑移动过去mHeaderView.setPadding(0,0,0,0);refreshState(mHeaderHeight);if(mOnRefreshListener != null){mOnRefreshListener.onRefreshing();}}else if(currentSatae == PULL_TO_REFRESH){//使用Scroll平滑移动过去mHeaderView.setPadding(0,-mHeaderHeight,0,0);}break;default:break;}return super.onTouchEvent(ev);//ListView的事件保留}

对这段代码解释一下:

在按下的时候记录一个坐标,downY这个值初始化值为-1,当move的时候如果这个值为-1,说明down事件没有获取到当前的坐标Y值(是有可能发生的),所以在move的时候先判断downY是否拿到没有拿到这个值就在move的时候记录第一个值。然后往下,判断当前处于什么状态,如果是下拉刷新状态,就不走任何逻辑了返回了false表示后续的事件都拿不到。然后MOVE事件里面拿到移动的距离,只有是手指move位置相对初识位置downY插值是大于零的表示头布局往下拉了一些并且当前处于第0个Item的时候才去走自己的逻辑处理下拉刷新状态。从而就确定了当前状态。随着移动的距离计算,如果超过了头布局的高度时候属于释放刷新状态,少于头布局的高度为下拉刷新状态。然后记录下当前状态,并且通过设置padding值改变头布局的位置,最后调用了refreshState(instance);方法来根据当前的状态值刷新控件的样式以及动画的加载等,把(moveY-downY)/3这个值传过去,因为待会要用到它计算百分比。(moveY-downY)/3的另一个原因是不让下拉头布局过多的距离。

然后是UP事件,如果UP的时候处于下拉刷新状态,那么就恢复原来的状态,这里使用很暴力的方式直接设置padding了。如果当前是释放刷新状态松手应该是进入正在刷新状态了,正在刷新状态的时候就要调用接口方法了,在这个方法里面进行具体的耗时操作,比如访问网络最新数据等。然后在调用refreshState(instance);方法来根据当前的状态值刷新控件的样式以及动画的加载。

看一下refreshState(instance);这个方法:

/*** 刷新当前的状态* 根据标记为处理控件的样式数据* @param instance*/private void refreshState(float instance) {//计算比例float moveY = Math.abs(instance);float percent = moveY / mHeaderHeight;if(percent >= 1.0f){percent = 1.0f;}Log.e(TAG,"百分比-->"+percent);switch (currentSatae) {case PULL_TO_REFRESH:mFirstStepView.setVisibility(VISIBLE);mSecondStepView.setVisibility(GONE);mThirdStepView.setVisibility(GONE);mTvDes.setText("下拉刷新");//执行动画mFirstStepView.setProgress(percent);mFirstStepView.postInvalidate();break;case RELEASE_TO_REFRESH:mFirstStepView.setVisibility(GONE);mSecondStepView.setVisibility(VISIBLE);mThirdStepView.setVisibility(GONE);mTvDes.setText("释放刷新");secondAnim.start();break;case REFRESHING:mFirstStepView.setVisibility(GONE);mSecondStepView.setVisibility(GONE);mThirdStepView.setVisibility(VISIBLE);mTvDes.setText("正在刷新");mThreeAnim.start();break;default:break;}}

通过判断不同的状态来做对应的控件处理,无非就是某个状态展示对应状态的动画,以及文案的修改。这里讲一下最开始计算百分数:

        //计算比例float moveY = Math.abs(instance);float percent = moveY / mHeaderHeight;if(percent >= 1.0f){percent = 1.0f;}

手指移动距离/头的高度-->0.0f-->1.0f,比如头高度是100,移动了20,那么percent=0.2f以此类推。但是在下拉的时候moveY可能会超过头的高度,如果超过了,就按照1.0f处理。

4、使用自定义下拉刷新控件

在Activity或者Fragment中:

public class TestActivity extends AppCompatActivity implements RefreshListView.OnRefreshListener {private static final int REFRESH_COMPLETE = 0;private RefreshListView mListView;private ArrayList<String> mDatas;/*** MyHandler是一个私有静态内部类继承自Handler,内部持有MainActivity的弱引用,* 避免内存泄露*/private MyHandler mHandler = new MyHandler(this);private ArrayAdapter<String> mAdapter;private static class MyHandler extends Handler{private WeakReference<TestActivity> mActivity;public MyHandler(TestActivity activity){mActivity = new WeakReference<TestActivity>(activity);}@Overridepublic void handleMessage(Message msg) {TestActivity activity = mActivity.get();if (activity != null) {switch (msg.what) {case REFRESH_COMPLETE:activity.mListView.setOnRefreshComplete();activity.mAdapter.notifyDataSetChanged();activity.mListView.setSelection(0);break;}}else{super.handleMessage(msg);}}}@Overrideprotected void onCreate(@Nullable Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_test);mListView = (RefreshListView) findViewById(R.id.lv_refresh);mDatas = new ArrayList<String>(Arrays.asList(Strings.NAMES));mAdapter = new ArrayAdapter<>(this, android.R.layout.simple_list_item_1, mDatas);mListView.setAdapter(mAdapter);mListView.setOnRefreshListener(this);}@Overridepublic void onRefreshing() {//开启子线程访问网络new Thread(new Runnable() {@Overridepublic void run() {SystemClock.sleep(3000);mDatas.add(0, "new data");mHandler.sendEmptyMessage(REFRESH_COMPLETE);}}).start();}}

直接在刷新的方法中进行耗时操作,进行访问网络的功能,以及成功之后添加数据功能,然后使用Handler发送消息,在处理消息的方法中进行数据的刷新。值得注意的是,这里为了防止内存泄漏做了一点点操作,相信都能明白是什么意思,因为之前文章也都说到过如何避免内存泄漏问题。

然后运行程序:

这样这个控件就讲完了,如果觉得对你有帮助记得加下关注哈,或者微信关注公众号——Android小菜。

仿美团下拉刷新控件(二)相关推荐

  1. 仿美团下拉刷新控件(一)

    如果想学习更多进阶知识,可以关注我的微信公众号:Android小菜. 也可以直接扫描二维码关注: 转载本专栏文章,请注明出处,尊重原创 .文章博客地址:道龙的博客 很有幸能进入美团.本文就仿写一下美团 ...

  2. Android自定义控件之仿美团下拉刷新

    android美团下拉刷新控件自定义控件 目录(?)[+]   美团的下拉刷新分为三个状态:  第一个状态为下拉刷新状态(pull to refresh),在这个状态下是一个绿色的椭圆随着下拉的距离动 ...

  3. Android仿苹果版QQ下拉刷新实现(一) ——打造简单平滑的通用下拉刷新控件

    前言: 因为公司人员变动原因,导致了博主四个月没有动安卓,一直在做IOS开发,如今接近年前,终于可以花一定的时间放在安卓上了.好了,废话不多说,今天我们要带来的效果是苹果版本的QQ下拉刷新.首先看一下 ...

  4. Android 怎么实现支持所有View的通用的下拉刷新控件

    转载请标明出处: http://blog.csdn.net/u010386612/article/details/51372696 本文出自:[AItsuki的博客] 下拉刷新对于一个app来说是必不 ...

  5. android多个下拉控件,Android实现支持所有View的通用的下拉刷新控件

    下拉刷新对于一个app来说是必不可少的一个功能,在早期大多数使用的是chrisbanes的PullToRefresh,或是修改自该框架的其他库.而到现在已经有了更多的选择,github上还是有很多体验 ...

  6. android google 下拉刷新 csdn,android SwipeRefreshLayout google官方下拉刷新控件

    下拉刷新功能之前一直使用的是XlistView很方便我前面的博客有介绍 SwipeRefreshLayout是google官方推出的下拉刷新控件使用方法也比较简单 今天就来使用下SwipeRefres ...

  7. Android SwipeRefreshLayout 官方下拉刷新控件介绍

    转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/24521483 下面App基本都有下拉刷新的功能,以前基本都使用XListView ...

  8. android 下拉刷新 组件,android系统自带下拉刷新控件的实现

    android系统自带的下拉刷新控件SwipeRefreshLayout位于android.support.v4.widget包下,实现步骤如下: 1.在布局文件中添加该控件,该控件一般作为父控件,而 ...

  9. pb自定义控件 事件_Android WebView与下拉刷新控件滑动冲突的解决方法

    使用WebView时一般会在外层使用下拉刷新控件如(SwipeRefreshLayout).但是测试时会发现网页无法上拉,往上滑动就会触发下拉刷新控件的refresh事件.所以这里记录一下解决该问题的 ...

最新文章

  1. 特斯拉Autopilot事故频发,真正意义上自动驾驶还要多久问世?
  2. WebAssembly 的由来
  3. ssm路径访问不到_ssm整合!!!
  4. App开发(Android与php接口)之:短信验证码
  5. 超凡先锋怎么进入维护服务器,超凡先锋新手教程怎么过 新手教程攻略_超凡先锋...
  6. 海量数据选取重复次数最多的n个
  7. lambda中sorted排序
  8. input 0.1无法相加_你真的知道0.1+0.2为何不等于0.3吗?
  9. poj 3436 (最大流)
  10. Qt编写的线损分析工具
  11. Windows Git客户端搭建
  12. Android在Service中显示Dialog
  13. HTML判断如果并且,将html转换为js,并且其中含有判断语句
  14. 视屏教程、电子书、技术文档
  15. arcgis注册dsoframer.ocx等组件
  16. Java—网络编程相关概念
  17. 第七次人口普查数据可视化---pyecharts
  18. 电脑知识:Win10系统优化的7个设置技巧
  19. 8大成功的网络营销案例 互联网营销案例分析
  20. 不积跬步 无以至千里

热门文章

  1. GitHub 启动代码永久保存计划,为人类文明留“火种”?
  2. Java使用JaxWsDynamicClientFactory和HttpURLConnection调取Webservice接口
  3. HTML5期末大作业:仿苏宁易购商城网站设计——仿苏宁易购官网商城(1页) HTML+CSS+JavaScript web网页大作业
  4. android wear悦跑圈,悦跑圈下载-悦跑圈 安卓版v5.14.0-PC6安卓网
  5. 根据周数获取当周的起始日期
  6. 三元函数的几何图形一般是_多元函数的定义域与几何图形.PPT
  7. python 正则匹配任意字符串(包括换行符,空白等)--主用于文本
  8. 深度学习基础笔记(MLP+CNN+RNN+Transformer等等)
  9. 内存专题--各种RAM/ROM/Cache/Flash等内存概念与区别
  10. Match公链官网正式上线,链接Web3加速落地