最近項(xiàng)目中由于統(tǒng)一使用SwipeRefreshLayout的下拉刷新,由于谷歌官方的SwipeRefreshLayout并沒(méi)有提供上拉加載更多的功能需频,只好自己寫(xiě)一個(gè)暗甥,記一下以后可以直接拿出來(lái)用。
其實(shí)實(shí)現(xiàn)原理很中規(guī)中矩皂甘,無(wú)非就是給ListView添加一個(gè)腳布局(用于顯示正在加載更多的提示)斧散,首先是隱藏的(設(shè)置一個(gè)負(fù)值padding供常,剛好為腳布局高度的相反數(shù)),當(dāng)監(jiān)聽(tīng)到用戶(hù)滑倒最底端(當(dāng)前可見(jiàn)的最后一個(gè)item是當(dāng)前列表的最后一項(xiàng)再繼續(xù)上拉的動(dòng)作時(shí)顯示腳布局鸡捐,加載完成后再隱藏它栈暇,這里為了避免加載多次,我們需要記錄用戶(hù)上拉時(shí)是否正在加載箍镜,只有當(dāng)同時(shí)滿(mǎn)足:①?zèng)]有正在加載源祈;②當(dāng)前已經(jīng)到了最低端;③用戶(hù)正在上拉操作時(shí)才加載更多色迂。
這里我覺(jué)得重寫(xiě)onTouchEvent判斷用戶(hù)上拉還是下拉比較麻煩香缺,就直接監(jiān)聽(tīng)滑動(dòng)狀態(tài),如果當(dāng)前最后一個(gè)可見(jiàn)的item是列表最后一項(xiàng),當(dāng)滑動(dòng)狀態(tài)處于SCROLL_STATE_FLING(開(kāi)始滾動(dòng))或者SCROLL_STATE_IDLE(處于空閑歇僧,已經(jīng)停止)時(shí)图张,如果滑動(dòng)狀態(tài)再發(fā)生改變只能是變?yōu)镾CROLL_STATE_TOUCH_SCROLL(滾動(dòng)狀態(tài))锋拖,由于最后一個(gè)可見(jiàn)的item必須是最后一個(gè),所以綜上可知只能變?yōu)橄蛏侠?向下拉最后一個(gè)可見(jiàn)的就不是列表的最后一項(xiàng)了)祸轮,下面是實(shí)現(xiàn)的代碼
package com.meskal.customview;
import android.content.Context;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.widget.AbsListView;
import android.widget.ListView;
import com.meskal.R;
public class PullUpLoadMoreListView extends ListView implements AbsListView.OnScrollListener {
private boolean isLoading = false;
private View mFooterView;
private int mFooterHeight;
private OnLoadMoreListener mListener;
private LayoutInflater inflater;
public PullUpLoadMoreListView(Context context) {
this(context, null);
}
public PullUpLoadMoreListView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public PullUpLoadMoreListView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
inflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
initFooterView();
setOnScrollListener(this);
}
/**
* 初始化腳布局
*/
private void initFooterView() {
mFooterView = inflater.inflate(R.layout.refresh_load_more, null);
mFooterView.measure(0, 0);
mFooterHeight = mFooterView.getMeasuredHeight();
mFooterView.setPadding(0, -mFooterHeight, 0, 0);
this.addFooterView(mFooterView);
}
@Override public void onScrollStateChanged(AbsListView absListView, int scrollstate) {
if(this.getLastVisiblePosition() == this.getAdapter().getCount() - 1
&& !isLoading && (scrollstate == SCROLL_STATE_FLING || scrollstate == SCROLL_STATE_IDLE)){
setLoadState(true);
if(this.mListener != null){
this.mListener.loadMore();
}
}
}
/**
* 設(shè)置狀態(tài)
* @param b
*/
public void setLoadState(boolean b) {
this.isLoading = b;
if(isLoading){
mFooterView.setPadding(0,0,0,0);
this.setSelection(this.getAdapter().getCount() + 1);
}else {
mFooterView.setPadding(0,-mFooterHeight,0,0);
}
}
@Override public void onScroll(AbsListView absListView, int i, int i1, int i2) {
}
public void setOnLoadMoreListener(OnLoadMoreListener listener){
this.mListener = listener;
}
public interface OnLoadMoreListener{
void loadMore();
}
}
腳布局就很簡(jiǎn)單了兽埃,當(dāng)然也可以更具需要定制更絢麗的進(jìn)度提醒:
<?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="wrap_content"
android:background="@drawable/block_bg"
android:orientation="horizontal">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="50dp"
android:orientation="horizontal"
android:gravity="center"
>
<ProgressBar
android:id="@+id/progressBar"
style="@android:style/Widget.Holo.ProgressBar.Small"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginRight="5dp"
/>
<TextView
android:layout_width="wrap_content"
android:layout_marginLeft="5dp"
android:layout_height="wrap_content"
android:gravity="center"
android:textSize="18sp"
android:textColor="#FF333333"
android:text="正在加載更多數(shù)據(jù)..."
/>
</LinearLayout>
</LinearLayout>
這里腳布局加了一個(gè)邊框(drawable下添加一個(gè)block_bg.xml):
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="#fff"/>
<stroke
android:color="#d4d4d4"
android:width="1px"/>
</shape>
對(duì)外我們對(duì)外公開(kāi)一個(gè)設(shè)置監(jiān)聽(tīng)器和設(shè)置加載狀態(tài)的方法,監(jiān)聽(tīng)器接口在使用時(shí)實(shí)現(xiàn)這個(gè)接口去做加載更多的操作适袜,設(shè)置正在加載中由控件本身負(fù)責(zé)柄错,這個(gè)時(shí)候我們讓腳布局顯示出來(lái),加載完成我們?cè)O(shè)置正在加載中(isLoading )為false就會(huì)隱藏腳布局苦酱,這里對(duì)于腳布局我們需要注意的時(shí)獲取高度之前要先主動(dòng)的去測(cè)量一下( mFooterView.measure(0, 0);)售貌,因?yàn)樵趘iew繪制中只有當(dāng)view執(zhí)行過(guò)onMeasure后才能得到具體寬高,否則得到的始終為0疫萤。
到這里颂跨,這個(gè)控件差不多寫(xiě)完了,其實(shí)配合SwipeRefreshLayout效果還不錯(cuò)给僵。當(dāng)然下拉刷新上拉加載的類(lèi)庫(kù)也有很多毫捣,像有名的PullToRefresh详拙,功能十分強(qiáng)大帝际,使用也很方便。還有記得之前使用過(guò)一個(gè)MaterialRefreshLayout饶辙,這個(gè)是比SwipeRefreshLayout更強(qiáng)大的刷新控件蹲诀,支持上拉加載更多,上拉和下拉顯示的都是轉(zhuǎn)圈的動(dòng)畫(huà)弃揽,上拉在底部顯示脯爪,而且支持動(dòng)畫(huà)顯示是否是侵入式的覆蓋在內(nèi)容上方