Android中Listview下拉刷新和上拉加載更多的多種實(shí)現(xiàn)方案
listview經(jīng)常結(jié)合下來(lái)刷新和上拉加載更多使用,本文總結(jié)了三種常用到的方案分別作出說(shuō)明。
方案一:添加頭布局和腳布局
android系統(tǒng)為listview提供了addfootview和addheadview兩個(gè)API。這樣可以直接自定義一個(gè)View,以添加視圖的形式實(shí)現(xiàn)下來(lái)刷新和上拉加載。
實(shí)現(xiàn)步驟
1、創(chuàng)建一個(gè)類繼承ListView:class PullToRefreshListView extends ListView;
2、在構(gòu)造方法中添加HeadView:addHeaderView(headView);
3、獲取HeadView的高。測(cè)量控件的高可以有兩方法getMeasuredHeight和getHeight,getMeasuredHeight()在onMeasure方法執(zhí)行之后才能獲取到;getHeight() 在onLayout方法執(zhí)行之后才能獲取到值;
4、顯示和隱藏headView,通過(guò)setpadding實(shí)現(xiàn),當(dāng)向下滑,且第一條可見(jiàn)item是第0條的時(shí)候才需要設(shè)置HeadView的paddingTop來(lái)顯示HeadView。
顯示:headView.setPadding(0,0,0,0);
隱藏:headView.setPadding(0,-headViewHeight,0,0);
5、下拉刷新三種狀態(tài)的判斷,移動(dòng)的時(shí)候,當(dāng)paddingTop < 0 的時(shí)候,說(shuō)明HeadView沒(méi)有完全顯示出來(lái),進(jìn)入下拉刷新?tīng)顟B(tài);移動(dòng)的時(shí)候,當(dāng)paddingTop >= 0 的時(shí)候, 說(shuō)明HeadView已經(jīng)完全顯示出來(lái)了,進(jìn)入松開(kāi)以新?tīng)顟B(tài);手指抬起的時(shí)候,且當(dāng)前狀態(tài)是松開(kāi)刷新?tīng)顟B(tài)的時(shí)候,進(jìn)入正在刷新?tīng)顟B(tài); 當(dāng)已經(jīng)是“正在刷新”狀態(tài)時(shí), 則不允許再做”下拉刷新”和”松開(kāi)刷新”的操作了,在Move事件中加入判斷,如果已經(jīng)是正在刷新?tīng)顟B(tài)了,則不處理下拉的操作了。
6、下拉箭頭的轉(zhuǎn)動(dòng)。下拉刷新是向下,松開(kāi)刷新時(shí)向上。旋轉(zhuǎn)動(dòng)畫(huà)通過(guò)屬性動(dòng)畫(huà)實(shí)現(xiàn)。隱藏箭頭的時(shí)候要清除動(dòng)畫(huà):iv_arrow.clearAnimation(); 如果不隱藏動(dòng)畫(huà)效果,設(shè)置View.GONE之后還是看得見(jiàn)的。
7、HeadView顯示時(shí),當(dāng)手指松開(kāi)時(shí)的處理,松開(kāi)時(shí)如果是“正在刷新”狀態(tài),則把headVie完全顯示;松開(kāi)時(shí)如果是“下拉刷新”狀態(tài),則把HeadView完全隱藏
8、增加FooterView:addFooterView(footerView)。當(dāng)ListView處于空閑狀態(tài),并且最后一條可見(jiàn)item是ListView中的最后一條數(shù)據(jù)時(shí)顯示footview, footerView顯示出來(lái)后,ListView不會(huì)自動(dòng)上滑把FooterView顯示出來(lái)的,所以需要手動(dòng)設(shè)置:setSelection(getCount() - 1);即選中最后一條。
9、增加回調(diào)監(jiān)聽(tīng)器。當(dāng)ListView處于刷新?tīng)顟B(tài)的時(shí)候會(huì)調(diào)用onRefreshing()方法;當(dāng)ListView處于加載更多的時(shí)候會(huì)調(diào)用onLoadMore()。加載完成后通知控件加載完成。
具體實(shí)現(xiàn):
import com.itheima.pulltorefreshlistview.R;
import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.animation.RotateAnimation;
import android.widget.AbsListView;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.ProgressBar;
import android.widget.TextView;
public class PullToRefreshListView extends ListView {
private View headerView;
private float downY;
private int headerViewHeight;
/** 狀態(tài):下拉刷新 */
private static final int STATE_PULL_TO_REFRESH = 0;
/** 狀態(tài):松開(kāi)刷新 */
private static final int STATE_RELEASE_REFRESH = 1;
/** 狀態(tài):正在刷新 */
private static final int STATE_REFRESHING = 2;
/** 當(dāng)前狀態(tài) */
private int currentState = STATE_PULL_TO_REFRESH; // 默認(rèn)是下拉刷新?tīng)顟B(tài)
private ImageView iv_arrow;
private ProgressBar progress_bar;
private TextView tv_state;
private RotateAnimation upAnim;
private RotateAnimation downAnim;
private OnRefreshingListener mOnRefreshingListener;
private View footerView;
private int footerViewHeight;
/** 正在加載更多 */
private boolean loadingMore;
public PullToRefreshListView(Context context, AttributeSet attrs) {
super(context, attrs);
initHeaderView();
initFooterView();
}
private void initHeaderView() {
headerView = View.inflate(getContext(), R.layout.header_view, null);
iv_arrow = (ImageView) headerView.findViewById(R.id.iv_arrow);
progress_bar = (ProgressBar) headerView.findViewById(R.id.progress_bar);
showRefreshingProgressBar(false);
tv_state = (TextView) headerView.findViewById(R.id.tv_state);
headerView.measure(0, 0); // 主動(dòng)觸發(fā)測(cè)量,mesure內(nèi)部會(huì)調(diào)用onMeasure
headerViewHeight = headerView.getMeasuredHeight();
hideHeaderView();
super.addHeaderView(headerView);
upAnim = createRotateAnim(0f, -180f);
downAnim = createRotateAnim(-180f, -360f);
}
private void initFooterView() {
footerView = View.inflate(getContext(), R.layout.footer_view, null);
footerView.measure(0, 0);// 主動(dòng)觸發(fā)測(cè)量,mesure內(nèi)部會(huì)調(diào)用onMeasure
footerViewHeight = footerView.getMeasuredHeight();
hideFooterView();
super.addFooterView(footerView);
super.setOnScrollListener(new OnScrollListener() {
// 當(dāng)ListView滾動(dòng)的狀態(tài)發(fā)生改變的時(shí)候會(huì)調(diào)用這個(gè)方法
@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
if (scrollState == OnScrollListener.SCROLL_STATE_IDLE // ListView處于空閑狀態(tài)
&& getLastVisiblePosition() == getCount() - 1 // 界面上可見(jiàn)的最后一條item是ListView中最后的一條item
&& loadingMore == false // 如果當(dāng)前沒(méi)有去做正在加載更多的事情
) {
loadingMore = true;
showFooterView();
setSelection(getCount() - 1);
if (mOnRefreshingListener != null) {
mOnRefreshingListener.onLoadMore();
}
}
}
// 當(dāng)ListView滾動(dòng)的時(shí)候會(huì)調(diào)用這個(gè)方法
@Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
}
});
}
private void hideFooterView() {
int paddingTop = -footerViewHeight;
setFooterViewPaddingTop(paddingTop);
}
private void showFooterView() {
int paddingTop = 0;
setFooterViewPaddingTop(paddingTop);
}
private void setFooterViewPaddingTop(int paddingTop) {
footerView.setPadding(0, paddingTop, 0, 0);
}
/**
* 設(shè)置顯示進(jìn)度的圈圈
* @param showProgressBar 如果是true,則顯示ProgressBar,否則的話顯示箭頭
*/
private void showRefreshingProgressBar(boolean showProgressBar) {
progress_bar.setVisibility(showProgressBar ? View.VISIBLE : View.GONE);
iv_arrow.setVisibility(!showProgressBar ? View.VISIBLE : View.GONE);
if (showProgressBar) {
iv_arrow.clearAnimation(); // 有動(dòng)畫(huà)的View要清除動(dòng)畫(huà)才能真正的隱藏
}
}
/**
* 創(chuàng)建旋轉(zhuǎn)動(dòng)畫(huà)
* @param fromDegrees 從哪個(gè)角度開(kāi)始轉(zhuǎn)
* @param toDegrees 轉(zhuǎn)到哪個(gè)角度
* @return
*/
private RotateAnimation createRotateAnim(float fromDegrees, float toDegrees) {
int pivotXType = RotateAnimation.RELATIVE_TO_SELF; // 旋轉(zhuǎn)點(diǎn)的參照物
int pivotYType = RotateAnimation.RELATIVE_TO_SELF; // 旋轉(zhuǎn)點(diǎn)的參照物
float pivotXValue = 0.5f; // 旋轉(zhuǎn)點(diǎn)x方向的位置
float pivotYValue = 0.5f; // 旋轉(zhuǎn)點(diǎn)y方向的位置
RotateAnimation ra = new RotateAnimation(fromDegrees, toDegrees, pivotXType, pivotXValue, pivotYType, pivotYValue);
ra.setDuration(300);
ra.setFillAfter(true); // 讓動(dòng)畫(huà)停留在結(jié)束位置
return ra;
}
/** 隱藏HeaderView */
private void hideHeaderView() {
int paddingTop = -headerViewHeight;
setHeaderViewPaddingTop(paddingTop);
}
/** 顯示HeaderView */
private void showHeaderView() {
int paddingTop = 0;
setHeaderViewPaddingTop(paddingTop);
}
/**
* 設(shè)置HeaderView的paddingTop
* @param paddingTop
*/
private void setHeaderViewPaddingTop(int paddingTop) {
headerView.setPadding(0, paddingTop, 0, 0);
}
@Override
public boolean onTouchEvent(MotionEvent ev) {
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
downY = ev.getY();
break;
case MotionEvent.ACTION_MOVE:
if (currentState == STATE_REFRESHING) {
// 如果當(dāng)前已經(jīng)是“正在刷新“的狀態(tài)了,則不用去處理下拉刷新了
return super.onTouchEvent(ev);
}
int fingerMoveDistanceY = (int) (ev.getY() - downY); // 手指移動(dòng)的距離
// 如果是向下滑動(dòng),并且界面上可見(jiàn)的第一條item是ListView的索引為0的item時(shí)我們才處理下拉刷新的操作
if (fingerMoveDistanceY > 0 && getFirstVisiblePosition() == 0) {
int paddingTop = -headerViewHeight + fingerMoveDistanceY;
setHeaderViewPaddingTop(paddingTop);
if (paddingTop < 0 && currentState != STATE_PULL_TO_REFRESH) {
// 如果paddingTop小于0,說(shuō)明HeaderView沒(méi)有完全顯示出來(lái),則進(jìn)入下拉刷新的狀態(tài)
currentState = STATE_PULL_TO_REFRESH;
tv_state.setText("下拉刷新");
iv_arrow.startAnimation(downAnim);
showRefreshingProgressBar(false);
// 讓箭頭轉(zhuǎn)一下
} else if (paddingTop >= 0 && currentState != STATE_RELEASE_REFRESH) {
// 如果paddingTop>=0,說(shuō)明HeaderView已經(jīng)完全顯示出來(lái),則進(jìn)入松開(kāi)刷新的狀態(tài)
currentState = STATE_RELEASE_REFRESH;
tv_state.setText("松開(kāi)刷新");
iv_arrow.startAnimation(upAnim);
showRefreshingProgressBar(false);
}
return true;
}
break;
case MotionEvent.ACTION_UP:
if (currentState == STATE_RELEASE_REFRESH) {
// 如果當(dāng)前狀態(tài)是松開(kāi)刷新,并且抬起了手,則進(jìn)入正在刷新?tīng)顟B(tài)
currentState = STATE_REFRESHING;
tv_state.setText("正在刷新");
showRefreshingProgressBar(true);
showHeaderView();
if (mOnRefreshingListener != null) {
mOnRefreshingListener.onRefreshing();
}
} else if (currentState == STATE_PULL_TO_REFRESH) {
// 如果抬起手時(shí)是下拉刷新?tīng)顟B(tài),則把HeaderView完成隱藏
hideHeaderView();
}
break;
}
return super.onTouchEvent(ev);
}
public void setOnRefreshingListener(OnRefreshingListener mOnRefreshingListener) {
this.mOnRefreshingListener = mOnRefreshingListener;
}
/** ListView刷新的監(jiān)聽(tīng)器 */
public interface OnRefreshingListener {
/** 當(dāng)ListView可以刷新數(shù)據(jù)的時(shí)候會(huì)調(diào)用這個(gè)方法 */
void onRefreshing();
/** 當(dāng)ListView可以加載更多 的時(shí)候會(huì)調(diào)用這個(gè)方法 */
void onLoadMore();
}
/** 聯(lián)網(wǎng)刷新數(shù)據(jù)的操作已經(jīng)完成了 */
public void onRefreshComplete() {
hideHeaderView();
currentState = STATE_PULL_TO_REFRESH;
showRefreshingProgressBar(false);
}
/** 加載更多新數(shù)據(jù)的操作已經(jīng)完成了 */
public void onLoadmoreComplete() {
hideFooterView();
loadingMore = false;
}
}
方案二: listview的多種樣式顯示
設(shè)置listview的適配器的時(shí)候可以實(shí)現(xiàn)兩個(gè)方法: getViewTypeCount()和getItemViewType(),前者指定條目的種類,后者返回具體的類型,這樣可以根據(jù)不同的類型設(shè)計(jì)相關(guān)的樣式,包括上拉加載更多,和下拉刷新,兩者類似,因此這里僅僅給出加載更多的寫法。具體實(shí)現(xiàn)如下:
1、重寫getViewTypeCount()和getItemViewType(),這里包括普通的item條目和加載更多的條目,所以getViewTypeCount()返回值為2;
@Override
public int getViewTypeCount() {
return super.getViewTypeCount() + 1;
}
@Override
public int getItemViewType(int position) {
if (position == getCount() - 1) {
return 0;
} else {
return addViewType(position); //構(gòu)造一個(gè)方法出來(lái),方便子類修改,添加更多的樣式
}
}
public int addViewType(int position) {
return 1;
}
2、在getview()中針對(duì)不同的類型添加布局:
@Override
public View getView(int position, View convertView, ViewGroup parent) {
BaseHoldle holdle;
if (convertView == null) {
if (getItemViewType(position) == 0) { //type為0 表示應(yīng)該加載加載更多的視圖
holdle = getLoadmoreHoldle();
} else { //否則為普通視圖
holdle = getSpecialBaseHoldle(position);
}
} else {
holdle = (BaseHoldle) convertView.getTag();
}
if (getItemViewType(position) == 0) { //加載更多視圖,請(qǐng)求網(wǎng)絡(luò)獲取數(shù)據(jù)
if (havemore()) {
holdle.setDataAndRefreshHoldleView(LoadmoreHoldle.LOADMORE_LODING);
triggleLoadMoreData();
} else {
holdle.setDataAndRefreshHoldleView(LoadmoreHoldle.LOADMORE_NONE);
}
} else { //普通視圖視圖,請(qǐng)求網(wǎng)絡(luò)獲取數(shù)據(jù)
T data = (T) mdata.get(position);
holdle.setDataAndRefreshHoldleView(data);
}
mHoldleView = holdle.mHoldleView;
mHoldleView.setScaleX(0.6f);
mHoldleView.setScaleY(0.6f);
ViewCompat.animate(mHoldleView).scaleX(1).scaleY(1).setDuration(400).setInterpolator(new OvershootInterpolator(4)).start();
return mHoldleView;
}
3、具體的加載更多視圖的實(shí)現(xiàn)
private BaseHoldle getLoadmoreHoldle() {
if (mLoadmoreHoldle == null) {
mLoadmoreHoldle = new LoadmoreHoldle();
}
return mLoadmoreHoldle;
}
public class LoadmoreHoldle extends BaseHoldle {
@Bind(R.id.item_loadmore_container_loading)
LinearLayout itemloadmorecontainerloading;
@Bind(R.id.item_loadmore_container_retry)
LinearLayout itemloadmorecontainerretry;
@Bind(R.id.item_loadmore_tv_retry)
TextView item_loadmore_tv_retry;
public static final int LOADMORE_LODING = 0;
public static final int LOADMORE_ERROR = 1;
public static final int LOADMORE_NONE = 2;
private int mCurretState;
@Override
public void refreshHoldleView(Object data) {
itemloadmorecontainerloading.setVisibility(View.GONE);
itemloadmorecontainerretry.setVisibility(View.GONE);
mCurretState = (int) data;
switch (mCurretState) {
case LOADMORE_LODING:
itemloadmorecontainerloading.setVisibility(View.VISIBLE);
break;
case LOADMORE_ERROR:
itemloadmorecontainerretry.setVisibility(View.VISIBLE);
break;
case LOADMORE_NONE:
break;
}
}
@Override
public View ininViewHoldle() {
View view = View.inflate(UiUtils.getContext(), R.layout.itemloadmore, null);
ButterKnife.bind(this, view);
return view;
}
}
//holder基類,提取公共的方法
public abstract class BaseHoldle<T> {
public View mHoldleView;
public T mdata;
public BaseHoldle() {
mHoldleView = ininViewHoldle();
mHoldleView.setTag(this);
}
public void setDataAndRefreshHoldleView(T mdata) {
this.mdata = mdata;
refreshHoldleView(mdata);
}
public abstract void refreshHoldleView(T data);
public abstract View ininViewHoldle();
}
方案三: SwipeRefreshLayout實(shí)現(xiàn)下來(lái)刷新
SwipeRefreshLayout對(duì)下不兼容,且只有下拉刷新功能沒(méi)有上拉加載更多的功能。當(dāng)時(shí)作為Andriod5.0之后的新特性,使用起來(lái)方便,可以直接調(diào)用系統(tǒng)的API。使用方法也較為簡(jiǎn)單。具體實(shí)現(xiàn)如下:
首先聲明控件,設(shè)置顏色:
refreshLayout = (SwipeRefreshLayout) findViewById(R.id.refresh);
refreshLayout.setOnRefreshListener(this);
refreshLayout.setColorSchemeResources(android.R.color.holo_blue_bright,
android.R.color.holo_green_light,android.R.color.holo_orange_light,
android.R.color.holo_red_light);
refreshLayout.setProgressBackgroundColor(R.color.refresh_bg);
refreshLayout.setProgressBackgroundColor(R.color.refresh_bg);
寫一個(gè)類實(shí)現(xiàn)SwipeRefreshLayout.OnRefreshListener,重寫onRefresh()方法:
@Override
public void onRefresh() {
refreshLayout.postDelayed(new Runnable() {
@Override
public void run() {
//請(qǐng)求網(wǎng)絡(luò),獲取數(shù)據(jù)
refreshLayout.setRefreshing(false);
}
},3000);
}
以上所述是小編給大家介紹的Android中Listview下拉刷新和上拉加載更多的多種實(shí)現(xiàn)方案,希望對(duì)大家有所幫助,如果大家有任何疑問(wèn)請(qǐng)給我留言,小編會(huì)及時(shí)回復(fù)大家的。在此也非常感謝大家對(duì)腳本之家網(wǎng)站的支持!
- Android實(shí)現(xiàn)上拉加載更多以及下拉刷新功能(ListView)
- Android RecyclerView 上拉加載更多及下拉刷新功能的實(shí)現(xiàn)方法
- Android ListView實(shí)現(xiàn)上拉加載更多和下拉刷新功能
- Android下拉刷新上拉加載更多左滑動(dòng)刪除
- Android XListView下拉刷新和上拉加載更多
- Android RecyclerView實(shí)現(xiàn)下拉刷新和上拉加載更多
- Android RecyclerView下拉刷新和上拉加載更多
- Android 仿硅谷新聞下拉刷新/上拉加載更多
- android使用PullToRefresh框架實(shí)現(xiàn)ListView下拉刷新上拉加載更多
- Android實(shí)踐之帶加載效果的下拉刷新上拉加載更多
相關(guān)文章
Android實(shí)現(xiàn)顯示和隱藏密碼功能的示例代碼
在前端中我們知道用javascript就可以可以很容易實(shí)現(xiàn)密碼的顯示與隱藏,本文將大家詳細(xì)介紹Android是如何實(shí)現(xiàn)顯示和隱藏密碼功能的,需要的可以參考一下2022-06-06
Android組件之DrawerLayout實(shí)現(xiàn)抽屜菜單
DrawerLayout組件同樣是V4包中的組件,也是直接繼承于ViewGroup類,所以這個(gè)類也是一個(gè)容器類。接下來(lái)通過(guò)本文給大家介紹Android組件之DrawerLayout實(shí)現(xiàn)抽屜菜單,感興趣的朋友一起學(xué)習(xí)吧2016-02-02
Android EditText追加空格、限制字符等方法示例
這篇文章主要給大家介紹了關(guān)于Android EditText追加空格、限制字符等的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)各位Android開(kāi)發(fā)者們具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-06-06
怎樣刪除android的gallery中的圖片實(shí)例說(shuō)明
長(zhǎng)按gallery中的圖片進(jìn)行刪除該圖片的操作,具體實(shí)現(xiàn)如下,感興趣的朋友可以參考下哈2013-06-06
百度語(yǔ)音識(shí)別(Baidu Voice) Android studio版本詳解
這篇文章主要介紹了百度語(yǔ)音識(shí)別(Baidu Voice) Android studio版本詳解的相關(guān)資料,需要的朋友可以參考下2016-09-09
Flutter實(shí)現(xiàn)漸變弧形進(jìn)度條的示例詳解
在Flutter開(kāi)發(fā)中,構(gòu)建一個(gè)具有視覺(jué)吸引力的、反映進(jìn)度的圓形弧形進(jìn)度條是一個(gè)常見(jiàn)需求,本文將詳細(xì)介紹如何使用Flutter和Dart語(yǔ)言實(shí)現(xiàn)這一功能,需要的可以參考下2023-12-12
Android編程之點(diǎn)擊按鈕的響應(yīng)方式小結(jié)【3種方式】
這篇文章主要介紹了Android編程之點(diǎn)擊按鈕的響應(yīng)方式,結(jié)合實(shí)例形式分析總結(jié)了常用的三種按鈕響應(yīng)方式,需要的朋友可以參考下2017-02-02

