文档章节

ListView下拉刷新

亓斌哥哥
 亓斌哥哥
发布于 2014/10/09 22:04
字数 1608
阅读 459
收藏 13
点赞 0
评论 0
public class MyListView extends ListView implements OnScrollListener {
private static final int STATE_NORMAL = 0;  // 正常状态
private static final int STATE_PULL = 1;    // 下来状态
private static final int STATE_RELEASE = 2; // 释放状态
private static final int STATE_LOADING = 3; // 数据加载状态
 
private View mHeaderView;   // listview的headerview
private ImageView mImage;   // headerview中图片
private ProgressBar mProgress; // headerview中的progressbar
private TextView mText;      // headerview中的文本
 
private RotateAnimation mAnim1;  // headerview中图片的旋转动画
private RotateAnimation mAnim2;  // 同上
private boolean isNowAtUp;  // 判断当前是不是在listview的最上面
 
private int mHeaderHeight;  // headerview的高度
private int mFirstVisibleItem;  // 保存listview中第一个可见项
private int mScrollState;  // 保存listview滑动的状态
private int mState;  // 保存判断的状态,同上面的常量进行比较,
private int mStartY; // 开始下拉的y值
private OnPullRefreshListener mListener;  // 回调接口
 
public MyListView(Context context, AttributeSet attrs) {
super(context, attrs);
initView();
}
 
public MyListView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
initView();
}
 
// 初始化view
private void initView() {
// 加载headerview
mHeaderView = LayoutInflater.from(getContext()).inflate(
R.layout.header_layout, null);
//获取headerview中组件
mImage = (ImageView) mHeaderView.findViewById(R.id.image);
mProgress = (ProgressBar) mHeaderView.findViewById(R.id.progress);
mText = (TextView) mHeaderView.findViewById(R.id.text);
// 初始化动画
initAnimation();
// 因为下面要用到headerview的高度,但在处理化的时候还没有进行onMeasure
// 所以要手工进行测量
measureView(mHeaderView);
// 获取headerview的高度
mHeaderHeight = mHeaderView.getMeasuredHeight();
// 设置headerview的上padding
// 为负的高度,则隐藏掉headerview
setPaddingTop(-mHeaderHeight);
// 将headerview添加到listview中
addHeaderView(mHeaderView);
 
// 监听滚动
setOnScrollListener(this);
}
 
// 初始化动画
private void initAnimation() {
mAnim1 = new RotateAnimation(180, 0,
RotateAnimation.RELATIVE_TO_SELF, 0.5f,
RotateAnimation.RELATIVE_TO_SELF, 0.5f); 
mAnim2 = new RotateAnimation(0, 180,
RotateAnimation.RELATIVE_TO_SELF, 0.5f,
RotateAnimation.RELATIVE_TO_SELF, 0.5f);
mAnim1.setDuration(500);
mAnim2.setDuration(500);
mAnim1.setFillAfter(true);
mAnim2.setFillAfter(true);
}
 
// 设置headerview的padding
private void setPaddingTop(int top) {
mHeaderView.setPadding(
mHeaderView.getPaddingLeft(),
top,
mHeaderView.getPaddingRight(),
mHeaderView.getPaddingBottom());
 
invalidate();
}
 
// 测量view
private void measureView(View view) {
// 先获取LayoutParams
ViewGroup.LayoutParams lp = view.getLayoutParams();
if (null == lp) {
lp = new ViewGroup.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT);
}
 
// 第一个参数是spec
// 第二个参数是padding
// 第三个参数是我期望的大小
// 如果第三个参数小于0
// 则返回的结果是第一个参数减去第二个参数
// 如果第三个参数不小于0
// 则返回第三个参数
int widthMeasureSpec = ViewGroup.getChildMeasureSpec(0, 0, lp.width);
int height = lp.height;
int heightMeasureSpec;
 
// 生成height的Spec
if (height > 0) {
heightMeasureSpec = MeasureSpec.makeMeasureSpec(height,
MeasureSpec.EXACTLY);
} else {
heightMeasureSpec = MeasureSpec.makeMeasureSpec(0,
MeasureSpec.UNSPECIFIED);
}
 
// 测量view,这样就可以获取headerview的高度了
// 否则headerview的高度获取出来为0
// MATCH_PARENT=-1, WRAP_CONTENT=-2
view.measure(widthMeasureSpec, heightMeasureSpec);
}
 
// 滑动状态该类
@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
// 保存下当前的状态
mScrollState = scrollState;
}
 
