上拉刷新下拉加载相信是在日常的开发中使用的最频繁的一个组件了,大量数据的展示一定会使用到分页的功能以提升用户体验,目前可以看到的市面上的应用的下拉刷新也都是配合的SwipeRefreshLayout来实现的,看起来比较美观,相比自定义的下拉刷新的动画效果,这个就显得比较简洁大方了。
下面看一下运行效果:
由于ListView没有提供默认的分页加载的功能,因此这里就需要我们自定了,实现起来也是比较简单的,大致的思路就是:给ListView添加一个FootView用来显示正在加载的等待动画,以及滑动到listview最底部的Item的监听,然后通过回调将事件的处理交给外部进行。
LoadListView.Java
/** * Created by 春水碧于天 on 2017/1/29. */
public class LoadListView extends ListView implements AbsListView.OnScrollListener {
private int mFootViewHeight;
private View mFootView;
private int LOADSTATE = 0; //加载的状态
public LoadListView(Context context) {
super(context);
InitFootView(context);
setOnScrollListener(this);
}
public LoadListView(Context context, AttributeSet attrs) {
super(context, attrs);
//初始化脚布局并添加到当前的ListView
InitFootView(context);
setOnScrollListener(this);
}
public LoadListView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
private void InitFootView(Context context) {
mFootView = View.inflate(context, R.layout.foot_load_item, null);
mFootView.measure(0, 0); //测量
mFootViewHeight = mFootView.getMeasuredWidth();
addFooterView(mFootView);
}
//加载完成调用隐藏脚布局,并把mLoadState的状态设置为0,表示未刷新状态
public void setLoadComplete() {
LOADSTATE = 0;
//加载完成后隐藏脚布局
mFootView.setPadding(0, -mFootViewHeight, 0, 0);
}
//滑动状态改变的监听
@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
}
/** * 滑动时一直调用 * @param view * @param firstVisibleItem 当前能看见的第一条item的Id * @param visibleItemCount 当前能看见的item的总数 * @param totalItemCount 所有的item */
@Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
Log.i("wk","firstVisibleItem: "+firstVisibleItem+"visibleItemCount: "+visibleItemCount+"totalItemCount: "+totalItemCount);
//判断是否滑动到当前listview的最后一个条目
if (firstVisibleItem + visibleItemCount == totalItemCount && totalItemCount > 0) {
if (LOADSTATE == 0) {
//取消隐藏
mFootView.setPadding(0, 0, 0, 0);
onLoadListener.onLoading();
LOADSTATE = 1; //设置状态为加载中,放置多次调用onLoading
}
}
}
//加载更多的回调接口
private OnLoadListener onLoadListener;
public void setOnLoadlistener(OnLoadListener onLoadListener) {
this.OnLoadListener= onLoadListener;
}
public interface OnLoadListener {
void onLoading();
}
}
这里记录一下OnScrollListener中的两个回调方法的作用:
1.onScrollStateChanged
//滑动状态改变的监听
@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
switch (scrollState) {
//根据手指离开后的惯性滑动时调用
case OnScrollListener.SCROLL_STATE_FLING:
Log.i("wk","惯性滑动");
break;
//滚动停止时调用
case OnScrollListener.SCROLL_STATE_IDLE:
Log.i("wk","滚动停止");
break;
//正在滚动时调用
case OnScrollListener.SCROLL_STATE_TOUCH_SCROLL:
Log.i("wk","正在滚动");
break;
}
}
这个方法根据第二个参数 scrollState 来决定回调的次数
2.onScroll
/** * 滑动时一直调用 * * @param view * @param firstVisibleItem 当前能看见的第一条item的Id * @param visibleItemCount 当前能看见的item的总数 * @param totalItemCount 所有的item */
@Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
}
它在ListView滑动时一直调用,通过onScroll中的三个参数,非常精确的描述了ListView的当前状态
firstVisibleItem 当前能看见的第一条item的Position
visibleItemCount 当前能看见的item的总数(包括没有完全显示的条目)
totalItemCount 所有的item
判断显示到了最后一行:
if (firstVisibleItem + visibleItemCount == totalItemCount && totalItemCount > 0) { }
判断ListView滑动的方向:
private int lastVisibleItem = 0;
@Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
Log.i("wk","lastVisibleItem=> "+lastVisibleItem+"firstVisibleItem=> "+firstVisibleItem);
if(lastVisibleItem>firstVisibleItem){
Log.i("wk","下滑");
}else if (lastVisibleItem"wk","上滑");
}
lastVisibleItem = firstVisibleItem;
foot_load_item.Java
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" android:gravity="center_horizontal" android:orientation="horizontal">
<ProgressBar android:layout_margin="10dp" android:layout_width="50dp" android:layout_height="50dp" />
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="正在加载中……" android:layout_margin="10dp" android:textSize="20dp" android:layout_gravity="center" />
LinearLayout>
这样一个支持上拉加载更多的ListView就实现了。
下面通过配合SwipeRefreshLayout来实现下拉刷新:
activity_main.xml
"1.0" encoding="utf-8"?>
"http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/activity_main"
android:layout_hljs-string">"match_parent"
android:layout_hljs-string">"match_parent"
android:orientation="vertical"
tools:cOntext="com.example.studyslide.MainActivity">
.support.v4.widget.SwipeRefreshLayout
android:id="@+id/swipeRefreshLayout"
android:layout_hljs-string">"match_parent"
android:layout_hljs-string">"match_parent">
<com.example.studyslide.LoadListView
android:id="@+id/listView"
android:layout_hljs-string">"match_parent"
android:layout_hljs-string">"match_parent">
com.example.studyslide.LoadListView>
.support.v4.widget.SwipeRefreshLayout>
MainActivity.Java
public class MainActivity extends AppCompatActivity implements SwipeRefreshLayout.OnRefreshListener {
private LoadListView mListView;
private ArrayList mDatas;
private SwipeRefreshLayout swipeRefreshLayout;
private Handler mHandler;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
InitData();
InitUI();
//设置加载显示的颜色,可以设置显示多种颜色
swipeRefreshLayout.setColorSchemeColors(Color.BLUE, Color.RED, Color.GREEN, Color.GRAY);
//设置swipeRefreshLayout的背景颜色
//swipeRefreshLayout.setBackgroundColor(Color.CYAN);
//设置显示的大小
swipeRefreshLayout.setSize(SwipeRefreshLayout.LARGE);
/* //设置手指下拉多少出现刷新 swipeRefreshLayout.setDistanceToTriggerSync(200); //设置刷新出现的位置 swipeRefreshLayout.setProgressViewEndTarget(false,200);*/
//设置刷新的监听
swipeRefreshLayout.setOnRefreshListener(this);
final myAdapter myAdapter = new myAdapter();
/** * 模拟网络数据加载 */
mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
int tag = msg.what;
switch (tag) {
//刷新
case 0:
for (int i = 0; i <10; i++) {
mDatas.add(0, "刷新出的数据" + i);
}
swipeRefreshLayout.setRefreshing(false);
myAdapter.notifyDataSetChanged();
break;
//加载更多
case 1:
for (int i = 0; i <10; i++) {
mDatas.add("加载出的数据" + i);
}
mListView.setLoadComplete();
myAdapter.notifyDataSetChanged();
break;
}
}
};
mListView.setAdapter(myAdapter);
mListView.setOnLoadlistener(new LoadListView.OnLoadListener() {
@Override
public void onLoading() {
Toast.makeText(MainActivity.this, "加载更多", Toast.LENGTH_SHORT).show();
//模拟网络加载数据延迟
new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(2000);
mHandler.sendEmptyMessage(1);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
}
}
}).start();
}
});
}
private void InitUI() {
mListView = (LoadListView) findViewById(R.id.listView);
swipeRefreshLayout = (SwipeRefreshLayout) findViewById(R.id.swipeRefreshLayout);
}
private void InitData() {
mDatas = new ArrayList();
for (int i = 0; i <40; i++) {
mDatas.add("这是" + i + "条数据");
}
}
@Override
public void onRefresh() {
new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(2000);
mHandler.sendEmptyMessage(0);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
}
}
}).start();
}
//ListView的适配器
class myAdapter extends BaseAdapter {
@Override
public int getCount() {
return mDatas.size();
}
@Override
public Object getItem(int position) {
return position;
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder viewHolder = null;
if (cOnvertView== null) {
viewHolder = new ViewHolder();
cOnvertView= View.inflate(MainActivity.this, R.layout.item_listview, null);
viewHolder.tv = (TextView) convertView.findViewById(R.id.textView);
convertView.setTag(viewHolder);
} else {
viewHolder = (ViewHolder) convertView.getTag();
}
viewHolder.tv.setText(mDatas.get(position));
return convertView;
}
final class ViewHolder {
public TextView tv;
}
}
}
常用的方法:
setOnRefreshListener(this):添加一个刷新的监听
setRefreshing(): 显示或隐藏刷新进度条
isRefreshing(): 检查当前是否处于刷新状态
setColorScheme(): 设置进度条的颜色主题,最多能设置四种
swipeRefreshLayout.setBackgroundColor():设置SwipeRefreshLayout 的背景色
swipeRefreshLayout.setSize(SwipeRefreshLayout.LARGE):设置刷新控件显示大小,默认为small
swipeRefreshLayout.setDistanceToTriggerSync(200):设置手指下拉多少出现刷新
swipeRefreshLayout.setProgressViewEndTarget(false,200):设置刷新出现的位置
这样一个可以上拉加载下拉刷新的ListView就完成了,呵呵,比较朴素的效果实现。