我们在使用ListView的时候。非常多情况下须要用到下拉刷新的功能。为了了解下拉刷新的底层实现原理,我採用自己定义ListView控件的方式来实现效果。

实现的基本原理是:自己定义ListView,给ListView载入头布局。然后动态的控制头布局的现实与隐藏。ListView初始化的时候,头布局是隐藏的,当手指往下拉的时候,依据手指移动的距离与头布局的高度的关系来控制头布局的显示。具体的控制思路详见后边的代码。代码中的凝视非常具体。先来看一下效果图:

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" width="240" height="427" alt="">         

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" width="240" height="427" alt=""> 
        

头布局的实现代码例如以下:

<?

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="match_parent"
android:orientation="horizontal" > <RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="20dp"
android:layout_marginTop="5dp"
android:padding="5dp" > <ImageView
android:id="@+id/iv_arror"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:padding="10dp"
android:src="@drawable/refresh_listview_arrow" /> <ProgressBar
android:id="@+id/pb_list"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:indeterminateDrawable="@drawable/custom_progress"
android:visibility="invisible" >
</ProgressBar>
</RelativeLayout> <LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_marginLeft="25dp"
android:layout_marginTop="12dp"
android:orientation="vertical"
android:padding="5dp" > <TextView
android:id="@+id/tv_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginTop="12dp"
android:text="下拉刷新"
android:textColor="#FF0000"
android:textSize="20sp" /> <TextView
android:id="@+id/tv_time"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginTop="3dp"
android:text="2015-03-10 17:07:07"
android:textColor="@android:color/darker_gray"
android:textSize="16sp" />
</LinearLayout> </LinearLayout>

接着定义一个RefreshListView,继承自ListView,重写它的三个构造方法。在RefreshlistView初始化的时候,载入一个头布局。这个头布局默认是隐藏的。

<span style="white-space:pre">	</span>// 初始化头布局
private void initHeaderView() {
// 给当前的ListView加入下拉刷新的头布局
mHeaderView = View.inflate(getContext(), R.layout.list_refresh_header,
null);
tvTitle = (TextView) mHeaderView.findViewById(R.id.tv_title);
tvTime = (TextView) mHeaderView.findViewById(R.id.tv_time);
// 下拉箭头
ivArror = (ImageView) mHeaderView.findViewById(R.id.iv_arror);
// 进度条
pb = (ProgressBar) mHeaderView.findViewById(R.id.pb_list); this.addHeaderView(mHeaderView);
// 初始化这个下拉刷新的ListView的时候,县隐藏掉下拉刷新的头布局,然后通过代码动态的控制头布局的显示与隐藏
// 隐藏头布局
// 先測量一把头布局
mHeaderView.measure(0, 0);
// 获得測量得到的高度
mHeaderViewHeight = mHeaderView.getMeasuredHeight();
// 设置paddingtop为负高度,隐藏头布局
mHeaderView.setPadding(0, -mHeaderViewHeight, 0, 0); // 初始化完毕布局,初始化两个动画效果 initAnimation();
// 设置当前时间
tvTime.setText("最后刷新时间:" + getCurrentTime());
}

当手指触摸屏幕时。触发OnTouchEvent事件,依据手指在Y轴方向上的移动偏移量来动态的控制头布局的显示与隐藏。并即时更新下拉框的显示的状态。详细的代码例如以下:

