- 浏览: 18722 次
- 性别:
- 来自: 北京
最新评论
之前在用ListView做下拉刷新和上拉加载的时候一直都是在网上找的实例,
但效果都不是太好,然后自己根据实例的思路,自己梳理了一下,自己也写了一把,感觉也不是太好,在此做下记录吧,希望对初入ANDROID开发的新手们有所帮助,直接上代码吧
在外部使用的时候,
需使用下拉刷新,直接实现CustomListView的OnRefreshListenner接口
需使用上拉加载,先实现Custom的setOnAddFootListener接口为ListView赋上想要显示的布局,然后再实现OnFootLoadingListener接口执行加载时需要做的请求、数据解析及ListView数据源刷新。最后需调用CustomListView.OnFootLoadingComplete()回复初始状态 和 CustomListView.removeFooterView()移除FootViewW布局。
大概实现就是这样,在此因为时间的原因没有写上实现的思路,有时间补上。但是此实例有明显的不足之处。
1. 下拉刷新与上拉加载的效果太突兀,还有待优化。
2. 下拉刷新与上拉加载的touch事件实现上区分的还不是很清晰明确,还有待优化。
但效果都不是太好,然后自己根据实例的思路,自己梳理了一下,自己也写了一把,感觉也不是太好,在此做下记录吧,希望对初入ANDROID开发的新手们有所帮助,直接上代码吧
package cn.zan.control.view; import java.util.Date; import android.content.Context; import android.util.AttributeSet; import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; import android.view.animation.Animation; import android.view.animation.LinearInterpolator; import android.view.animation.RotateAnimation; import android.widget.AbsListView; import android.widget.ImageView; import android.widget.ListAdapter; import android.widget.ListView; import android.widget.ProgressBar; import android.widget.TextView; import cn.zan.zan_society.R; /** * Gening 2013-10-31 **/ public class CustomListView extends ListView { private static final int DONE = 0; private static final int PULL_TO_REFRESH = 1; private static final int RELEASE_TO_REFRESH = 2; private static final int REFRESHING = 3; private static final float RATIO = 3; private int state; // 当前下拉刷新的状态 private int firstVisibleIndex; // ListView 中第一个可以看见的Item下标 /***************************** ListView 头部 View 控件 ***************************/ private View headView; // ListView 头部 View private ImageView headArrow; // ListView 头部 View的箭头 private ProgressBar progressBar; // ListView 头部 View的读取转圈 private TextView headTitle; // ListView 头部 View里的文字 private TextView headLastUpdate; // ListView 头部 View里的文字,最后更新时间 private int headContentHeight; // ListView 头部 View的高度 private Animation animation; private Animation reverseAnimation; private boolean isRefreshable; private boolean isRecored = false; // 用来记录第一次按下坐标点,在整个滑动的过程中 只记录一次 private float startY; private boolean isBack = false; private boolean isFootLoading = false; // 正在加载底部数据标识 private boolean hasFoot = false; // 是否有了底部 View(FootView) private int lastPos; // 最后一个可见的item的位置 private int count; // ListView Item总数,注意不是当前可见的item总数 public CustomListView(Context context, AttributeSet attrs) { super(context, attrs); if (isInEditMode()) { return; } init(context); } private void init(Context context) { // listview 设置滑动时缓冲背景色 setCacheColorHint(0x00000000); headView = View.inflate(context, R.layout.head, null); headArrow = (ImageView) headView.findViewById(R.id.head_arrow); progressBar = (ProgressBar) headView.findViewById(R.id.progressbar); headTitle = (TextView) headView.findViewById(R.id.head_title); headLastUpdate = (TextView) headView.findViewById(R.id.head_last_update); headArrow.setMinimumWidth(50); headArrow.setMinimumHeight(70); MeasureView(headView); headContentHeight = headView.getMeasuredHeight(); headView.setPadding(0, -1 * headContentHeight, 0, 0); addHeaderView(headView); // 为 ListView加入顶部 View this.setOnScrollListener(custom_listview_onscroll_lis); animation = new RotateAnimation(-180, 0, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f); animation.setDuration(250); animation.setFillAfter(true); // 设定动画结束时,停留在动画结束位置 (保留动画效果) animation.setInterpolator(new LinearInterpolator()); // 匀速变化 reverseAnimation = new RotateAnimation(0, -180, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f); reverseAnimation.setDuration(200); reverseAnimation.setFillAfter(true);// 设定动画结束时,停留在动画结束位置 (保留动画效果) reverseAnimation.setInterpolator(new LinearInterpolator());// 匀速变化 // 设置当前headView的状态 state = DONE; // 设置当前下拉刷新是否可用 isRefreshable = false; } /** 测量headView的 宽高 **/ private void MeasureView(View child) { ViewGroup.LayoutParams lp = child.getLayoutParams(); if (null == lp) { lp = new ViewGroup.LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT); } int measureChildWidth = ViewGroup.getChildMeasureSpec(0, 0, lp.width); int measureChildHeight; if (lp.height > 0) { measureChildHeight = MeasureSpec.makeMeasureSpec(lp.height, MeasureSpec.EXACTLY); } else { measureChildHeight = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED); } child.measure(measureChildWidth, measureChildHeight); } @Override public boolean onTouchEvent(MotionEvent event) { switch (event.getAction()) { case MotionEvent.ACTION_DOWN: if (isRefreshable) { if (firstVisibleIndex == 0 && !isRecored) { startY = event.getY(); isRecored = true; } } break; case MotionEvent.ACTION_MOVE: if (isRefreshable) { float tempY = event.getY(); if (firstVisibleIndex == 0 && !isRecored) { startY = tempY; isRecored = true; } if (isRecored) { if (tempY - startY < 0) { break; } if (state != REFRESHING) { if (state == PULL_TO_REFRESH) { if ((tempY - startY) / RATIO >= headContentHeight && (tempY - startY) > 0) { // 向下拉了 从下拉刷新的状态 来到 松开刷新的状态 state = RELEASE_TO_REFRESH; changeHeadViewOfState(); } else if ((tempY - startY) <= 0) { // 向上推了 从下拉刷新的状态 来到 刷新完成的状态 state = DONE; changeHeadViewOfState(); } } else if (state == RELEASE_TO_REFRESH) { // 向上推了 还没有完全将HEADVIEW 隐藏掉(可以看到一部分) if ((tempY - startY) / RATIO < headContentHeight && (tempY - startY) > 0) { // 从松开刷新的状态 来到 下拉刷新的状态 state = PULL_TO_REFRESH; changeHeadViewOfState(); isBack = true; } else if ((tempY - startY) <= 0) { // 向上推了 一下子推到了最上面 从松开刷新的状态 来到 刷新完成的状态 (数据不刷新的) state = DONE; changeHeadViewOfState(); } } else if (state == DONE) { // 刷新完成的状态 来到 下拉刷新的状态 if ((tempY - startY) > 0) { state = PULL_TO_REFRESH; changeHeadViewOfState(); } } if (state == PULL_TO_REFRESH) headView.setPadding(0, (int) ((tempY - startY) / RATIO - headContentHeight), 0, 0); if (state == RELEASE_TO_REFRESH) headView.setPadding(0, (int) ((tempY - startY) / RATIO - headContentHeight), 0, 0); } } } break; case MotionEvent.ACTION_UP: if (isRefreshable) { if (state != REFRESHING) { if (state == PULL_TO_REFRESH) { // 松手 state = DONE; changeHeadViewOfState(); } else if (state == RELEASE_TO_REFRESH) { // 松手 state = REFRESHING; changeHeadViewOfState(); // 执行数据刷新方法 onRefresh(); } } isRecored = false; isBack = false; } break; } return super.onTouchEvent(event); } /** 改变下拉刷新时,头部控件显示样式 **/ private void changeHeadViewOfState() { switch (state) { case PULL_TO_REFRESH: headArrow.setVisibility(View.VISIBLE); progressBar.setVisibility(View.GONE); headTitle.setVisibility(View.VISIBLE); headLastUpdate.setVisibility(View.VISIBLE); headArrow.clearAnimation(); headTitle.setText("下拉可以刷新"); // 由 松开刷新 到 下拉刷新 if (isBack) { headArrow.startAnimation(animation); isBack = false; } break; case RELEASE_TO_REFRESH: headArrow.setVisibility(View.VISIBLE); progressBar.setVisibility(View.GONE); headTitle.setVisibility(View.VISIBLE); headLastUpdate.setVisibility(View.VISIBLE); headArrow.clearAnimation(); headArrow.startAnimation(reverseAnimation); headTitle.setText("松开可以刷新"); break; case REFRESHING: headArrow.setVisibility(View.GONE); progressBar.setVisibility(View.VISIBLE); headTitle.setVisibility(View.VISIBLE); headLastUpdate.setVisibility(View.VISIBLE); headArrow.clearAnimation(); headTitle.setText("正在刷新..."); headView.setPadding(0, 0, 0, 0); break; case DONE: headArrow.setVisibility(View.VISIBLE); progressBar.setVisibility(View.GONE); headTitle.setVisibility(View.VISIBLE); headLastUpdate.setVisibility(View.VISIBLE); headArrow.clearAnimation(); headTitle.setText("下拉可以刷新"); headView.setPadding(0, -1 * headContentHeight, 0, 0); break; } } /** ListView 监听事件 **/ private OnScrollListener custom_listview_onscroll_lis = new OnScrollListener() { @Override public void onScrollStateChanged(AbsListView view, int scrollState) { if (!isFootLoading) { // 没有滚动 if (hasFoot && scrollState == SCROLL_STATE_IDLE) { isFootLoading = true; onFootLoading(); } } } @Override public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) { firstVisibleIndex = firstVisibleItem; lastPos = getLastVisiblePosition(); count = totalItemCount; // 因为刚进入的时候,lastPos=-1,count=0,这个时候不能让它执行onAddFoot方法 if (lastPos == count - 1 && !hasFoot && lastPos != -1) { hasFoot = true; onAddFoot(); } } }; /** 下拉刷新监听 **/ private OnRefreshListner refreshListner; // 刷新监听器 /** 设置下拉刷新监听器 **/ public void setOnRefreshListner(OnRefreshListner listener) { isRefreshable = true; refreshListner = listener; } /** 执行下拉刷新操作 **/ private void onRefresh() { if (refreshListner != null) { refreshListner.onRefresh(); } } /** 添加底部View(FootView)监听器 **/ public OnAddFootListener onAddFootListener; /** 设置添加Foot监听器 **/ public void setOnAddFootListener(OnAddFootListener addFootListener) { onAddFootListener = addFootListener; } /** 执行添加Foot **/ public void onAddFoot() { if (onAddFootListener != null && hasFoot) { onAddFootListener.addFoot(); } } /** 上拉加载,监听器 **/ public OnFootLoadingListener footLoadingListener; public void setOnFootLoadingListener(OnFootLoadingListener footLoading) { footLoadingListener = footLoading; } /** 执行底部加载 **/ public void onFootLoading() { if (footLoadingListener != null && isFootLoading) { footLoadingListener.onFootLoading(); } } /********************************************************************** 监听器 **************************************************************************/ /** 下拉刷新监听器 **/ public interface OnRefreshListner { // 下拉刷新的时候,在这里执行获取数据的过程 void onRefresh(); } /** 添加Foot的监听器 **/ public interface OnAddFootListener { // 这里是用户addFootView的操作 void addFoot(); } /** 上拉加载监听器 **/ public interface OnFootLoadingListener { // 上拉加载的时候,在这里行后台获取数据的过程 void onFootLoading(); } /******************************************************************** 对外调用方法 *****************************************************************/ /** 底部数据加载完成,用户需要加入一个removeFootView的操作 **/ public void onFootLoadingComplete() { hasFoot = false; isFootLoading = false; } /** 上拉刷新完成时 所执行的操作,更改状态,隐藏head **/ public void onRefreshComplete() { state = DONE; changeHeadViewOfState(); headLastUpdate.setText("最后刷新时间: " + new Date().toLocaleString()); } @Override public void setAdapter(ListAdapter adapter) { headLastUpdate.setText("最后刷新时间: " + new Date().toLocaleString()); super.setAdapter(adapter); } }
在外部使用的时候,
需使用下拉刷新,直接实现CustomListView的OnRefreshListenner接口
需使用上拉加载,先实现Custom的setOnAddFootListener接口为ListView赋上想要显示的布局,然后再实现OnFootLoadingListener接口执行加载时需要做的请求、数据解析及ListView数据源刷新。最后需调用CustomListView.OnFootLoadingComplete()回复初始状态 和 CustomListView.removeFooterView()移除FootViewW布局。
大概实现就是这样,在此因为时间的原因没有写上实现的思路,有时间补上。但是此实例有明显的不足之处。
1. 下拉刷新与上拉加载的效果太突兀,还有待优化。
2. 下拉刷新与上拉加载的touch事件实现上区分的还不是很清晰明确,还有待优化。
- CustomListView.zip (3.5 KB)
- 下载次数: 11
相关推荐
标题提到的"android listView下拉刷新 上拉加载 分开",意味着它提供了三个独立的示例,分别针对下拉刷新和上拉加载功能进行实现。下面我们将详细探讨这些知识点。 1. **下拉刷新(Pull-to-Refresh)** 下拉刷新功能...
"Android Listview下拉刷新上拉加载源码"这个资源可能包含了实现这些功能的具体代码示例。 下拉刷新功能允许用户通过手势向下拉动ListView的顶部来更新列表内容,通常用于获取最新数据。这种功能的实现通常依赖于第...
首先,我们看到标题和描述提到了"android listview下拉刷新上拉加载",这通常是指在ListView顶部添加一个可下拉的刷新视图,当用户下拉时显示刷新动画并触发数据更新。同样,在ListView底部添加一个可上拉的加载视图...
这就是“android listview下拉刷新上拉加载更多改良版”所解决的问题。 下拉刷新(Pull-to-Refresh)功能让用户可以通过手势向下拉动列表来更新数据,而上拉加载更多(Load More)则允许用户在滚动到底部时加载更多...
总结来说,"android listview 下拉刷新 上拉加载整合"是Android开发中提升用户体验的重要技术点,通过使用开源库或自定义实现,我们可以为ListView添加这两种功能,提高应用的交互性和功能性。对于初学者,理解并...
为了提升用户体验,开发者经常需要在ListView中实现下拉刷新、上拉加载和滑动删除等功能。本篇将详细讲解如何在Android中实现这些特性。 下拉刷新(Pull-to-Refresh)功能允许用户通过向下拉动列表来获取最新数据。...
android listview下拉刷新 上拉加载更多 http://blog.csdn.net/wenwei19861106/article/details/78016472 http://blog.csdn.net/wenwei19861106/article/details/78016472
"完美的ListView下拉刷新上拉加载实例Demo"就是一个这样的示例项目,它旨在帮助开发者理解和实现这种交互模式。 下拉刷新(Pull-to-Refresh)功能允许用户通过在ListView顶部向下拉动来更新列表内容,通常用于获取...
总的来说,自定义ListView下拉刷新和上拉加载更多虽然涉及到一些复杂的交互逻辑,但通过合理的设计和第三方库,可以大大简化开发过程。在实际项目中,可以根据需求选择自定义实现或者利用已有的解决方案,以提供更好...
以上就是关于“Android ListView下拉刷新、动态加载数据及图文混排”的实现步骤。通过这个功能,用户可以在滚动到列表底部时加载更多内容,而下拉刷新则允许用户获取最新的数据,提高了用户体验。
总之,下拉刷新和上拉加载更多是提升Android应用用户体验的关键特性,通过合理使用开源库和自定义事件监听,可以轻松地在ListView中实现这些功能。开发者可以根据项目需求选择合适的库,或者自定义实现,以满足各种...
总结起来,自定义ListView下拉刷新和上拉加载更多是提升Android应用性能和用户体验的重要手段。通过自定义组件,开发者可以灵活地设计交互和视觉效果,更好地匹配应用的整体设计。理解并掌握这种自定义实现方法对于...
总结,实现"android listview 下拉刷新 上拉翻页 仿新浪微博客户端"的功能,关键在于选用合适的第三方库(如XListView)并正确设置和监听其刷新和加载事件。同时,合理的数据加载策略、动画效果以及状态处理都是提升...
在Android应用开发中,"下拉刷新"和"上拉加载"是常见的功能,用于提供流畅的用户体验,尤其是在处理大量数据列表时。本教程将详细讲解如何在Android中实现自定义的下拉刷新和上拉加载功能。 首先,我们要了解这两个...
在Android开发中,下拉刷新和上拉加载是常见的用户交互功能,特别是在列表视图(ListView)中。这种设计能够提升用户体验,使用户无需离开当前界面就能获取更多数据。本教程将详细介绍如何在Android中实现这样的功能。...
本Demo "Android ListView下拉刷新 Demo.rar" 主要是为了展示如何在ListView中实现下拉刷新功能,帮助开发者更好地理解和实践这一功能。 首先,我们要理解下拉刷新的基本概念。下拉刷新,顾名思义,是指用户在...
综上所述,实现Android Studio环境下的ListView下拉刷新和上拉加载,需要结合SwipeRefreshLayout和自定义的OnScrollListener。这两个功能极大地提升了用户在浏览列表数据时的交互体验,使得应用更具吸引力。在实际...
在Android开发中,ListView是一种常用的组件,用于展示...通过分析和理解这个"Android应用源码 ListView下拉刷新 Demo",开发者能够更好地掌握在实际项目中实现ListView下拉刷新的方法,提高应用的交互性和用户体验。
在Android开发中,自定义ListView实现下拉刷新和加载更多的功能是常见的需求,尤其是在构建具有数据流滚动和实时更新的应用程序时。这个"自定义ListView实现下拉刷新+加载更多功能Demo"旨在帮助开发者理解如何集成...