项目中经常使用listView的下拉刷新,上拉加载更多,以及左滑删除更多
但是因为时间关系从来没有把这个控件好好整理下,异常边界处理不够好
这次根据自己项目的实际需要整理了一下
下拉刷新采用的是SwipeRefreshLayout
上拉加载更多逻辑是自己写的
滑动删除采用的是别人开源的控件左滑控件这个控件不会改变你任何Adapter中的代码
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//上拉加载更多
listView.setUpPullRefreshListener(new SListView.IUpPullRefreshListener() {
@Override
public void upPullRefresh() {
pageNo++;
loadListData();
}
});
//下拉刷新
swipeLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
@Override
public void onRefresh() {
swipeLayout.setRefreshing(true);
pageNo=1;
loadListData();
}
});
//传递SwipeRefreshLayout实例而已
listView.setSlidingRestriction(SwipeLayout);
}
public void loadListData(){
........................
//当数据加载完成后调用此方法具体见下面代码
listView.loadDataOver(true, true);
swipeLayout.setRefreshing(false);
adapter.notifyDataSetChanged();
}
//界面布局activity_main
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:imageText="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#ffffff"
android:orientation="vertical">
<android.support.v4.widget.SwipeRefreshLayout
android:id="@+id/swipeLayout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.cx.wdiget.listView.SListView
android:id="@+id/listView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:divider="@null" />
android.support.v4.widget.SwipeRefreshLayout>
RelativeLayout>
//item布局代码
//your_content 这里面是自定义的布局,宽度必须使用match_parent,外面就是滑动展示的布局
<com.mcxtzhang.swipemenulib.SwipeMenuLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="50dp"
android:clickable="true">
<LinearLayout
android:id="@+id/your_content"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:id="@+id/tv_name"
android:layout_width="match_parent"
android:layout_height="49dp"
android:background="@color/white"
android:gravity="center"
android:text="11111111111111111111111111"
android:textColor="@color/color_333333"
android:textSize="@dimen/dimen_18sp" />
<View
android:layout_width="match_parent"
android:layout_height="@dimen/dimen_0.5dp"
android:background="#00c0c7" />
LinearLayout>
<TextView
android:id="@+id/tv_delete"
android:layout_width="100dp"
android:layout_height="match_parent"
android:background="#ff0000"
android:gravity="center"
android:text="删 除"
android:textColor="@android:color/white"
android:textSize="25sp" />
com.mcxtzhang.swipemenulib.SwipeMenuLayout>
//自定义listView类
package com.cx.wdiget.listView;
import android.content.Context;
import android.support.v4.widget.SwipeRefreshLayout;
import android.util.AttributeSet;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.widget.AbsListView;
import android.widget.ListView;
import android.widget.ProgressBar;
import android.widget.TextView;
import com.cx.wdiget.R;
import com.mcxtzhang.swipemenulib.SwipeMenuLayout;
/**
* 自定义listView下拉和上拉刷新
*
* 下拉刷新采用SwipeRefreshLayout
*
* 上拉刷新自定义实现
*
* listView中item左滑删除采用这个第三方{@link SwipeMenuLayout}控件
*/
public class SListView extends ListView implements AbsListView.OnScrollListener {
private LayoutInflater inflate;
private View footerRootView;
private ProgressBar pb_footerProgressBar;
private TextView tv_footerHint;
private IUpPullRefreshListener iUpPullRefreshListener;
private IDownPullRefreshListener iDownPullRefreshListener;
/**
* 上拉加载更多状态码
*
* UP_LOADING 加载中
*
* UP_LOADING_DONE 加载完成
*
* UP_LOADING_NO_MORE 加载完成没有更多新数据,数据加载成功没有下一页数据时显示
*
* UP_LOADING_ERROR 加载完成异常(无网络、获取数据失败等)
*/
private int upLoadingState = 0;
private final int UP_LOADING = 1;
private final int UP_LOADING_DONE = 2;
private final int UP_LOADING_NO_MORE = 3;
private final int UP_LOADING_ERROR = 4;
/**当前item是否超过手机一屏幕,超过才把footerView预加载出来**/
private boolean moreThanOneScreen = false;
/**当前item是否是滑动到屏幕最后一条**/
private boolean scrollLastItem = false;
/**使用了{@link SwipeMenuLayout}控件后,是否有item滑动开,false关闭 true 打开**/
private boolean swipeMenuLayoutOpen = false;
/**当上拉加载,没有更多数据时,记录加载时间,做一个几分钟内再次执行上拉不加载数据的限制**/
private long upNoMoreDataStartTime = 0;
/**swipeRefreshLayout不为null表示使用他来做下拉刷新**/
private SwipeRefreshLayout swipeRefreshLayout;
public SListView(Context context) {
this(context, null);
}
public SListView(Context context, AttributeSet attrs) {
super(context, attrs);
initView(context);
}
/**
* 初始化操作
*
* @param context context
*/
private void initView(Context context) {
inflate = LayoutInflater.from(context);
this.setOnScrollListener(this);
}
/**
* listView 初始化FooterView
*/
private void initFooterView() {
footerRootView = inflate.inflate(R.layout.item_down_pull_refresh_footer, null);
pb_footerProgressBar = (ProgressBar) footerRootView.findViewById(R.id.pb_footerProgressBar);
tv_footerHint = (TextView) footerRootView.findViewById(R.id.tv_footerHint);
footerRootView.setVisibility(View.GONE);
footerRootView.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
upPullLoadingData(true);
}
});
addFooterView(footerRootView);
}
/**
*
* on touch event
*
* @param event event
* @return
*/
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
swipeMenuLayoutOpen = (SwipeMenuLayout.getViewCache() != null);
//当左滑打开时不能执行任何非当前item的事件
if (swipeMenuLayoutOpen) {
if(swipeRefreshLayout!=null){
swipeRefreshLayout.setEnabled(false);
}
this.requestDisallowInterceptTouchEvent(swipeMenuLayoutOpen);
SwipeMenuLayout.getViewCache().smoothClose();
}
break;
case MotionEvent.ACTION_MOVE:
if (swipeRefreshLayout != null) {
swipeRefreshLayout.setEnabled(!swipeMenuLayoutOpen);
}
this.requestDisallowInterceptTouchEvent(swipeMenuLayoutOpen);
break;
case MotionEvent.ACTION_UP:
swipeMenuLayoutOpen = false;
break;
case MotionEvent.ACTION_CANCEL:
swipeMenuLayoutOpen = false;
break;
default:
break;
}
return swipeMenuLayoutOpen || super.onTouchEvent(event);
}
@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
if (scrollState == SCROLL_STATE_IDLE && scrollLastItem) {
upPullLoadingData(false);
}
}
@Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
moreThanOneScreen = (totalItemCount > visibleItemCount);
scrollLastItem = (firstVisibleItem + visibleItemCount == totalItemCount);
//满足条件先把footerRootView显示出来,滑动到底部时不会造成footerRootView显示的延迟
//iUpPullRefreshListener表示用户允许执行上拉加载
//moreThanOneScreen当列表数据超过一屏幕时才展示
if (iUpPullRefreshListener != null && footerRootView != null) {
footerRootView.setVisibility(moreThanOneScreen ? View.VISIBLE : View.GONE);
}
}
/**
* 上拉刷新状态的改变,改变样式
*/
private void changeFooterViewByState() {
if (iUpPullRefreshListener == null || footerRootView == null) {
return;
}
switch (upLoadingState) {
case UP_LOADING_NO_MORE:
pb_footerProgressBar.setVisibility(View.GONE);
tv_footerHint.setText("没有更多了");
if (upNoMoreDataStartTime <= 0) {
upNoMoreDataStartTime = System.currentTimeMillis();
}
break;
case UP_LOADING_ERROR:
pb_footerProgressBar.setVisibility(View.GONE);
tv_footerHint.setText("点击加载更多");
upNoMoreDataStartTime = 0;
break;
case UP_LOADING:
pb_footerProgressBar.setVisibility(View.VISIBLE);
tv_footerHint.setText("加载中...");
upNoMoreDataStartTime = 0;
break;
default:
break;
}
}
/**
* 执行上拉加载数据
*/
private void upPullLoadingData(boolean clickFooterView) {
if (iUpPullRefreshListener != null && upLoadingState != UP_LOADING && moreThanOneScreen) {
if (!AndroidUtils.isNetworkAvailable()) {
AndroidUtils.toast("网络不给力,请检查后重试");
upLoadingState = UP_LOADING_ERROR;
changeFooterViewByState();
return;
}
if (upLoadingState == UP_LOADING_NO_MORE && !againLoadingNoMoreData()) {
return;
}
if (upLoadingState == UP_LOADING_ERROR && !clickFooterView) {
return;
}
upLoadingState = UP_LOADING;
changeFooterViewByState();
iUpPullRefreshListener.upPullRefresh();
}
}
/**
* 超过五分钟才能再次执行上拉加载
*
* 当上拉加载状态为UP_LOADING_NO_MORE时,再次执行上拉加载时有时间限制
*
* 超过限制时间后才能再次执行上拉操作
*
* @return true 可以加载 false不可以加载
*/
private boolean againLoadingNoMoreData() {
return (System.currentTimeMillis() - upNoMoreDataStartTime > (5 * 60 * 1000));
}
/**
* 数据加载完成后调用
*
* @param loadSuccess 加载数据是否成功
* @param nextPage 是否还有下一页数据
*/
public void loadDataOver(boolean loadSuccess, boolean nextPage) {
Log.v("tag", "loadDataOver");
if (loadSuccess) {
if (!nextPage) {
upLoadingState = UP_LOADING_NO_MORE;
changeFooterViewByState();
} else {
upLoadingState = UP_LOADING_DONE;
}
} else {
upLoadingState = UP_LOADING_ERROR;
changeFooterViewByState();
}
}
/**
* 左滑删除限制
*
* 使用{@link SwipeMenuLayout}
*
* 当item滑动开时,不允许执行任何事件({@link #onTouchEvent(MotionEvent)})
*/
public void setSlidingRestriction(SwipeRefreshLayout swipeRefreshLayout) {
this.swipeRefreshLayout = swipeRefreshLayout;
}
public void setUpPullRefreshListener(IUpPullRefreshListener iUpPullRefreshListener) {
if (iUpPullRefreshListener != null) {
this.iUpPullRefreshListener = iUpPullRefreshListener;
initFooterView();
}
}
public void setDownPullRefreshListener(IDownPullRefreshListener iDownPullRefreshListener) {
this.iDownPullRefreshListener = iDownPullRefreshListener;
}
public interface IUpPullRefreshListener {
void upPullRefresh();
}
public interface IDownPullRefreshListener {
void downPullRefresh();
}
}
//item_down_pull_refresh_footer
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="50dp"
android:background="@color/color_ffffff"
android:gravity="center"
android:orientation="horizontal"
android:padding="@dimen/dimen_15dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:orientation="horizontal">
<ProgressBar
android:id="@+id/pb_footerProgressBar"
style="?android:attr/progressBarStyleSmall"
android:layout_width="@dimen/dimen_15dp"
android:layout_height="@dimen/dimen_15dp"
android:indeterminate="true"
android:indeterminateDrawable="@drawable/up_pull_footer_progressbar"
android:visibility="visible" />
<TextView
android:id="@+id/tv_footerHint"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/dimen_10dp"
android:gravity="center"
android:text="@string/p2refresh_head_load_more"
android:textColor="#00c0c7"
android:textSize="@dimen/dimen_14sp" />
LinearLayout>
LinearLayout>