<span style="white-space:pre">	</span>/**
* 下拉屏幕的时候。将头布局展示出来,重写一下ListView的触摸屏幕的事件
*/
@Override
public boolean onTouchEvent(MotionEvent ev) {
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
// 手指按下的时候获得当前屏幕的Y坐标
startY = (int) ev.getRawY(); break;
case MotionEvent.ACTION_MOVE:
// 手指移动的时候。获得当前屏幕的Y坐标,与開始的Y坐标做比較 if (startY == -1) {
// 确保startY有效
startY = (int) ev.getRawY();
} int endY = (int) ev.getRawY();
// 屏幕Y方向移动的距离
int dy = endY - startY;
// 仅仅有屏幕向下滑,也就是dy>0,而且当前的ListView显示的是第一个条目。那个隐藏的下拉刷新的头布局才慢慢的随手指滑出来
if (dy > 0 && this.getFirstVisiblePosition() == 0) {
// 同意下拉刷新框出来
// 下拉刷新框出来事实上就是给头布局设置padding。首先依据手指移动的距离计算一下padding
int padding = dy - mHeaderViewHeight;//
mHeaderView.setPadding(0, padding, 0, 0);
// 更新刷新框的状态
// 一共同拥有三种状态,下拉刷新、正在刷新、松开刷新
// 定义这三种状态
// 假设padding大于0说明下拉刷新的框已经所有拉出来了,将状态改为松开刷新
if (padding > 0 && mCurrentState != STATE_RELEASE_REFRESH) {
// 状态改为松开刷新,将下拉框显示的状态更新一下
mCurrentState = STATE_RELEASE_REFRESH;
// 更新当前下拉框显示的状态
updateState();
}
if (padding < 0 && mCurrentState != STATE_PULL_REFRESH) {
// 状态改为下拉刷新
mCurrentState = STATE_PULL_REFRESH;
updateState();
} } break;
case MotionEvent.ACTION_UP:
// 手指抬起来的时候重置startY。 将状态改为正在刷新
startY = -1;
if (mCurrentState == STATE_RELEASE_REFRESH) {
// 假设当前为松开刷新,则手指一抬起来就将状态改为正在
mCurrentState = STATE_REFRESHING;
// 头布局的padding设置为0000
mHeaderView.setPadding(0, 0, 0, 0);
updateState();
} else {
// 没有全然拉出来。就将头布局隐藏
mHeaderView.setPadding(0, -mHeaderViewHeight, 0, 0); } break; } return super.onTouchEvent(ev);
} /**
* 更新当前下拉框显示的状态
*/
private void updateState() {
// 推断当前状态是什么,依据当前状态更新下拉框显示
switch (mCurrentState) {
case STATE_PULL_REFRESH:
// 下拉刷新
tvTitle.setText("下拉刷新");
ivArror.setVisibility(View.VISIBLE);
pb.setVisibility(View.INVISIBLE);
// 给箭头设置动画
ivArror.startAnimation(animDown);
break; case STATE_REFRESHING:
// 正在刷新
tvTitle.setText("正在刷新...");
ivArror.clearAnimation();// 必须先清除动画,才干隐藏
ivArror.setVisibility(View.INVISIBLE);
pb.setVisibility(View.VISIBLE);
// 正在刷新的时候调用接口中的方法
if (mListener != null) {
// 正在刷新
mListener.onRefresh();
} break; case STATE_RELEASE_REFRESH:
// 松开刷新
tvTitle.setText("松开刷新");
ivArror.setVisibility(View.VISIBLE);
pb.setVisibility(View.INVISIBLE);
ivArror.startAnimation(animUp);
break;
} }

为了监听下拉刷新的动作,自己定义一个监听接口。当正在刷新的时候运行onRefresh方法。对外提供一个设置监听的方法,监听器由子类实现。详细的正在刷新运行的逻辑由子类在onRefresh中实现。

// 下拉刷新逻辑的实现方式:给当前的ListView设置下拉刷新的监听器,监听器的本质就是一个接口
/**
* 下拉刷新的监听器
*
* @author ZHY
*
*/
public interface onRefreshListener {
// 刷新的时候运行的方法,谁实现这个接口。谁运行此方法
public void onRefresh(); } onRefreshListener mListener; // 有了监听器之后,提供一个设置监听的方法
public void setOnRefreshListener(onRefreshListener listener) {
// 这个Listneer是从子类中闯过来的,是子类定义的监听
mListener = listener;
}

刷新完毕之后,改变下拉刷新的状态,而且隐藏下拉框

<span style="white-space:pre">	</span>// 刷新完毕的时候。将下拉框隐藏
/**
* 调用server的数据刷新。刷新完毕之后调用的方法 载入完毕之后的回调
*
* @param isSuccess
*/
public void onRefreshCompleted(boolean isSuccess) { // 将状态改成下拉刷新,然后隐藏下拉框
mCurrentState = STATE_PULL_REFRESH;
tvTitle.setText("下拉刷新");
ivArror.setVisibility(View.VISIBLE);
pb.setVisibility(View.INVISIBLE); mHeaderView.setPadding(0, -mHeaderViewHeight, 0, 0);// 隐藏
// 假设刷新成功,则更新最后一次刷新时间,否则不更新时间
if (isSuccess) {
tvTime.setText("最后刷新时间:" + getCurrentTime()); } }

这一部分工作做完之后。一个能够实现下拉刷新功能的ListView就定义好了。在MainActivity中就能够直接使用了

源代码下载

