用网上的下拉刷新+上拉更多改的,欢迎大家反馈问题,并一同完善,以后用的时候就方便了
package com.tts.dyq.util;
import java.text.SimpleDateFormat;
import java.util.Date;
import android.annotation.SuppressLint;
import android.content.Context;
import android.os.IInterface;
import android.provider.ContactsContract.CommonDataKinds.Event;
import android.util.AttributeSet;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.view.animation.Animation;
import android.view.animation.LinearInterpolator;
import android.view.animation.RotateAnimation;
import android.widget.AbsListView;
import android.widget.AbsListView.OnScrollListener;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.ProgressBar;
import android.widget.TextView;
import com.tts.dyq.R;
@SuppressLint("SimpleDateFormat")
public class PullToRefreshListView_Both extends ListView implements OnScrollListener {
private static final String TAG = "listview";
private final static int RELEASE_To_REFRESH = 0; // 释放
private final static int PULL_To_REFRESH = 1;// 下拉刷新
private final static int REFRESHING = 2; // 正在刷新
private final static int DONE = 3; // 按下
private final static int LOADING = 4;
// 实际的padding的距离与界面上偏移距离的比例
private final static int RATIO = 3;
private LayoutInflater inflater;
private LinearLayout headView;
private TextView tipsTextview;
private TextView lastUpdatedTextView;
private ImageView arrowImageView;
private ProgressBar progressBar;
private RotateAnimation animation;
private RotateAnimation reverseAnimation;
// 用于保证startY的值在一个完整的touch事件中只被记录一次
private boolean isRecored = false;
private int headContentWidth;
private int headContentHeight;
private int firstItemIndex;
private int state;
private boolean isBack;
private OnRefreshListener refreshListener;
private boolean isRefreshable;
private LinearLayout footView;
private TextView m_tipsTextview;
private TextView m_lastUpdatedTextView;
private ImageView m_arrowImageView;
private ProgressBar m_progressBar;
private boolean m_isRecored = false;
private int m_headContentWidth;
private int m_headContentHeight;
private int startY;
private int m_firstItemIndex;
private boolean m_isBack;
private OnRefreshListener m_refreshListener;
private boolean mRefreshHead;
private int mTotalSize;
public PullToRefreshListView_Both(Context context) {
super(context);
init(context);
}
private void init(Context context) {
inflater = LayoutInflater.from(context);
initHeadView(context);
initFootView(context);
initAnimation();
state = DONE;
isRefreshable = false;
setOnScrollListener(this);
}
/**
* 初始化动画
*/
private void initAnimation() {
animation = new RotateAnimation(0, -180, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
animation.setInterpolator(new LinearInterpolator());
animation.setDuration(250);
animation.setFillAfter(true);
reverseAnimation = new RotateAnimation(0, -180, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF,
0.5f);
reverseAnimation.setInterpolator(new LinearInterpolator());
reverseAnimation.setDuration(200);
reverseAnimation.setFillAfter(true);
}
public PullToRefreshListView_Both(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
}
private void initHeadView(Context context) {
headView = (LinearLayout) inflater.inflate(R.layout.head, null);
arrowImageView = (ImageView) headView.findViewById(R.id.head_arrowImageView);
progressBar = (ProgressBar) headView.findViewById(R.id.head_progressBar);
tipsTextview = (TextView) headView.findViewById(R.id.head_tipsTextView);
lastUpdatedTextView = (TextView) headView.findViewById(R.id.head_lastUpdatedTextView);
measureView(headView);
headContentHeight = headView.getMeasuredHeight();
headContentWidth = headView.getMeasuredWidth();
headView.setPadding(0, -1 * headContentHeight, 0, 0);
headView.invalidate();
Log.v("size", "width:" + headContentWidth + " height:" + headContentHeight);
addHeaderView(headView, null, false);
}
private void initFootView(Context context) {
footView = (LinearLayout) inflater.inflate(R.layout.foot, null);
m_arrowImageView = (ImageView) footView.findViewById(R.id.foot_arrowImageView);
m_progressBar = (ProgressBar) footView.findViewById(R.id.foot_progressBar);
m_tipsTextview = (TextView) footView.findViewById(R.id.foot_tipsTextView);
m_lastUpdatedTextView = (TextView) footView.findViewById(R.id.foot_lastUpdatedTextView);
measureView(footView);
m_headContentHeight = footView.getMeasuredHeight();
m_headContentWidth = footView.getMeasuredWidth();
footView.setPadding(0, -1 * m_headContentHeight, 0, 0);
footView.invalidate();
Log.v("size", "width:" + m_headContentWidth + " height:" + m_headContentHeight);
addFooterView(footView, null, false);
}
@Override
public void onScroll(AbsListView arg0, int firstVisiableItem, int visibleItemCount, int totalItemCount) {
firstItemIndex = firstVisiableItem;
mTotalSize = totalItemCount;
m_firstItemIndex = totalItemCount;
mIsLast = (firstVisiableItem + visibleItemCount) == totalItemCount ? true : false;
// Log.e(TAG, "-------onScroll-------mIsLastItemVisible=" + mIsLast);
}
private boolean mIsLast = false;
@Override
public void onScrollStateChanged(AbsListView arg0, int arg1) {
}
@Override
public boolean onTouchEvent(MotionEvent event) {
// Log.e(TAG, "isRefreshable=" + isRefreshable);
if (getAdapter() == null)
return false;
if (isRefreshable) {
switch (event.getAction()) {
// 在down时候记录当前Y的位置
case MotionEvent.ACTION_DOWN:
startY = (int) event.getY();
// Log.e(TAG, "------x-----startY=" + startY);
break;
case MotionEvent.ACTION_UP:
// Log.e(TAG, "-------------------ACTION_UP-------------------");
if (mRefreshHead) {
updateHeadOnUp();
} else {
updateFootViewOnUp(event);
}
case MotionEvent.ACTION_MOVE:
int tempY = (int) event.getY();
// Log.e(TAG, "------ACTION_MOVE-----tempY=" + tempY +
// " ;startY=" + startY);
if (tempY > startY) {
mRefreshHead = true;
if (firstItemIndex == 0) {
updateHeadViewOnMove(tempY);
}
} else {
mRefreshHead = false;
if (mIsLast) {
updateFootViewOnMove(tempY);
}
}
break;
}
}
return super.onTouchEvent(event);
}
private void updateFootViewOnUp(MotionEvent event) {
Log.e(TAG, "---------foot----up------------status-----------" + state);
if (state != REFRESHING && state != LOADING) {
if (state == DONE) {
// 什么都不做
// Log.e(TAG, "--------foot---up-----0------");
footView.setPadding(0, -1 * m_headContentHeight, 0, 0);
headView.setPadding(0, -1 * headContentHeight, 0, 0);
}
// 由下拉刷新状态,到done状态
if (state == PULL_To_REFRESH) {
// Log.e(TAG, "--------foot---up-----1------");
state = DONE;
changeHeaderViewByState();
Log.v(TAG, "由上拉刷新状态,到done状态");
}
if (state == RELEASE_To_REFRESH) {
// Log.e(TAG, "--------foot---up-----2------");
state = REFRESHING;
changeHeaderViewByState();
onRefresh();
Log.v(TAG, "由松开刷新状态,到done状态");
}
}
m_isRecored = false;
m_isBack = false;
}
private void updateHeadOnUp() {
// Log.e(TAG, "---------head----up-------------------status-----------" + state);
if (state != REFRESHING && state != LOADING) {
if (state == DONE) {
// Log.e(TAG, "----head----up----------0-----");
// 什么都不做
footView.setPadding(0, -1 * m_headContentHeight, 0, 0);
headView.setPadding(0, -1 * headContentHeight, 0, 0);
}
// 由下拉刷新状态,到done状态
if (state == PULL_To_REFRESH) {
// Log.e(TAG, "----head----up---------1------");
state = DONE;
changeHeaderViewByState();
Log.v(TAG, "由下拉刷新状态,到done状态");
}
if (state == RELEASE_To_REFRESH) {
// Log.e(TAG, "----head----up--------2-------");
state = REFRESHING;
changeHeaderViewByState();
onRefresh();
Log.v(TAG, "由松开刷新状态,到done状态");
}
}
isRecored = false;
isBack = false;
}
private void changeHeaderViewByState() {
// Log.e(TAG, "---------changeHeaderViewByState------in----");
switch (state) {
// 松开刷新状态
case RELEASE_To_REFRESH:
if (mRefreshHead) {
arrowImageView.setVisibility(View.VISIBLE);
progressBar.setVisibility(View.GONE);
tipsTextview.setVisibility(View.VISIBLE);
lastUpdatedTextView.setVisibility(View.VISIBLE);
arrowImageView.clearAnimation();
arrowImageView.startAnimation(animation);
tipsTextview.setText("松开刷新");
Log.v(TAG, "当前状态,松开刷新");
} else {
// Log.e(TAG, "---------changeHeaderViewByState-----1-----");
m_arrowImageView.setVisibility(View.VISIBLE);
m_progressBar.setVisibility(View.GONE);
m_tipsTextview.setVisibility(View.VISIBLE);
m_lastUpdatedTextView.setVisibility(View.VISIBLE);
m_arrowImageView.clearAnimation();
m_arrowImageView.startAnimation(animation);
m_tipsTextview.setText("松开刷新");
Log.v(TAG, "当前状态,松开刷新");
}
break;
// 下拉刷新
case PULL_To_REFRESH:
if (mRefreshHead) {
progressBar.setVisibility(View.GONE);
tipsTextview.setVisibility(View.VISIBLE);
lastUpdatedTextView.setVisibility(View.VISIBLE);
arrowImageView.clearAnimation();
arrowImageView.setVisibility(View.VISIBLE);
// 是由RELEASE_To_REFRESH状态转变来的
// 箭头反转向上
if (isBack) {
isBack = false;
arrowImageView.clearAnimation();
arrowImageView.startAnimation(reverseAnimation);
tipsTextview.setText("下拉刷新");
} else {
tipsTextview.setText("下拉刷新");
}
footView.setPadding(0, -1 * m_headContentHeight, 0, 0);
} else {
// Log.e(TAG, "---------changeHeaderViewByState---2-------");
m_progressBar.setVisibility(View.GONE);
m_tipsTextview.setVisibility(View.VISIBLE);
m_lastUpdatedTextView.setVisibility(View.VISIBLE);
m_arrowImageView.clearAnimation();
m_arrowImageView.setVisibility(View.VISIBLE);
// 是由RELEASE_To_REFRESH状态转变来的
// 箭头反转向上
if (m_isBack) {
m_isBack = false;
m_arrowImageView.clearAnimation();
m_arrowImageView.startAnimation(reverseAnimation);
m_tipsTextview.setText("上拉刷新");
} else {
m_tipsTextview.setText("上拉刷新");
}
headView.setPadding(0, -1 * headContentHeight, 0, 0);
}
Log.v(TAG, "当前状态,下拉刷新");
break;
// 刷新中 状态
case REFRESHING:
if (mRefreshHead) {
headView.setPadding(0, 0, 0, 0);
progressBar.setVisibility(View.VISIBLE);
arrowImageView.clearAnimation();
arrowImageView.setVisibility(View.GONE);
tipsTextview.setText("正在刷新...");
lastUpdatedTextView.setVisibility(View.VISIBLE);
} else {
// Log.e(TAG, "---------changeHeaderViewByState---3-------");
footView.setPadding(0, 0, 0, 0);
m_progressBar.setVisibility(View.VISIBLE);
m_arrowImageView.clearAnimation();
m_arrowImageView.setVisibility(View.GONE);
m_tipsTextview.setText("正在刷新...");
m_lastUpdatedTextView.setVisibility(View.VISIBLE);
}
Log.v(TAG, "当前状态,正在刷新...");
break;
// 刷新完毕
case DONE:
if (mRefreshHead) {
firstItemIndex = 0;
headView.setPadding(0, -1 * headContentHeight, 0, 0);
progressBar.setVisibility(View.GONE);
arrowImageView.clearAnimation();
arrowImageView.setImageResource(R.drawable.goicon);
tipsTextview.setText("下拉刷新");
lastUpdatedTextView.setVisibility(View.VISIBLE);
} else {
// Log.e(TAG, "---------changeHeaderViewByState---4-------");
m_firstItemIndex = mTotalSize;
footView.setPadding(0, -1 * m_headContentHeight, 0, 0);
m_progressBar.setVisibility(View.GONE);
m_arrowImageView.clearAnimation();
m_arrowImageView.setImageResource(R.drawable.ic_pulltorefresh_arrow_up);
m_tipsTextview.setText("上拉刷新");
m_lastUpdatedTextView.setVisibility(View.VISIBLE);
}
Log.v(TAG, "当前状态,done");
break;
}
}
public void setOnRefreshListener(OnRefreshListener headViewRefreshListener,
OnRefreshListener footViewRefreshListener) {
this.refreshListener = headViewRefreshListener;
this.m_refreshListener = footViewRefreshListener;
isRefreshable = true;
}
public void updateFootViewOnMove(int tempY) {
Log.e(TAG, "---------------------updateFootViewOnMove------------------------------");
if (!m_isRecored && m_firstItemIndex == mTotalSize) {
Log.v(TAG, "在move时候记录下位置");
m_isRecored = true;
startY = tempY;
}
if (state != REFRESHING && m_isRecored && state != LOADING) {
// 保证在设置padding的过程中,当前的位置一直是在head,否则如果当列表超出屏幕的话,当在上推的时候,列表会同时进行滚动
// 可以松手去刷新了
if (state == RELEASE_To_REFRESH) {
setSelection(mTotalSize);
// 往上推了,推到了屏幕足够掩盖head的程度,但是还没有推到全部掩盖的地步
if (((startY - tempY) / RATIO < m_headContentHeight) && (startY - tempY) > 0) {
state = PULL_To_REFRESH;
changeHeaderViewByState();
Log.e(TAG, "由松开刷新状态转变到上拉刷新状态");
}
// 一下子推到顶了
else if (startY - tempY <= 0) {
state = DONE;
changeHeaderViewByState();
Log.e(TAG, "由松开刷新状态转变到done状态");
}
// 往下拉了,或者还没有上推到屏幕顶部掩盖head的地步
else {
// 不用进行特别的操作,只用更新paddingTop的值就行了
}
}
// 还没有到达显示松开刷新的时候,DONE或者是PULL_To_REFRESH状态
if (state == PULL_To_REFRESH) {
setSelection(mTotalSize);
// 下拉到可以进入RELEASE_TO_REFRESH的状态
if ((startY - tempY) / RATIO >= m_headContentHeight) {
state = RELEASE_To_REFRESH;
m_isBack = true;
changeHeaderViewByState();
Log.e(TAG, "由done或者上拉刷新状态转变到松开刷新");
}
// 上推到顶了
else if (startY - tempY <= 0) {
state = DONE;
changeHeaderViewByState();
Log.e(TAG, "由DOne或者上拉刷新状态转变到done状态");
}
}
// done状态下
if (state == DONE) {
if (startY - tempY > 0) {
state = PULL_To_REFRESH;
changeHeaderViewByState();
}
}
// 更新headView的size
if (state == PULL_To_REFRESH) {
footView.setPadding(0, -1 * m_headContentHeight + (startY - tempY) / RATIO, 0, 0);
}
// 更新headView的paddingTop
if (state == RELEASE_To_REFRESH) {
footView.setPadding(0, 10, 0, 0);
}
}
headView.setPadding(0, -1 * headContentHeight , 0, 0);
}
public void updateHeadViewOnMove(int tempY) {
Log.e(TAG, "-------Head----OnMove-----------");
if (!isRecored && firstItemIndex == 0) {
Log.v(TAG, "在move时候记录下位置");
isRecored = true;
startY = tempY;
}
if (state != REFRESHING && isRecored && state != LOADING) {
// 保证在设置padding的过程中,当前的位置一直是在head,否则如果当列表超出屏幕的话,当在上推的时候,列表会同时进行滚动
// 可以松手去刷新了
if (state == RELEASE_To_REFRESH) {
setSelection(0);
// 往上推了,推到了屏幕足够掩盖head的程度,但是还没有推到全部掩盖的地步
if (((tempY - startY) / RATIO < headContentHeight) && (tempY - startY) > 0) {
state = PULL_To_REFRESH;
changeHeaderViewByState();
Log.v(TAG, "由松开刷新状态转变到下拉刷新状态");
}
// 一下子推到顶了
else if (tempY - startY <= 0) {
state = DONE;
changeHeaderViewByState();
Log.v(TAG, "由松开刷新状态转变到done状态");
}
// 往下拉了,或者还没有上推到屏幕顶部掩盖head的地步
else {
// 不用进行特别的操作,只用更新paddingTop的值就行了
}
}
// 还没有到达显示松开刷新的时候,DONE或者是PULL_To_REFRESH状态
if (state == PULL_To_REFRESH) {
setSelection(0);
// 下拉到可以进入RELEASE_TO_REFRESH的状态
if ((tempY - startY) / RATIO >= headContentHeight) {
state = RELEASE_To_REFRESH;
isBack = true;
changeHeaderViewByState();
Log.v(TAG, "由done或者下拉刷新状态转变到松开刷新");
}
// 上推到顶了
else if (tempY - startY <= 0) {
state = DONE;
changeHeaderViewByState();
Log.v(TAG, "由DOne或者下拉刷新状态转变到done状态");
}
}
// done状态下
if (state == DONE) {
if (tempY - startY > 0) {
state = PULL_To_REFRESH;
changeHeaderViewByState();
}
}
// 更新headView的size
if (state == PULL_To_REFRESH) {
headView.setPadding(0, -1 * headContentHeight + (tempY - startY) / RATIO, 0, 0);
}
// 更新headView的paddingTop
if (state == RELEASE_To_REFRESH) {
headView.setPadding(0, 10, 0, 0);
}
}
footView.setPadding(0, -1 * m_headContentHeight, 0, 0);
}
public interface OnRefreshListener {
public void onRefresh();
}
public void onRefreshComplete() {
if (mRefreshHead) {
state = DONE;
SimpleDateFormat format = new SimpleDateFormat("yyyy年MM月dd日 HH:mm");
String date = format.format(new Date());
lastUpdatedTextView.setText("最近更新:" + date);
} else {
state = DONE;
SimpleDateFormat format = new SimpleDateFormat("yyyy年MM月dd日 HH:mm");
String date = format.format(new Date());
m_lastUpdatedTextView.setText("最近更新:" + date);
}
changeHeaderViewByState();
}
private void onRefresh() {
if (mRefreshHead) {
if (refreshListener != null) {
refreshListener.onRefresh();
}
} else {
if (m_refreshListener != null) {
m_refreshListener.onRefresh();
}
}
}
// 此方法直接照搬自网络上的一个下拉刷新的demo,此处是“估计”headView的width以及height
private void measureView(View child) {
ViewGroup.LayoutParams p = child.getLayoutParams();
if (p == null) {
p = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
}
int childWidthSpec = ViewGroup.getChildMeasureSpec(0, 0 + 0, p.width);
int lpHeight = p.height;
int childHeightSpec;
if (lpHeight > 0) {
childHeightSpec = MeasureSpec.makeMeasureSpec(lpHeight, MeasureSpec.EXACTLY);
} else {
childHeightSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
}
child.measure(childWidthSpec, childHeightSpec);
}
public void setAdapter(BaseAdapter adapter) {
SimpleDateFormat format = new SimpleDateFormat("yyyy年MM月dd日 HH:mm");
String date = format.format(new Date());
if (mRefreshHead) {
lastUpdatedTextView.setText("最近更新:" + date);
} else {
m_lastUpdatedTextView.setText("最近更新:" + date);
}
super.setAdapter(adapter);
}
}
本文介绍了一个自定义的ListView组件,支持下拉刷新和上拉加载更多功能。通过改变头部视图的状态来提示用户操作,实现了不同状态间的平滑过渡。
852

被折叠的 条评论
为什么被折叠?



