自定义CListView
继承ListView
,实现AbsListView.OnScrollListener
接口。
CListView
添加CListViewHeaderView
作为表头,使用表头显示状态,在加入表头以后列表的数量是Adapter
的数量加上1。
CListView
捕捉手势操作,监听滚动事件并设置刷新事件。
public class CListView extends ListView implements AbsListView.OnScrollListener {
private CListViewHeaderView mHeaderView;
private int mFirstItemIndex;
private float mStartY, mCurrentY;
private boolean mRefreshEnable, mRecord;
public CListView(Context context) {
this(context, null);
}
public CListView(Context context, AttributeSet attrs) {
super(context, attrs);
mHeaderView = new CListViewHeaderView(context);
mHeaderView.setListView(this);
addHeaderView(mHeaderView);
mHeaderView.refreshFinish();
setOnScrollListener(this);
}
@Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
mFirstItemIndex = firstVisibleItem;
}
@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
}
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
// 保证触摸的y值只记录一次
if (!mRecord) {
mStartY = event.getY();
mRecord = true;
}
break;
case MotionEvent.ACTION_MOVE:
if (!mRecord) {
mStartY = event.getY();
mRecord = true;
}
mCurrentY = event.getY();
if (mRefreshEnable && mFirstItemIndex == 0) {
mHeaderView.move((int) (mCurrentY - mStartY));
}
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
mCurrentY = event.getY();
if (mRefreshEnable && mFirstItemIndex == 0 && mRecord) {
mHeaderView.release((int) (mCurrentY - mStartY));
}
mRecord = false;
break;
}
return super.onTouchEvent(event);
}
/*
* 刷新回调
*/
public void refreshFinish() {
mHeaderView.refreshFinish();
}
public void setOnRefreshListener(IOnRefreshListener refreshListener) {
mRefreshEnable = (refreshListener != null);
mHeaderView.setOnRefreshListener(refreshListener);
}
public interface IOnRefreshListener {
void onRefreshStart();
}
}
CListViewHeaderView
拥有四种状态
DONE
,初始状态PULL_TO_REFRESH
,下拉刷新RELEASE_TO_REFRESH
,松开刷新REFRESHING
,刷新中CListViewHeaderView
默认是初始状态,当进行下拉操作时,显示为下拉刷新。下拉超过3倍表头高度,显示松开刷新。正在刷新时不能进行界面操作。
public class CListViewHeaderView extends LinearLayout {
private final static int DONE = 0;
private final static int PULL_TO_REFRESH = 1; // 下拉刷新
private final static int RELEASE_TO_REFRESH = 2; // 放手刷新
private final static int REFRESHING = 3; // 刷新
private final static int RATIO = 3;
private ImageView mIvArrow;
private ProgressBar mProgressBarRefresh;
private TextView mTvRefreshTips;
private Animation mAnimCycle, mAnimReverse;
private String mPullToRefresh, mReleaseToRefresh, mRefreshing;
private int mContentHeight;
private int mHeadState = DONE;
private boolean mReverse; // 图标是否旋转
private CListView mListView;
private CListView.IOnRefreshListener mListener;
public CListViewHeaderView(Context context) {
this(context, null);
}
public CListViewHeaderView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
inflate(context, R.layout.list_view_header_view, this);
mIvArrow = findViewById(R.id.iv_arrow);
mProgressBarRefresh = findViewById(R.id.progress_bar_refresh);
mTvRefreshTips = findViewById(R.id.tv_refresh_tips);
mAnimCycle = AnimationUtils.loadAnimation(context, R.anim.anim_list_view_rotate);
mAnimReverse = AnimationUtils.loadAnimation(context, R.anim.anim_list_view_reverse);
mContentHeight = context.getResources().getDimensionPixelOffset(R.dimen.head_view_height);
mPullToRefresh = context.getString(R.string.list_view_pull_to_refresh);
mReleaseToRefresh = context.getString(R.string.list_view_release_to_refresh);
mRefreshing = context.getString(R.string.list_view_refreshing);
}
void setListView(CListView listView) {
this.mListView = listView;
}
void move(int distance) {
if (mHeadState != REFRESHING) {
if (mHeadState == DONE) {
if (distance > 0) {
mHeadState = PULL_TO_REFRESH;
changeHeaderViewByState();
}
}
if (mHeadState == PULL_TO_REFRESH) {
if (distance >= RATIO * mContentHeight) {
mHeadState = RELEASE_TO_REFRESH;
mReverse = true;
changeHeaderViewByState();
} else if (distance <= 0) {
mHeadState = DONE;
changeHeaderViewByState();
}
}
if (mHeadState == RELEASE_TO_REFRESH) {
if (distance <= 0) {
mHeadState = DONE;
changeHeaderViewByState();
} else if (distance < RATIO * mContentHeight) {
mHeadState = PULL_TO_REFRESH;
changeHeaderViewByState();
}
}
if (mHeadState == PULL_TO_REFRESH || mHeadState == RELEASE_TO_REFRESH) {
if (mListView != null) {
mListView.setSelection(0);
}
setPadding(0, distance / RATIO - mContentHeight, 0, 0);
}
}
}
void release(float distance) {
if (distance >= RATIO * mContentHeight) {
mHeadState = REFRESHING;
} else {
mHeadState = DONE;
}
changeHeaderViewByState();
if (mHeadState == REFRESHING) {
mListener.onRefreshStart();
}
}
void setOnRefreshListener(CListView.IOnRefreshListener listener) {
this.mListener = listener;
}
public void refreshFinish() {
mHeadState = DONE;
changeHeaderViewByState();
}
private void changeHeaderViewByState() {
switch (mHeadState) {
case DONE:
setPadding(0, -1 * mContentHeight, 0, 0);
mIvArrow.clearAnimation();
mProgressBarRefresh.setVisibility(View.GONE);
mTvRefreshTips.setText(mPullToRefresh);
break;
case PULL_TO_REFRESH:
mIvArrow.setVisibility(View.VISIBLE);
mIvArrow.clearAnimation();
mProgressBarRefresh.setVisibility(View.GONE);
mTvRefreshTips.setText(mPullToRefresh);
// 是由RELEASE_To_REFRESH状态转变来的
if (mReverse) {
mReverse = false;
mIvArrow.startAnimation(mAnimReverse);
}
break;
case RELEASE_TO_REFRESH:
mIvArrow.setVisibility(View.VISIBLE);
mIvArrow.clearAnimation();
mIvArrow.startAnimation(mAnimCycle);
mProgressBarRefresh.setVisibility(View.GONE);
mTvRefreshTips.setText(mReleaseToRefresh);
break;
case REFRESHING:
setPadding(0, 0, 0, 0);
mIvArrow.clearAnimation();
mIvArrow.setVisibility(View.GONE);
mProgressBarRefresh.setVisibility(View.VISIBLE);
mTvRefreshTips.setText(mRefreshing);
break;
}
}
}
资源文件list_view_header_view.xml
在Activity
中添加CListView.IOnRefreshListener
监听器,并在3秒后结束。
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
... ...
final CListView listView = findViewById(R.id.list_view);
listView.setAdapter(new ArrayAdapter<>(this,
R.layout.list_view_item, R.id.tv_name, getResources().getStringArray(R.array.month)));
listView.setOnRefreshListener(new CListView.IOnRefreshListener() {
@Override
public void onRefreshStart() {
listView.postDelayed(new Runnable() {
@Override
public void run() {
listView.refreshFinish();
}
}, 3000);
}
});
}