本文主要介绍可同时实现下拉刷新及滑动到底部加载更多的ListView的使用。
该ListView优点包括:a. 可自定义下拉响应事件(如下拉刷新) b.可自定义滚动到底部响应的事件(如滑动到底部加载更多) c.可自定义丰富的样式 d.高效(若下拉样式关闭不会加载其布局,同listView效率一致) e. 丰富的设置。
更多下拉刷新开源项目可见 Android 下拉刷新。底部加载更多开源项目可见 Android 底部加载更多。
Demo APK 可以方便的查看效果,在各大应用商店搜索 trinea android 下载即可,如:Google Play。
可运行代码地址可见DropDownListViewDemo,效果图如下:
1、引入公共库
引入TrineaAndroidCommon@Github(欢迎star和fork^_^)作为你项目的library(如何拉取代码及添加公共库),或是自己抽取其中的DropDownListView@Github部分使用。
2、在layout中定义
将布局中的ListView标签换成cn.trinea.android.common.view.DropDownListView标签
并加上自定义属性的命名空间xmlns:listViewAttr=”http://schemas.android.com/apk/res/cn.trinea.android.demo”,其中cn.trinea.android.demo需要用自己的包名替换。如何自定义属性及其命名空间可见本文最后。xml代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:listViewAttr="http://schemas.android.com/apk/res/cn.trinea.android.demo" android:layout_width="match_parent" android:layout_height="match_parent" > <cn.trinea.android.common.view.DropDownListView android:id="@+id/list_view" android:layout_width="match_parent" android:layout_height="wrap_content" android:drawSelectorOnTop="false" android:paddingBottom="@dimen/dp_40" listViewAttr:isDropDownStyle="true" listViewAttr:isOnBottomStyle="true" listViewAttr:isAutoLoadOnBottom="true" /> </RelativeLayout> |
DropDownListView自定义了三个boolean属性
1 2 3 4 5 |
<declare-styleable name="drop_down_list_attr"> <attr name="isDropDownStyle" format="boolean" /> <attr name="isOnBottomStyle" format="boolean" /> <attr name="isAutoLoadOnBottom" format="boolean" /> </declare-styleable> |
isDropDownStyle表示是否允许下拉样式,java代码中可自定义下拉listener,表示需要完成的任务
isOnBottomStyle表示是否允许底部样式,java代码中可自定义滚动到底部的listener,表示需要完成的任务
isAutoLoadOnBottom表示是否允许滚动到底部时自动执行对应listener,仅在isOnBottomStyle为true时有效
PS:如果isDropDownStyle或isOnBottomStyle为false,并不会加载对应的布局,所以性能同ListView一样。
3、在Java类中调用
通过setOnDropDownListener设置下拉的事件,不过需要在事件结束时手动调用onDropDownComplete恢复状态(注意需要在adapter.notifyDataSetChanged();后面调用)
通过setOnBottomListener设置滚动到底部的事件,不过需要在事件结束时手动调用onBottomComplete恢复状态,示例代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 |
/** * DropDownListViewDemo * * @author Trinea 2013-6-1 */ public class DropDownListViewDemo extends BaseActivity { private LinkedList<String> listItems = null; private DropDownListView listView = null; private ArrayAdapter<String> adapter; private String[] mStrings = { "Aaaaaa", "Bbbbbb", "Cccccc", "Dddddd", "Eeeeee", "Ffffff", "Gggggg", "Hhhhhh", "Iiiiii", "Jjjjjj", "Kkkkkk", "Llllll", "Mmmmmm", "Nnnnnn", }; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState, R.layout.drop_down_listview_demo); listView = (DropDownListView)findViewById(R.id.list_view); // set drop down listener listView.setOnDropDownListener(new OnDropDownListener() { @Override public void onDropDown() { new GetDataTask(true).execute(); } }); // set on bottom listener listView.setOnBottomListener(new OnClickListener() { @Override public void onClick(View v) { new GetDataTask(false).execute(); } }); listItems = new LinkedList<String>(); listItems.addAll(Arrays.asList(mStrings)); adapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, listItems); listView.setAdapter(adapter); } private class GetDataTask extends AsyncTask<Void, Void, String[]> { private boolean isDropDown; public GetDataTask(boolean isDropDown){ this.isDropDown = isDropDown; } @Override protected String[] doInBackground(Void... params) { try { Thread.sleep(1000); } catch (InterruptedException e) { ; } return mStrings; } @Override protected void onPostExecute(String[] result) { if (isDropDown) { listItems.addFirst("Added after drop down"); adapter.notifyDataSetChanged(); // should call onDropDownComplete function of DropDownListView at end of drop down complete. SimpleDateFormat dateFormat = new SimpleDateFormat("MM-dd HH:mm:ss"); listView.onDropDownComplete(getString(R.string.update_at) + dateFormat.format(new Date())); } else { listItems.add("Added after on bottom"); adapter.notifyDataSetChanged(); // should call onBottomComplete function of DropDownListView at end of on bottom complete. listView.onBottomComplete(); } super.onPostExecute(result); } } } |
4、高级接口设置
public void setOnDropDownListener(OnDropDownListener onDropDownListener)设置下拉的事件
public void onDropDownComplete()和public void onDropDownComplete(CharSequence secondText)恢复下拉状态,注意onDropDownComplete需要在adapter.notifyDataSetChanged();后面调用
public void setOnBottomListener(OnClickListener onBottomListener)设置滚动到底部的事件
public void onBottomComplete()恢复底部状态
public void setSecondPositionVisible()
在isDropDownStyle为true情况下,drop down的header layout为ListView position为0的item,所以可能需要调用(如adapter.notifyDataSetChanged())setSecondPositionVisible()设置position为1(即第二个)的item可见。setSelection(0)滚动到的header layout的item。onDropDownComplete()默认已经调用setSecondPositionVisible()
public void setDropDownStyle(boolean isDropDownStyle)同xml中的isDropDownStyle属性,表示是否为下拉样式,下拉释放后执行onDropDownListener
public void setOnBottomStyle(boolean isOnBottomStyle)同xml中isOnBottomStyle属性,表示滚动到底部执行onBottomListener样式
public void setAutoLoadOnBottom(boolean isAutoLoadOnBottom)同xml中isAutoLoadOnBottom属性,表示滚动到底部是否自动执行onBottomListener
public void setHeaderPaddingTopRate(float headerPaddingTopRate)设置header padding top距离与实际下拉距离的比例
public void setHeaderReleaseMinDistance(int headerReleaseMinDistance)设置header可释放执行onDropDownListener的最小距离
public void setShowFooterProgressBar(boolean isShowFooterProgressBar)设置底部是否显示progressbar
public void setHasMore(boolean hasMore)set whether has more
public void setHeaderDefaultText(String headerDefaultText)设置header默认文字, default is R.string.drop_down_list_header_default_text
public void setHeaderPullText(String headerPullText)设置header下拉提示文字, default is R.string.drop_down_list_header_pull_text
public void setHeaderReleaseText(String headerReleaseText)设置header可释放提示文字, default is R.string.drop_down_list_header_release_text
public void setHeaderLoadingText(String headerLoadingText)设置header加载中提示文字, default is R.string.drop_down_list_header_loading_text
public void setFooterDefaultText(String footerDefaultText)设置footer默认文字, default is R.string.drop_down_list_footer_default_text
public void setFooterLoadingText(String footerLoadingText)设置footer加载中提示文字, default is R.string.drop_down_list_footer_loading_text
public void setFooterNoMoreText(String footerNoMoreText)设置footer没有更多提示文字, default is R.string.drop_down_list_footer_no_more_text
public void setHeaderSecondText(CharSequence secondText)设置header第二部分文字, default is null
5、样式设置(自定义header和footer信息)
将TrineaAndroidCommon作为lib引入之后,可以在自己工程内重定义某些资源,覆盖TrineaAndroidCommon中的设置。
自定义下拉的图片,在项目drawable资源下添加文件名为drop_down_list_arrow.png的图片即可
定义相关文字,strings.xml中定义下面属性:
1 2 3 4 5 6 7 |
<string name="drop_down_list_header_default_text">点击可以刷新</string> <string name="drop_down_list_header_pull_text">下拉可以刷新</string> <string name="drop_down_list_header_release_text">松开可以刷新</string> <string name="drop_down_list_header_loading_text">加载中…</string> <string name="drop_down_list_footer_default_text">更多</string> <string name="drop_down_list_footer_loading_text">加载中…</string> <string name="drop_down_list_footer_no_more_text">没有更多了</string> |
定义相关字体颜色,colors.mxl中定义下面属性:
1 2 3 4 5 6 |
<!-- drop down list header font color --> <color name="drop_down_list_header_font_color">#000000</color> <!-- drop down list header second font color --> <color name="drop_down_list_header_second_font_color">#000000</color> <!-- drop down list footer font color --> <color name="drop_down_list_footer_font_color">#000000</color> |
定义相关样式(会覆盖前面的string和color定义),styles.xml中定义下面属性:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
<style name="drop_down_list_header_progress_bar_style"> <item name="android:minHeight">@dimen/drop_down_list_header_progress_bar_height</item> <item name="android:maxHeight">@dimen/drop_down_list_header_progress_bar_height</item> </style> <style name="drop_down_list_footer_progress_bar_style"> <item name="android:minHeight">@dimen/drop_down_list_footer_progress_bar_height</item> <item name="android:maxHeight">@dimen/drop_down_list_footer_progress_bar_height</item> </style> <style name="drop_down_list_header_font_style"> <item name="android:textColor">@color/drop_down_list_header_font_color</item> <item name="android:textAppearance">?android:attr/textAppearanceMedium</item> </style> <style name="drop_down_list_header_second_font_style"> <item name="android:textColor">@color/drop_down_list_header_second_font_color</item> <item name="android:textAppearance">?android:attr/textAppearanceSmall</item> </style> <style name="drop_down_list_footer_font_style"> <item name="android:textColor">@color/drop_down_list_footer_font_color</item> <item name="android:textAppearance">?android:attr/textAppearanceMedium</item> </style> |
定义相关dimen值,dimens.xml中定义下面属性:
1 2 3 4 |
<dimen name="drop_down_list_header_padding_top">12dp</dimen> <dimen name="drop_down_list_header_padding_bottom">15dp</dimen> <dimen name="drop_down_list_header_progress_bar_height">36dp</dimen> <dimen name="drop_down_list_footer_progress_bar_height">36dp</dimen> |
您好 请问我在一次刷新之后,内容已经填满了一个屏幕 为何头部还是显示点击刷新,必须滑动屏幕后才能变成下拉刷新
在事件结束时手动调用onDropDownComplete恢复状态(注意需要在adapter.notifyDataSetChanged();后面调用)
mAdapter.notifyDataSetChanged();listView.onDropDownComplete();是这么写的,但是依然还是有这个问题,请问还有其他可能么?
Demo Apk跑起来有这个问题吗
demo倒是没问题,不过我跟demo有点不一样,在oncreate的时候我本身listItems没有值,手动调用了onDropDown去刷新,刷新之后的东西超过了一个页面,但是还是有点击刷新,但只要一滑动就没了
我在demo里面初始清空数据,手动调用onDropDown加载完后超过一屏是正常的。你可以把demo里面改成 private String[] mStrings = { };onCreate函数最后调用listView.onDropDown();onPostExecute函数中if (isDropDown) 里面的listItems.addFirst(“Added after drop down”);这句复制十几遍测试一下
请教楼主一个问题,如果服务器端的数据已经加载完了。怎么样在底部显示“没有更多数据”?
setHasMore(false)后现在不会在底部显示没有更多数据了,而是直接无法上拉更多,符合现在主流app的习惯
嘿嘿,多谢楼主。我就奇怪,为什么我setHasMore(flase)以后底部没有显示“没有更多数据”,原来是这样啊。。。如果我要实现这样的效果,需要怎么修改源码呢?恳请楼主大大告知,感激不尽。。。
改一行代码就可以了,https://github.com/Trinea/android-common/commit/018fd8125793e1b95ff80dbc37c91602de9d7caa#diff-16aaeba859ba8fbcd216828762d1a767R549 这里面加的那行代码删除掉我想加个setShowFooterWhenNoMore(boolean isShowFooterWhenNoMore),兼容两种情况,只是没啥时间,如果你有兴趣可以添加提交下^_^
gtihub上还没有修改别人的代码过,不知道怎么弄。。。我试试
应该是commit,再push就可以了
public void setShowFooterWhenNoMore(boolean isShowFooterWhenNoMore){ if (isOnBottomStyle) { if (isShowFooterProgressBar) { footerProgressBar.setVisibility(View.GONE); } footerButton.setEnabled(true); if (!hasMore) { footerButton.setText(footerNoMoreText); } else { footerButton.setText(footerDefaultText); } isOnBottomLoading = false; } }我按照楼主说的,只把removeFooterView(footerLayout);删掉。不知道怎么兼容两种情况哎。。。
没事,这周我会和其他几个功能一起提交
https://github.com/Trinea/android-common/commit/7547b14fb99444e1f38ae7e165756410ef9fe964 setShowFooterWhenNoMore已添加
哈哈,楼主大大辛苦。。。最近又遇到了一个问题:选中listview中的某一项之后进入另一个activity中,然后后退的时候,如何恢复到原来选中的那个listview项。我在网上搜了半天,又看到楼主的文章,前来学习了。
你肯定是加了其他什么东西导致这个问题了,一般情况下back返回就是ListView之前的样子
额,不好意思,我的意思应该没表达清楚。恢复到之前选中的那个listview,我参考了,楼主大大的文章和网上的一篇博客,已经解决了。。。
懂了,阿里嘎多。。。楼主大大。
感谢,有一个问题,为何demo里第一行显示的是数据,而我这进入列表后第一行显示的是点击可以刷新?
如果你的数据不足一屏的话是会显示点击刷新的
感谢回复,的确是这样,我看看能不能把它默认隐藏起来
不行的,需要的话换这个吧 https://github.com/chrisbanes/Android-PullToRefresh
目前的项目用的就是这个,不过这个不符合国内的习惯,国内习惯拉倒最底自动加载更多,同时显示“加载中”。有空我自己封装一个好了:-)
这篇文章介绍的就可以,但因为用的是ListView的Header所以没法在数据较少的时候隐藏,底部加载更多没问题的,原理一样
谢谢,实现了。
怎么弄的,可以指导下不。。
http://blog.csdn.net/way_ping_li/article/details/7956498
下啦刷新很卡..
2,3?
老大,发现一个小问题。ListItem的position位置是从1开始的,不是很方便。有空的时候能否修正一下?
这个利用了listView的header设计的,header本身是0,没法改的
导入lib后 运行 上下拉报错哦 Caused by: android.view.InflateException: Binary XML file line #7: Error inflating class cn.trinea.android.common.view.DropDownListView
你怎么导入的,要作为公共库导入,而不能做为jar导入
使用下拉刷新的时候,开始拉的时候,第一行会自动跳上去一些。在往下拉,又跳下来了。会出现一个跳动的过程。(编译源码的。)使用楼主提供的apk demo又没有这个问题。能解答下吗?
可能跟demo manifest里面有关
SDK 版本?# Project target.target=android-16编译时使用的Android SDK 版本 4.1.2
mainfest 添加 uses-sdk android:minSdkVersion=”14″
这行是有的。minVersion也为14,源代码未做任何修改。我把编译的版本微博私信给你了。
安装不了
您安装的机器Android版本号是多少?我测试的是4.1.1。会不会是编译的SDK版本的问题。
使用上拉加载更多的功能,一次加载10条数据,发现每次更新list view都会闪烁一下,体验不好,请问下是什么问题呢?
现在的做法是在setOnBottomListener里面更新数据,并调用adapter的notifyDataSetChanged,是不是调用有问题?
onDropDownComplete需要在adapter.notifyDataSetChanged();后面调用
现在onDropDownComplete就是在adapter.notifyDataSetChanged();后面调用的,加载更多的时候还是会闪烁。
系统版本号多少,什么手机
android 4.0.4 小米1
我待会儿试试
我想问下楼主大人,下拉刷新,松开动画要怎么实现呢! 当下拉松开后,headView 不要马上消失,而是慢慢的弹回去,这中效果,如何实现了,求思路.
不断改变padding,可以看示例demo
demo 没有做动画效果,下拉松开后 headView 马上就消失了,而不是一个回弹效果
你可以在onDropDown中添加动画效果,类似adjustHeaderPadding的处理
下拉还是很卡,楼主修复了么
暂时还没有,你是2.3的环境?
是