@Override
public void onScroll(AbsListView view, int firstVisibleItem,
int visibleItemCount, int totalItemCount) {
// 保存当前第一个可见项
mFirstVisibleItem = firstVisibleItem;
}
 
// 监听touch事件
@Override
public boolean onTouchEvent(MotionEvent ev) {
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
// 如果是按下操作
// 并且现在第一个可见项是listview的第一项
// 即:现在在最上面
if (mFirstVisibleItem == 0) {
isNowAtUp = true;  // 记录现在是在最上面
mStartY = (int) ev.getY(); // 获取点击的y坐标
}
break;
case MotionEvent.ACTION_MOVE:
onMove(ev);  // 在onMove中处理移动事件
break;
case MotionEvent.ACTION_UP:
// 如果当前状态是可释放状态
if(mState == STATE_RELEASE) {
// 那个up后, 修改状态为数据加载状态
mState = STATE_LOADING;
// 刷新界面
refreshView();
// 调用回调接口中的方法
// 具体实现在activity中
mListener.onPull();
}else if(mState == STATE_PULL){  // 如果是下拉状态
mState = STATE_NORMAL; // 则更改状态为正常状态,因为还没有拉到加载数据的程度
refreshView(); // 刷新界面
}
break;
}
return super.onTouchEvent(ev);
}
 
// 刷新界面,其实是更改headerview中子view的状态
private void refreshView() {
switch (mState) {
case STATE_NORMAL:
setPaddingTop(-mHeaderHeight);  // 如果是正常状态,则将headerview隐藏了
break;
case STATE_PULL:  // 如果是下拉状态
mProgress.setVisibility(View.GONE); // 隐藏progressbar
mImage.setVisibility(View.VISIBLE); // 将图片显示出来
mImage.clearAnimation(); // 清除动画
mImage.startAnimation(mAnim1); // 设置旋转动画
mText.setText("下拉刷新!");  // 更新textview的文本
break;
case STATE_RELEASE:  // 释放状态
mProgress.setVisibility(View.GONE);  // 隐藏progressbar
mImage.setVisibility(View.VISIBLE);  // 将图片显示出来
mImage.clearAnimation(); // 清除动画
mImage.startAnimation(mAnim2); // 设置旋转动画
mText.setText("释放加载新数据!"); // 更新textview的文本
break;
case STATE_LOADING:  // 数据加载状态
setPaddingTop(mHeaderHeight);  // 设置paddingtop为headerview的高度
mProgress.setVisibility(View.VISIBLE); // 显示progressbar
mImage.clearAnimation(); // 清除动画
mImage.setVisibility(View.GONE); // 隐藏imageview
mText.setText("正在加载数据..."); // 更新文本
break;
}
}
 
// 处理action_move事件
private void onMove(MotionEvent ev) {
// 如果当前不是在顶部,直接返回
if (!isNowAtUp) {
return;
}
 
int nowY = (int) ev.getY();  // 记录当前的y坐标
int space = nowY - mStartY;  // 计算下拉的程度
int top = space - mHeaderHeight; // 计算top的值
 
switch (mState) {
case STATE_NORMAL:  // 如果是正常状态
if (space > 0) {  // 如果下拉了
mState = STATE_PULL; // 则 修改状态为下拉
refreshView(); // 并刷新headerview
}
break;
case STATE_PULL:  // 如果是下来状态
setPaddingTop(top); // 不断修改headerview的paddingtop
// 如果达到条件,并且还是在下拉中
if (space >= mHeaderHeight + 30
&& mScrollState == OnScrollListener.SCROLL_STATE_TOUCH_SCROLL) {
mState = STATE_RELEASE;  // 修改状态为可释放状态
refreshView(); // 刷新headerview
}
break;
case STATE_RELEASE:  // 如果是可释放状态
setPaddingTop(top); // 不断修改headerview的paddingtop
// 如果下拉程度在STATE_PULL区间
if (space > 0 && space <= mHeaderHeight + 30) {
mState = STATE_PULL; // 则修改状态为下来状态,这样是又慢慢拉回去了
refreshView(); // 刷新headerview
} else if (space <= 0) {  // 如果没有下拉的空间了
mState = STATE_NORMAL; // 修改状态为正常状态,拉了一圈又回退回去了
isNowAtUp = false; // 还原默认值
refreshView(); // 刷新headerview
}
break;
}
}
// 外部调用的方法
// 通知我新数据加载完毕
// 还原状态为正常状态
public void endToRefresh() {
mState = STATE_NORMAL;
refreshView();
}
// 设置加载数据的回调接口
public void setOnPullRefreshListener(OnPullRefreshListener l) {
mListener = l;
}
// 定义一个回调接口
public interface OnPullRefreshListener {
public void onPull();
}
}


