前言:
看过许多下拉刷新的例子,好多大牛们的代码写的很完美,让人羡慕嫉妒恨~~~,可是,对于下拉刷新时的手势操作却没有给出详细的解释,当一堆堆逻辑代码出来的时候,对于我们这些菜鸟来说,理解起来真是让人脑子都大了。为了解放大脑(懒得自己进行全面分析),一步一步详解下拉操作,妈妈再也不用担心ListView 下拉刷新是什么鬼啦!~~
先上效果图:~~
上拉加载数据: 下拉刷新:下拉距离短不刷新数据 下拉刷新数据:
思路详解:
自定义的带有下拉刷新和上拉加载的ListView开始时,跟系统的ListView一样。不过多了个header和footer只不过这两个布局以不同的方式隐藏起来了而已。(header是在手机屏幕外的上面,footer是直接隐藏起来了。因为下拉和上拉加载不同,下拉加载有手势判断,要出现动画效果,根据下拉的各种手势,来设置具体的操作。如果直接跟footer一样首先默认header的View.setVisibility(GONE),当有下拉手势时再设置View.setVisibility(View.VISIBLE)就会没有良好的动画效果。)如下图所示。
PS:破电脑只有自带的Window画图工具。凑合看吧
先将代码拆分~ 上拉加载跟下拉刷新分开来讲,后面会有完整的代码。~~~
上拉加载数据:
由于这个比下拉刷新简单。先理解这个。上拉加载适用于需要加载的数据量很大时,如果一下子加载完。会使ListView出现卡顿。这时候,如果利用上拉加载。先加载一部分数据。当上拉时,再加载其他的一部分数据。这样就会有很好的用户体验。
footer布局文件
<?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:layout_centerInParent="true"
android:orientation="vertical">
<LinearLayout
android:id="@+id/ll_footer"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<ProgressBar
android:id="@+id/footer_pb"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
style="?android:attr/progressBarStyleSmall"
android:layout_gravity="center"
/>
<TextView
android:id="@+id/footer_tv"
android:text="footer正在加载。。"
android:textSize="16sp"
android:gravity="center"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
</LinearLayout>
接下来看上拉加载逻辑:上拉加载我们利用的是AbsListView.OnScrollListener这个接口。 它有两个方法需要重写:
1.publicvoid onScroll(AbsListView view,int firstVisibleItem,int visibleItemCount,int totalItemCount) {};
2.publicvoid onScrollStateChanged(AbsListView view,int scrollState) {};
借鉴别的地方的对这两个方法的详细解释。他讲解的很详细啦:
new OnScrollListener() {
boolean isLastRow = false;
@Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
//滚动时一直回调,直到停止滚动时才停止回调。单击时回调一次。
//firstVisibleItem:当前能看见的第一个列表项ID(从0开始)
//visibleItemCount:当前能看见的列表项个数(小半个也算)
//totalItemCount:列表项共数
//判断是否滚到最后一行
if (firstVisibleItem + visibleItemCount == totalItemCount && totalItemCount > 0) {
isLastRow = true;
}
}
@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
//正在滚动时回调,回调2-3次,手指没抛则回调2次。scrollState = 2的这次不回调
//回调顺序如下
//第1次:scrollState = SCROLL_STATE_TOUCH_SCROLL(1) 正在滚动
//第2次:scrollState = SCROLL_STATE_FLING(2) 手指做了抛的动作(手指离开屏幕前,用力滑了一下)
//第3次:scrollState = SCROLL_STATE_IDLE(0) 停止滚动
//当屏幕停止滚动时为0;当屏幕滚动且用户使用的触碰或手指还在屏幕上时为1;
//由于用户的操作,屏幕产生惯性滑动时为2
//当滚到最后一行且停止滚动时,执行加载
if (isLastRow && scrollState == AbsListView.OnScrollListener.SCROLL_STATE_IDLE) {
//加载元素
......
isLastRow = false;
}
}
}
好了,了解了OnScrollListener的这两个方法具体是干什么的,接下来看我们怎么实现~~~:
上拉加载的关键就在这个接口中实现:
首先是LoadListView中的定义的变量:
private int lastVisibleItem; //最后一个可见项
private int totalItems; //总的item
private View footer; //底部View+头部View;
private boolean isLoading = false;//是否正在加载
private ILoadListener iListener;//自定义的一个加载接口。暴露给MainActivity让它实现具体加载操作。可以根据需求不同而改写。
加载布局文件以及设置监听:
private void initViews(Context context) {
//获得footer+header布局文件
LayoutInflater inflater =LayoutInflater.from(context);
footer = inflater.inflate(R.layout.footer,null);
footer.findViewById(R.id.ll_footer).setVisibility(GONE);//初始化时设置footer不可见
this.addFooterView(footer);
this.setOnScrollListener(this);//设置滚动监听
}
重写OnScrollListener的这两个方法:
@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
if(lastVisibleItem==tota