ListView上拉加载下拉刷新

ListView上拉加载下拉刷新

主要用到了这个几个文件,MainActivity是界面的Activity,MyAdapter是ListView的自定义适配,MyListView是自定义带头部LIistView,如果只需要上拉加载就不需要;activity_main.xml是住界面,item.xml是ListView的子布局里面只有一个TextView,listview_footer.xml是listview的加载更多的底部布局,listview_header.xml是listview的头部布局。

MainActivity.java

package com.example.listview; import java.util.ArrayList; import java.util.List; import android.annotation.SuppressLint; import android.app.Activity; import android.os.AsyncTask; import android.os.Bundle; import android.os.Handler; import android.view.LayoutInflater; import android.view.View; import android.widget.AbsListView; import android.widget.AbsListView.OnScrollListener; import android.widget.Toast; import com.example.listview.MyListView.OnRefreshListener; public class MainActivity extends Activity implements OnScrollListener{ /** ListView*/ private MyListView listView; /** 自定义的Adapter*/ private MyAdapter adapter; /** 一共的数据*/ private List list=new ArrayList(); /** ListView的底部布局*/ private View footer; private Handler handler; private int count=0; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); /** 配置好ListView*/ listView=(MyListView) findViewById(R.id.listView); /** 添加底部布局,要在setAdapter前,否则没有效果*/ footer=LayoutInflater.from(this).inflate(R.layout.listview_footer, null); listView.addFooterView(footer); /** 适配listView*/ adapter=new MyAdapter(this, list); listView.setAdapter(adapter); /** 添加一个线程设置时间有等待的效果*/ handler=new Handler(); listView.setOnScrollListener(this); listView.setonRefreshListener(new OnRefreshListener() { @Override public void onRefresh() { new AsyncTask() { protected Void doInBackground(Void... params) { try { Thread.sleep(1000); } catch (Exception e) { e.printStackTrace(); } // list.add("刷新后添加的内容"); return null; } @Override protected void onPostExecute(Void result) { adapter.notifyDataSetChanged(); listView.onRefreshComplete(); } }.execute(null, null, null); } }); setData(); } /** * 底部滚动的监听 */ @Override public void onScrollStateChanged(final AbsListView view, int scrollState) { /** 当滚动停止同时在底部的时候*/ if (scrollState == OnScrollListener.SCROLL_STATE_IDLE && (view.getLastVisiblePosition() == view.getCount() - 1)) { /** 为了有数据加载等待的时间,如果是网络数据请求,则此处不需要直接请求接口就ok*/ handler.postDelayed(new Runnable() { @Override public void run() { setData(); /** 让刷新出来的数据从屏幕开始显示,如果不设定位置,listView数据更新后会跑到第一条数据开始显示*/ listView.setSelection(view.getCount()-1); } }, 2000); } } @Override public void onScroll(AbsListView arg0, int arg1, int arg2, int arg3) { } /** 放数据,如果你的数据可以分页获取就不需要这样,此处是为了有分页的数据*/ @SuppressLint("ShowToast") private void setData(){ //当数据到达总量的时候移除底部布局 if(count>50){ listView.removeFooterView(footer); Toast.makeText(this,"没有更多数据", 500).show(); return; } for(int i=count;i
MyListView.java

package com.example.listview; import java.util.Date; import android.content.Context; import android.util.AttributeSet; import android.view.LayoutInflater; import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; import android.view.animation.LinearInterpolator; import android.view.animation.RotateAnimation; import android.widget.AbsListView; import android.widget.AbsListView.OnScrollListener; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.ListView; import android.widget.ProgressBar; import android.widget.TextView; /** * ListView添加刷新头部自定义的ListView * * @author 刘梓未 * * */ public class MyListView extends ListView implements OnScrollListener { private final static int RELEASE_To_REFRESH = 0;// 下拉过程的状态值 private final static int PULL_To_REFRESH = 1; // 从下拉返回到不刷新的状态值 private final static int REFRESHING = 2;// 正在刷新的状态值 private final static int DONE = 3; private final static int LOADING = 4; // 实际的padding的距离与界面上偏移距离的比例 private final static int RATIO = 3; private LayoutInflater inflater; // ListView头部下拉刷新的布局 private LinearLayout headerView; private TextView lvHeaderTipsTv; private TextView lvHeaderLastUpdatedTv; private ImageView lvHeaderArrowIv; private ProgressBar lvHeaderProgressBar; // 定义头部下拉刷新的布局的高度 private int headerContentHeight; private RotateAnimation animation; private RotateAnimation reverseAnimation; private int startY; private int state; private boolean isBack; // 用于保证startY的值在一个完整的touch事件中只被记录一次 private boolean isRecored; private OnRefreshListener refreshListener; private boolean isRefreshable; public MyListView(Context context) { super(context); init(context); } public MyListView(Context context, AttributeSet attrs) { super(context, attrs); init(context); } private void init(Context context) { setCacheColorHint(context.getResources().getColor(android.R.color.transparent)); inflater = LayoutInflater.from(context); headerView = (LinearLayout) inflater.inflate(R.layout.listview_header, null); lvHeaderTipsTv = (TextView) headerView .findViewById(R.id.lvHeaderTipsTv); lvHeaderLastUpdatedTv = (TextView) headerView .findViewById(R.id.lvHeaderLastUpdatedTv); lvHeaderArrowIv = (ImageView) headerView .findViewById(R.id.lvHeaderArrowIv); // 设置下拉刷新图标的最小高度和宽度 lvHeaderArrowIv.setMinimumWidth(70); lvHeaderArrowIv.setMinimumHeight(50); lvHeaderProgressBar = (ProgressBar) headerView .findViewById(R.id.lvHeaderProgressBar); measureView(headerView); headerContentHeight = headerView.getMeasuredHeight(); // 设置内边距,正好距离顶部为一个负的整个布局的高度,正好把头部隐藏 headerView.setPadding(0, -1 * headerContentHeight, 0, 0); // 重绘一下 headerView.invalidate(); // 将下拉刷新的布局加入ListView的顶部 addHeaderView(headerView, null, false); // 设置滚动监听事件 setOnScrollListener(this); // 设置旋转动画事件 animation = new RotateAnimation(0, -180, RotateAnimation.RELATIVE_TO_SELF, 0.5f, RotateAnimation.RELATIVE_TO_SELF, 0.5f); animation.setInterpolator(new LinearInterpolator()); animation.setDuration(250); animation.setFillAfter(true); reverseAnimation = new RotateAnimation(-180, 0, RotateAnimation.RELATIVE_TO_SELF, 0.5f, RotateAnimation.RELATIVE_TO_SELF, 0.5f); reverseAnimation.setInterpolator(new LinearInterpolator()); reverseAnimation.setDuration(200); reverseAnimation.setFillAfter(true); // 一开始的状态就是下拉刷新完的状态,所以为DONE state = DONE; // 是否正在刷新 isRefreshable = false; } @Override public void onScrollStateChanged(AbsListView view, int scrollState) { } @Override public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) { } @Override public boolean onTouchEvent(MotionEvent ev) { if (isRefreshable) { switch (ev.getAction()) { case MotionEvent.ACTION_DOWN: if (!isRecored) { isRecored = true; startY = (int) ev.getY();// 手指按下时记录当前位置 } break; case MotionEvent.ACTION_UP: if (state != REFRESHING && state != LOADING) { if (state == PULL_To_REFRESH) { state = DONE; changeHeaderViewByState(); } if (state == RELEASE_To_REFRESH) { state = REFRESHING; changeHeaderViewByState(); onLvRefresh(); } } isRecored = false; isBack = false; break; case MotionEvent.ACTION_MOVE: int tempY = (int) ev.getY(); if (!isRecored) { isRecored = true; startY = tempY; } if (state != REFRESHING && isRecored && state != LOADING) { // 保证在设置padding的过程中,当前的位置一直是在head,否则如果当列表超出屏幕的话,当在上推的时候,列表会同时进行滚动 // 可以松手去刷新了 if (state == RELEASE_To_REFRESH) { setSelection(0); // 往上推了,推到了屏幕足够掩盖head的程度,但是还没有推到全部掩盖的地步 if (((tempY - startY) / RATIO 0) { state = PULL_To_REFRESH; changeHeaderViewByState(); } // 一下子推到顶了 else if (tempY - startY = headerContentHeight) {// 由done或者下拉刷新状态转变到松开刷新 state = RELEASE_To_REFRESH; isBack = true; changeHeaderViewByState(); } // 上推到顶了 else if (tempY - startY 0) { state = PULL_To_REFRESH; changeHeaderViewByState(); } } // 更新headView的size if (state == PULL_To_REFRESH) { headerView.setPadding(0, -1 * headerContentHeight + (tempY - startY) / RATIO, 0, 0); } // 更新headView的paddingTop if (state == RELEASE_To_REFRESH) { headerView.setPadding(0, (tempY - startY) / RATIO - headerContentHeight, 0, 0); } } break; default: break; } } return super.onTouchEvent(ev); } // 当状态改变时候,调用该方法,以更新界面 private void changeHeaderViewByState() { switch (state) { case RELEASE_To_REFRESH: lvHeaderArrowIv.setVisibility(View.VISIBLE); lvHeaderProgressBar.setVisibility(View.GONE); lvHeaderTipsTv.setVisibility(View.VISIBLE); lvHeaderLastUpdatedTv.setVisibility(View.VISIBLE); lvHeaderArrowIv.clearAnimation();// 清除动画 lvHeaderArrowIv.startAnimation(animation);// 开始动画效果 lvHeaderTipsTv.setText("松开刷新"); break; case PULL_To_REFRESH: lvHeaderProgressBar.setVisibility(View.GONE); lvHeaderTipsTv.setVisibility(View.VISIBLE); lvHeaderLastUpdatedTv.setVisibility(View.VISIBLE); lvHeaderArrowIv.clearAnimation(); lvHeaderArrowIv.setVisibility(View.VISIBLE); // 是由RELEASE_To_REFRESH状态转变来的 if (isBack) { isBack = false; lvHeaderArrowIv.clearAnimation(); lvHeaderArrowIv.startAnimation(reverseAnimation); lvHeaderTipsTv.setText("下拉刷新"); } else { lvHeaderTipsTv.setText("下拉刷新"); } break; case REFRESHING: headerView.setPadding(0, 0, 0, 0); lvHeaderProgressBar.setVisibility(View.VISIBLE); lvHeaderArrowIv.clearAnimation(); lvHeaderArrowIv.setVisibility(View.GONE); lvHeaderTipsTv.setText("正在刷新..."); lvHeaderLastUpdatedTv.setVisibility(View.VISIBLE); break; case DONE: headerView.setPadding(0, -1 * headerContentHeight, 0, 0); lvHeaderProgressBar.setVisibility(View.GONE); lvHeaderArrowIv.clearAnimation(); lvHeaderArrowIv.setImageResource(R.drawable.head_arrow); lvHeaderTipsTv.setText("下拉刷新"); lvHeaderLastUpdatedTv.setVisibility(View.VISIBLE); break; } } // 此方法直接照搬自网络上的一个下拉刷新的demo,此处是“估计”headView的width以及height private void measureView(View child) { ViewGroup.LayoutParams params = child.getLayoutParams(); if (params == null) { params = new ViewGroup.LayoutParams( ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT); } int childWidthSpec = ViewGroup.getChildMeasureSpec(0, 0 + 0, params.width); int lpHeight = params.height; int childHeightSpec; if (lpHeight > 0) { childHeightSpec = MeasureSpec.makeMeasureSpec(lpHeight, MeasureSpec.EXACTLY); } else { childHeightSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED); } child.measure(childWidthSpec, childHeightSpec); } public void setonRefreshListener(OnRefreshListener refreshListener) { this.refreshListener = refreshListener; isRefreshable = true; } public interface OnRefreshListener { public void onRefresh(); } @SuppressWarnings("deprecation") public void onRefreshComplete() { state = DONE; lvHeaderLastUpdatedTv.setText("最近更新:" + new Date().toLocaleString()); changeHeaderViewByState(); } private void onLvRefresh() { if (refreshListener != null) { refreshListener.onRefresh(); } } }

listview_footer.xml

listview_header.xml
ListView上拉加载下拉刷新

<frameLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentLeft="true" android:layout_centerVertical="true" > </frameLayout>

下载地址

点击复制链接 与好友分享!回本站首页
您对本文章有什么意见或着疑问吗?请到论坛讨论您的关注和建议是我们前行的参考和动力
上一篇:DM8168 PWM驱动(寄存器设置)
下一篇:Swift实现OC中的单例模式
相关文章
图文推荐
ListView上拉加载下拉刷新
适配器模式
ListView上拉加载下拉刷新
Handler的介绍和使用
ListView上拉加载下拉刷新
struts2上传文件
ListView上拉加载下拉刷新
通过JFreeChart的饼状

分类:默认分类 时间:2012-01-05 人气:9
本文关键词:
分享到:

相关文章

  • Android之ListView异步加载图片且仅显示可见子项中的图片 2012-01-16

    折腾了好多天,遇到 N 多让人崩溃无语的问题,不过今天终于有些收获了,这是实验的第一版,有些混乱,下一步进行改造细分,先把代码记录在这儿吧。 网上查了很多资料,发现都千篇一律,抄来抄去,很多细节和完整实例都没看到,只有自己一点点研究了,总体感觉 android 下面要显示个图片真不容易啊。 项目主要实现的功能: 异步加载图片图片内存缓存、异步磁盘文件缓存解决使用 viewHolder 后出现的图片错位问题优化列表滚动性能,仅显示可见子项中的图片无需固定图片显示高度,对高度进行缓存使列表滚动时不会

  • ListView内数据的动态追加 2012-01-20

    设计思路 把置入适配器的list追加数据记录,再使用适配器的notifyDataSetChanged()刷新。 方法案例 以http://blog.csdn.net/jueblog/article/details/12114513的ListView为例,对Activity作如下改进。 [java] package com.app.test01; import java.util.ArrayList; import java.util.HashMap; import java.util.List;

  • 从extenionplugin的C++ 模块中读取数据并显示到Qt的ListView上 2012-01-29

    这次加载的数据来自于C++动态库而不是另一个qml文件。这个比之前的文章复杂。 我的项目目录树如下: /listview2$ tree . ├── imports │ └── mylist │ ├── libmylist.so │ └── qmldir ├── list2.pro ├── plugin.cpp ├── run.sh └── test.qml The list2.pro文件内容如下: TEMPLATE = lib CONFIG += plugin QT += qml DESTDIR

  • Android开发学习笔记:浅谈ListView 2012-02-02

    LisView列表视图是Android开发中非常常用的一种视图组件,它是以垂直列表的方式列出需要显示的列表项。 创建ListView可以用ListView组件,也可以继承ListActivity。在使用过程中最重要的是如何设置ListView显示的内容,也就是怎样设置Adapter。Adapter类型可以分为三种:ArrayAdapter,SimpleCursorAdapter和SimpleAdapter。下面介绍这三种Adapter是如何添加列表视图内容的: 一.ArrayAdapter Ar

  • Android关于ListView的优化问题 2012-03-19

    今天在我哥们的带领下,学习了一些关于ListView的优化方案。现在提出来和大家分享下.... 第一点: 在Listview中数据加载时经常用到的ViewHolder,我们需要把它写成静态类static,这样的话数据是共享的在本地缓存中,取出的数据是很快的。 第二点: 如果Listview需要加载图片的话,我们一般是开子线程去加载数据的,然后再主线程中更新。这样的话为了良好的用户体验,我们经常会设置一张默认图片,如果数据还在加载,我们就先显示默认图片,然后在慢慢加载图片。 holder.img.

  • Android PullToRefresh 下拉刷新,上拉更多,支持ScrollView,ListView,可方便拓展GridView,WebView等 2012-03-27

    在写着东西之前,从网上找到很多这方面的源码,但是基本没有找到满意的,包括在GitHub上的比较有名的Android-PullToRefresh-master,思来想去还是自己写吧,当然其中借鉴了一些别的开源代码! 废话不多说,直接上代码,注释很全乎,应该不难理解,Demo下载地址在最后: package com.zs.pulltorefreshtest; import android.content.Context; import android.util.AttributeSet; impor

  • android的ListView点击item使item展开的做法 2012-04-08

    直接上代码把,主要是重新给item measure高度,直接上代码把 import java.util.ArrayList; import android.app.Activity; import android.os.Bundle; import android.view.LayoutInflater; import android.view.MotionEvent; import android.view.View; import android.view.View.OnTouchListe

  • Android杂谈--内存泄露(1)--contentView缓存使用与ListView优化 2012-04-14

    引起Android内存泄露有很多种原因,下面罗列了一些问题,以后会一一解决 1、构造Adapter时没有使用缓存convertView(衍生出ListView优化问题) 2、查询数据库游标没有关闭 3、Activity中生命周期对象大于Activity生命周期(关于Application Context与Activity Context) 4、Bitmap对象不使用时没有recycle掉(这里还有其他解决方案) 今天说的是第一种:如何使用缓存来优化ListView 因为如果不使用缓存conver

  • android ListView 报错 The specified child already has a parent 2012-04-19

    今天遇到一个问题,在listviev中加入传进来的布局,上下滑动时,报错The specified child already has a parent。 先贴原始代码: @Override public View getView(int position, View convertView, ViewGroup parent) { convertView = layoutInflater.inflate(R.layout.check_laizi_item_ll, null); Relative

Copyright (C) quwantang.com, All Rights Reserved.

趣玩堂 版权所有 京ICP备15002868号

processed in 0.043 (s). 10 q(s)