下拉加载更多在我们平常使用的APP中经常会见到,比如我们刷微博时下拉加载更多的新闻,空间动态下拉加载更多的消息等。Android是没有给我们提供这样的控件的,那今天我们就动手简单的实现一下这个功能。
在这里我们重写ListView,利用 线程池+OnScrollListener+接口回调 配合来实现。
简单说一下实现的逻辑:我们都知道ListView提供给我们一个方法addFooterView,我们就利用这个方法给我们的ListView添加脚布局,并通过setPadding方法控制脚布局的显示与隐藏,然后添加接口回调用于显示更多数据的加载,在回调方法外部包装一层线程池来控制数据加载的有序性,也许你会有个迷惑,我们什么时候开始加载数据呢,别忘了我们还用到了OnScrollListener接口呢,我们就在OnScrollListener接口的onScrollStateChanged方法中来判断ListView是否滑动到了底部。好,接下来我们看代码。
public classXvListViewextendsListViewimplementsAbsListView.OnScrollListener{
private intHIDE_HEIGHT;//脚布局的高
private intmCount;//每次加载的个数
privateContextmContext;
privateViewmView;//脚布局
privateHandlerUploadmHandlerUpload;//回调接口
privateExecutorServicemEcecutorService;//线程池
privateBaseAdapteradapter;
/**
* 得到主线程的looper
*/
privateHandlermHandler=newHandler(Looper.getMainLooper()){
@Override
public voidhandleMessage(Message msg) {
super.handleMessage(msg);
switch(msg.what){
case0:
Toast.makeText(mContext,"没有更多内容了",Toast.LENGTH_SHORT).show();
break;
case1:
showFooterView(false);
adapter.notifyDataSetChanged();
break;
}
}
};
publicXvListView(Context context,AttributeSet attrs) {
super(context,attrs);
mContext= context;
init();
setOnScrollListener(this);
}
/**
* 线程池以及脚布局的初始化
*/
private voidinit() {
mEcecutorService= Executors.newFixedThreadPool(1);
mView= LayoutInflater.from(mContext).inflate(R.layout.pull_to_refresh,null);
HIDE_HEIGHT=mView.getMeasuredHeight();
mView.setPadding(0,-HIDE_HEIGHT,0,0);
this.addFooterView(mView);
}
/**
* 这里实现OnScrollListener接口的onScrollStateChanged方法
*/
@Override
public voidonScrollStateChanged(AbsListView absListView, inti) {
if((getAdapter().getCount()-1== getLastVisiblePosition()) &&
((i == OnScrollListener.SCROLL_STATE_IDLE) || (i == OnScrollListener.SCROLL_STATE_FLING))){
executeUpload();
}
}
/**
* 控制脚布局的显示与隐藏
*/
private voidshowFooterView(booleanisboolean){
if(isboolean){
mView.setPadding(0,0,0,0);
}else{
mView.setPadding(0,-HIDE_HEIGHT,0,0);
}
}
/**
* 利用线程池来控制有序加载
*/
private voidexecuteUpload(){
showFooterView(true);
if(mHandlerUpload!=null){
mEcecutorService.execute(newRunnable() {
@Override
public voidrun() {
mCount=mHandlerUpload.upload();
if(mCount==0) {
mHandler.sendEmptyMessage(0);
}
mHandler.sendEmptyMessage(1);
}
});
}
}
public voidsetHandlerUpload(HandlerUpload mHandlerUpload,BaseAdapter adapter){
this.mHandlerUpload= mHandlerUpload;
this.adapter= adapter;
}
@Override
public voidonScroll(AbsListView absListView, inti, inti1, inti2) {
}
/**
* 利用接口回调加载数据
*/
public interfaceHandlerUpload{
intupload();
}
}
代码都有注释,很简单。
XML布局
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity" > <com.example.xvhuichuang.lianxi.com.lianxi.UI.XvListView android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/pullup"></com.example.xvhuichuang.lianxi.com.lianxi.UI.XvListView>
</RelativeLayout>
最后在Activity设置适配器并实现下拉加载功能
public class Main extends AppCompatActivity{
private MyAdapter myAdapter;
private List<String> lists;
private int i = 0, j = 0 ;
XvListView pullUpLoadMoreListView ;
@Override
protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState);
setContentView(R.layout.main2);
lists = new ArrayList<>();
for (;i<15;i++){
lists.add(i+"");
}
pullUpLoadMoreListView = (XvListView) findViewById(R.id.pullup);
myAdapter = new MyAdapter();
pullUpLoadMoreListView.setHandlerUpload(new XvListView.HandlerUpload() { @Override
public int upload() {
j = i+15;
for (;i<j;i++){
lists.add(""+i);
}
return 15;
}
},myAdapter);
pullUpLoadMoreListView.setAdapter(myAdapter);
}
class MyAdapter extends BaseAdapter{
@Override
public int getCount() {
return lists.size();
}
@Override
public Object getItem(int i) {
return lists.get(i);
}
@Override
public long getItemId(int i) {
return i;
}
@Override
public View getView(int i, View view, ViewGroup viewGroup) {
View view1 = LayoutInflater.from(Main.this).inflate(R.layout.qq,null);
TextView textView = (TextView) view1.findViewById(R.id.text); textView.setText(lists.get(i));
return view1;
}
}
}
当然这里我没有对适配器的getView进行性能优化,在实际的运用中务必对其进行优化!