Android自己定义控件--下拉刷新的实现的更多相关文章

  1. android控件 下拉刷新pulltorefresh

    外国人写的下拉刷新控件,我把他下载下来放在网盘,有时候訪问不了github 支持各种控件下拉刷新 ListView.ViewPager.WevView.ExpandableListView.GridV ...

  2. Android UI--自定义ListView(实现下拉刷新+加载更多)

    Android UI--自定义ListView(实现下拉刷新+加载更多) 关于实现ListView下拉刷新和加载更多的实现,我想网上一搜就一堆.不过我就没发现比较实用的,要不就是实现起来太复杂,要不就 ...

  3. Android自己定义控件系列五:自己定义绚丽水波纹效果

    尊重原创!转载请注明出处:http://blog.csdn.net/cyp331203/article/details/41114551 今天我们来利用Android自己定义控件实现一个比較有趣的效果 ...

  4. Android自己定义控件:进度条的四种实现方式

    前三种实现方式代码出自: http://stormzhang.com/openandroid/2013/11/15/android-custom-loading/ (源代码下载)http://down ...

  5. android 自己定义控件

    Android自己定义View实现非常easy 继承View,重写构造函数.onDraw.(onMeasure)等函数. 假设自己定义的View须要有自己定义的属性.须要在values下建立attrs ...

  6. Android自己定义控件皮肤

    Android自己定义控件皮肤 对于Android的自带控件,其外观仅仅能说中规中矩,而我们平时所示Android应用中,一个简单的button都做得十分美观.甚至于很多button在按下时的外观都有 ...

  7. android 自己定义控件属性(TypedArray以及attrs解释)

    近期在捣鼓android 自己定义控件属性,学到了TypedArray以及attrs.在这当中看了一篇大神博客Android 深入理解Android中的自己定义属性.我就更加深入学习力一番.我就沿着这 ...

  8. Atitit.ui控件---下拉菜单选择控件的实现select html

    Atitit.ui控件---下拉菜单选择控件的实现select   html 1. 调用& model的实现 1 2. -----select.jsp------ 1 1. 调用& m ...

  9. 【转载】 Android PullToRefresh (ListView GridView 下拉刷新) 使用详解

    Android下拉刷新pullToRefreshListViewGridView 转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/3 ...

随机推荐

  1. 表单编码 appliation/x-www-form-urlencoded 与 multipart/form-data 的区别

    当表单使用POST方法时,表单数据提交到服务器端之前有两种编码类型可供选择.默认编码类型为 application/x-www-form-urlencoded,此时所有非字母数字类型的字符都需要转换为 ...

  2. 选择员工要有3S能力

    企业的核心竞争力依托于高素质的员工.不断地对员工进行培训.提升并管理好员工,是让企业持续散发活力的一剂良药. 在企业里,有个说法叫三个房子有一个柱子,第一个是以人为本,怎么样吸引最优秀的员工:第二个是 ...

  3. OpenJudge 东方14ACM小组 / 20170123 02 岛屿

    总时间限制:  40000ms 单个测试点时间限制:  4000ms 内存限制:  128000kB 描述 从前有一座岛屿,这座岛屿是一个长方形,被划为N*M的方格区域,每个区域都有一个确定的高度.不 ...

  4. 【MFC】Button控件和Picture Control的鼠标事件执行顺序

    1.Button控件鼠标事件执行顺序 (1) WM_LBUTTONDOWN (2) WM_LBUTTONUP (3) OnBnClickedButton1(); 2.Picture Control的鼠 ...

  5. 转 C++中不能声明为虚函数的有哪些函数

    传送门 C++中不能声明为虚函数的有哪些函数 常见的不不能声明为虚函数的有:普通函数(非成员函数):静态成员函数:内联成员函数:构造函数:友元函数. 1.为什么C++不支持普通函数为虚函数? 普通函数 ...

  6. WKWebView与js交互中产生的内存泄漏

    最近开发中突然发现富文本帖子详情内存没有释放掉,找了好久问题都没找到,终于今天发现了问题,先上一点代码片段 WKWebViewConfiguration *configuration = [[WKWe ...

  7. Java实验--关于英文短语词语接龙

    在课堂上经过实验之后,重新在宿舍里面从0开始编写大概30分钟左右能够完成这个实验,不是原来的思路. 该实验的表述为:从两个文本input1.txt和input2.txt中读取英文单词,若前面的英文单词 ...

  8. 正确使用Block避免Cycle Retain和Crash

    Block简介 Block作为C语言的扩展,并不是高新技术,和其他语言的闭包或lambda表达式是一回事.需要注意的是由于Objective-C在iOS中不支持GC机制,使用Block必须自己管理内存 ...

  9. 深度排序与alpha混合 【转】

      翻译:李现民 最后修改:2012-07-03 原文:Depth sorting alpha blended objects 先说个题外话,本来我想回答在 Creators Club论坛上的一个常见 ...

  10. Spring核心(ioc控制反转)

     IoC,Inversion Of Control 即控制反转,由容器来管理业务对象之间的依赖关系,而非传统方式中的由代码来管理. 其本质.即将控制权由应用程序代码转到了外部容器,控制权的转移就是 ...