MyListView中使用的header_layout.xml文件:

<?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:background="@android:color/darker_gray"
    android:orientation="vertical" >
    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:paddingBottom="10dip"
        android:paddingLeft="30dip"
        android:paddingRight="30dip"
        android:paddingTop="10dip" >
        <LinearLayout
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerInParent="true"
            android:orientation="horizontal" >
            <ImageView
                android:id="@+id/image"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_gravity="center"
                android:src="@drawable/arrow" />
            <ProgressBar
                android:id="@+id/progress"
                style="?android:attr/progressBarStyleSmall"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_gravity="center"
                android:visibility="gone" />
            <TextView
                android:id="@+id/text"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_gravity="center"
                android:text="下拉可以刷新" />
        </LinearLayout>
    </RelativeLayout>
</LinearLayout>



使用:

在布局文件中:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity" >
    <org.load.listview.MyListView
        android:id="@+id/list"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />
</RelativeLayout>


在MainActivity中:

public class MainActivity extends Activity {
private MyListView mListView;
// 模拟数据
private String[] mData = { "aaa", "bbb", "ccc", "ddd", "eee", "fff", "ggg",
"hhh", "iii" };
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mListView = (MyListView) findViewById(R.id.list);
// 数据适配器
final ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,
android.R.layout.simple_list_item_1, mData);
// 设置适配器
mListView.setAdapter(adapter);
// 这里就用到了回调接口
// 表示当可以加载新数据时干什么
mListView.setOnPullRefreshListener(new OnPullRefreshListener() {
@Override
public void onPull() {
// 模拟获取新数据
// 延迟2s后更新前两个数据
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 2; i++) {
mData[i] = "new data " + new Random().nextInt(100);
adapter.notifyDataSetChanged();
mListView.endToRefresh();  // 通知MyListView数据加载完毕了
}
}
}, 2000);
}
});
}
}






© 著作权归作者所有

共有 人打赏支持
亓斌哥哥

亓斌哥哥

粉丝 28
博文 34
码字总数 12346
作品 13
莱芜
程序员
Jaynm/PullToRefreshListView

PullToRefreshScrollViewDemo Android使用PullToRefresh完成ListView下拉刷新和左滑删除 一、本文主要内容: 使用PullToRefresh完成ListView下拉、上拉刷新; 扩展PullToRefresh完美的实现L...

Jaynm ⋅ 2016/11/03 ⋅ 0

Android学习系列(15)--App列表之下拉刷新

Android的ListView是应用最广的一个组件,功能强大,扩展性灵活(不局限于ListView本身一个类),前面的文章有介绍分组,拖拽,3D立体,游标,圆角,而今天我们要介绍的是另外一个扩展ListVie...

chengche ⋅ 2014/01/08 ⋅ 0

滑动事件总结(刷新,加载更多,嵌套滑动)

下拉刷新 在Api21之前,ListView和GridView的使用相当普遍,包括下拉刷新我们也可以使用它,利用他的addHeaderView()和addFooterView()方法,或者使用父级中隐藏View的方式来实现; 在A...

卐字旗下的余晖 ⋅ 2016/06/07 ⋅ 0

滚动到底部加载更多及下拉刷新listview的使用

最新内容建议直接访问原文:滚动到底部加载更多及下拉刷新listview的使用 本文主要介绍可同时实现下拉刷新及滑动到底部加载更多的ListView的使用。 该ListView优点包括:a. 可自定义下拉响应...

Trinea ⋅ 2013/06/24 ⋅ 3

React Native支持任意组件实现下拉刷新功能,并且可以自定义下拉刷新头部

1.背景   无论是Android还是ios,下拉刷新都是一个很有必要也很重要的功能。那么在RN(以下用RN表示React Native)之中,我们该如何实现下拉刷新功能呢?RN官方提供了一个用于ScrollView,Li...

请叫我百米冲刺 ⋅ 2017/06/22 ⋅ 0

下拉刷新ListView的实现原理

本文主要介绍如何实现类似新浪微博客户端下拉刷新效果的ListView。关于其使用见下拉刷新ListView的使用。 示例APK地址:TrineaAndroidDemo 首先让我们看下效果 四张图分别为第一次下拉、第一...

等待流星 ⋅ 2014/03/14 ⋅ 0

Android 下拉刷新框架实现

