package cn.coderss.pulltorefresh;
import cn.coderss.pulltorefresh.ILoadingLayout.State;
import android.content.Context;
import android.util.AttributeSet;
import android.view.View;
import android.widget.AbsListView;
import android.widget.AbsListView.OnScrollListener;
import android.widget.Adapter;
import android.widget.ListView;
/**
* 这个类实现了ListView下拉刷新,上加载更多和滑到底部自动加载
*
* @author Li Hong
* @since 2013-8-15
*/
public class PullToRefreshListView extends PullToRefreshBase<ListView> implements OnScrollListener {
/**ListView*/
private ListView mListView;
/**用于滑到底部自动加载的Footer*/
private LoadingLayout mLoadMoreFooterLayout;
/**滚动的监听器*/
private OnScrollListener mScrollListener;
/**
* 构造方法
*
* @param context context
*/
public PullToRefreshListView(Context context) {
this(context, null);
}
/**
* 构造方法
*
* @param context context
* @param attrs attrs
*/
public PullToRefreshListView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
/**
* 构造方法
*
* @param context context
* @param attrs attrs
* @param defStyle defStyle
*/
public PullToRefreshListView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
setPullLoadEnabled(false);
}
@Override
protected ListView createRefreshableView(Context context, AttributeSet attrs) {
ListView listView = new ListView(context);
mListView = listView;
listView.setOnScrollListener(this);
return listView;
}
/**
* 设置是否有更多数据的标志
*
* @param hasMoreData true表示还有更多的数据,false表示没有更多数据了
*/
public void setHasMoreData(boolean hasMoreData) {
if (!hasMoreData) {
if (null != mLoadMoreFooterLayout) {
mLoadMoreFooterLayout.setState(State.NO_MORE_DATA);
}
LoadingLayout footerLoadingLayout = getFooterLoadingLayout();
if (null != footerLoadingLayout) {
footerLoadingLayout.setState(State.NO_MORE_DATA);
}
}
}
/**
* 设置滑动的监听器
*
* @param l 监听器
*/
public void setOnScrollListener(OnScrollListener l) {
mScrollListener = l;
}
@Override
protected boolean isReadyForPullUp() {
return isLastItemVisible();
}
@Override
protected boolean isReadyForPullDown() {
return isFirstItemVisible();
}
@Override
protected void startLoading() {
super.startLoading();
if (null != mLoadMoreFooterLayout) {
mLoadMoreFooterLayout.setState(State.REFRESHING);
}
}
@Override
public void onPullUpRefreshComplete() {
super.onPullUpRefreshComplete();
if (null != mLoadMoreFooterLayout) {
mLoadMoreFooterLayout.setState(State.RESET);
}
}
@Override
public void setScrollLoadEnabled(boolean scrollLoadEnabled) {
super.setScrollLoadEnabled(scrollLoadEnabled);
if (scrollLoadEnabled) {
// 设置Footer
if (null == mLoadMoreFooterLayout) {
mLoadMoreFooterLayout = new FooterLoadingLayout(getContext());
}
if (null == mLoadMoreFooterLayout.getParent()) {
mListView.addFooterView(mLoadMoreFooterLayout, null, false);
}
mLoadMoreFooterLayout.show(true);
} else {
if (null != mLoadMoreFooterLayout) {
mLoadMoreFooterLayout.show(false);
}
}
}
@Override
public LoadingLayout getFooterLoadingLayout() {
if (isScrollLoadEnabled()) {
return mLoadMoreFooterLayout;
}
return super.getFooterLoadingLayout();
}
@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
if (isScrollLoadEnabled() && hasMoreData()) {
if (scrollState == OnScrollListener.SCROLL_STATE_IDLE
|| scrollState == OnScrollListener.SCROLL_STATE_FLING) {
if (isReadyForPullUp()) {
startLoading();
}
}
}
if (null != mScrollListener) {
mScrollListener.onScrollStateChanged(view, scrollState);
}
}
@Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
if (null != mScrollListener) {
mScrollListener.onScroll(view, firstVisibleItem, visibleItemCount, totalItemCount);
}
}
@Override
protected LoadingLayout createHeaderLoadingLayout(Context context, AttributeSet attrs) {
return new RotateLoadingLayout(context);
}
/**
* 表示是否还有更多数据
*
* @return true表示还有更多数据
*/
private boolean hasMoreData() {
if ((null != mLoadMoreFooterLayout) && (mLoadMoreFooterLayout.getState() == State.NO_MORE_DATA)) {
return false;
}
return true;
}
/**
* 判断第一个child是否完全显示出来
*
* @return true完全显示出来,否则false
*/
private boolean isFirstItemVisible() {
final Adapter adapter = mListView.getAdapter();
if (null == adapter || adapter.isEmpty()) {
return true;
}
int mostTop = (mListView.getChildCount() > 0) ? mListView.getChildAt(0).getTop() : 0;
if (mostTop >= 0) {
return true;
}
return false;
}
/**
* 判断最后一个child是否完全显示出来
*
* @return true完全显示出来,否则false
*/
private boolean isLastItemVisible() {
final Adapter adapter = mListView.getAdapter();
if (null == adapter || adapter.isEmpty()) {
return true;
}
final int lastItemPosition = adapter.getCount() - 1;
final int lastVisiblePosition = mListView.getLastVisiblePosition();
/**
* This check should really just be: lastVisiblePosition == lastItemPosition, but ListView
* internally uses a FooterView which messes the positions up. For me we'll just subtract
* one to account for it and rely on the inner condition which checks getBottom().
*/
if (lastVisiblePosition >= lastItemPosition - 1) {
final int childIndex = lastVisiblePosition - mListView.getFirstVisiblePosition();
final int childCount = mListView.getChildCount();
final int index = Math.min(childIndex, childCount - 1);
final View lastVisibleChild = mListView.getChildAt(index);
if (lastVisibleChild != null) {
return lastVisibleChild.getBottom() <= mListView.getBottom();
}
}
return false;
}
}