前段时间项目中用到了下拉刷新功能,之前在网上也找到过类似的demo,但这些demo的质量参差不齐,用户体验也不好,接口设计也不行。最张没办法,终于忍不了了,自己就写了一个下拉刷新的框架,...

军歌 ⋅ 2014/06/23 ⋅ 1

一起撸个朋友圈吧(step1) ListView(中)篇

项目地址:https://github.com/razerdp/FriendCircle 一起撸个朋友圈吧这是本文所处文集,所有更新都会在这个文集里面哦,欢迎关注 上篇链接:http://www.jianshu.com/p/7fa237cfddbb 下篇链...

WeiChaoFeng ⋅ 2017/12/13 ⋅ 0

重写ListView实现下拉刷新上拉加载

安卓本身的ListView没有刷新功能,要想实现这一功能,就得继承ListView并重写它的方法。同时也要实现其OnScrollListener这一接口。 下拉刷新,需要在原本的ListView上部添加一个Head,ListV...

ZytCandy ⋅ 2014/08/07 ⋅ 4

ExpandableListView和Listview可以共用一个写好的下拉刷新的工具类吗

以前我用的ListView加了下拉刷新,现在我改成了使用ExpandableListView,在他的基础上再加下拉刷新,我把关于Listview的都改成了ExpandableListView的 ,但是没效果,不知道是 ExpandableLi...

BAITOCC ⋅ 2013/12/26 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

浅谈springboot Web模式下的线程安全问题

我们在@RestController下,一般都是@AutoWired一些Service,由于这些Service都是单例,所以并不存在线程安全问题。 由于Controller本身是单例模式 (非线程安全的), 这意味着每个request过来,...

算法之名 ⋅ 今天 ⋅ 0

知乎Java数据结构

作者:匿名用户 链接:https://www.zhihu.com/question/35947829/answer/66113038 来源:知乎 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。 感觉知乎上嘲讽题主简...

颖伙虫 ⋅ 今天 ⋅ 0

Confluence 6 恢复一个站点有关使用站点导出为备份的说明

推荐使用生产备份策略。我们推荐你针对你的生产环境中使用的 Confluence 参考 Production Backup Strategy 页面中的内容进行备份和恢复(这个需要你备份你的数据库和 home 目录)。XML 导出备...

honeymose ⋅ 今天 ⋅ 0

JavaScript零基础入门——(九)JavaScript的函数

JavaScript零基础入门——(九)JavaScript的函数 欢迎回到我们的JavaScript零基础入门,上一节课我们了解了有关JS中数组的相关知识点,不知道大家有没有自己去敲一敲,消化一下?这一节课,...

JandenMa ⋅ 今天 ⋅ 0

火狐浏览器各版本下载及插件httprequest

各版本下载地址:http://ftp.mozilla.org/pub/mozilla.org//firefox/releases/ httprequest插件截至57版本可用

xiaoge2016 ⋅ 今天 ⋅ 0

Docker系列教程28-实战:使用Docker Compose运行ELK

原文:http://www.itmuch.com/docker/28-docker-compose-in-action-elk/,转载请说明出处。 ElasticSearch【存储】 Logtash【日志聚合器】 Kibana【界面】 答案: version: '2'services: ...

周立_ITMuch ⋅ 今天 ⋅ 0

使用快嘉sdkg极速搭建接口模拟系统

在具体项目研发过程中,一旦前后端双方约定好接口,前端和app同事就会希望后台同事可以尽快提供可供对接的接口方便调试,而对后台同事来说定好接口还仅是个开始、设计流程,实现业务逻辑,编...

fastjrun ⋅ 今天 ⋅ 0

PXE/KickStart 无人值守安装

导言 作为中小公司的运维,经常会遇到一些机械式的重复工作,例如:有时公司同时上线几十甚至上百台服务器,而且需要我们在短时间内完成系统安装。 常规的办法有什么? 光盘安装系统 ===> 一...

kangvcar ⋅ 昨天 ⋅ 0

使用Puppeteer撸一个爬虫

Puppeteer是什么 puppeteer是谷歌chrome团队官方开发的一个无界面(Headless)chrome工具。Chrome Headless将成为web应用自动化测试的行业标杆。所以我们很有必要来了解一下它。所谓的无头浏...

小草先森 ⋅ 昨天 ⋅ 0

Java Done Right

* 表示难度较大或理论性较强。 ** 表示难度更大或理论性更强。 【Java语言本身】 基础语法,面向对象,顺序编程,并发编程,网络编程,泛型,注解,lambda(Java8),module(Java9),var(...

风华神使 ⋅ 昨天 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部