本篇文章是之前的两篇博文:模仿网易邮箱的滑动删除 和 Android - 下拉刷新 的总结,本篇文章在前两篇文章的基础上,对滑动删除进行了一定的优化,并且解决了下拉刷新和滑动删除的冲突,当然,这只是实际工作中写的一个demo,仅为实现主要功能。
以下是除图片资源之外的所有内容,首先是Demo结构图:
MainActivity.java:

public class MainActivity extends Activity implements OnRefreshListener{
private List<String> mList;
private HwgtAdapter mAdapter;
private HwgtListView mHwgtListView;
private static final int REFRESHSUCCESS = 3133;
private static final int LOADMORESUCCESS = 9198;
Handler mHandler = new Handler(){
public void handleMessage(Message msg) {
switch (msg.arg1) {
case REFRESHSUCCESS:
mAdapter.notifyDataSetChanged();
mHwgtListView.hideHeaderView();
break;
case LOADMORESUCCESS:
mAdapter.notifyDataSetChanged();
mHwgtListView.hideFooterView();
break;
default:
break;
}
};
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.activity_main);
findView();
initData();
}
private void findView() {
mHwgtListView = (HwgtListView) findViewById(R.id.refreshlistview);
mHwgtListView.setDividerHeight(0);
DisplayMetrics dm = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(dm);
mAdapter = new HwgtAdapter(this, dm.widthPixels, mHandler);
mHwgtListView.setAdapter(mAdapter);
mHwgtListView.setDivider(new ColorDrawable(R.color.gray_bg));
mHwgtListView.setDividerHeight(1/*CommInfo.dip2px(getApplicationContext(), 10)*/);
mHwgtListView.setOnRefreshListener(this);
}
private void initData() {
mList = new ArrayList<String>();
for (int i = 1; i < 11; i++) {
mList.add("原始 mList 的数据:第" + i+"条");
}
}
@Override
public void onDownPullRefresh() {
new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
for (int i = 1; i < 6; i++) {
mList.add("刷新出来的数据:第" + i+"条");
}
Message mMessage = Message.obtain();
mMessage.arg1 = REFRESHSUCCESS;
mHandler.sendMessage(mMessage);
}
}).start();
}
@Override
public void onLoadingMore() {
new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
for (int i = 1; i < 6; i++) {
mList.add("上拉加载的:第" + i+"条");
}
Message mMessage = Message.obtain();
mMessage.arg1 = LOADMORESUCCESS;
mHandler.sendMessage(mMessage);
}
}).start();
}
}
HwgtAdapter.java:
public class HwgtAdapter extends BaseAdapter {
private final int HSSHWGTSLIDHIDE = 0;
private final int HSSHWGTSLIDHALF = 1;
private final int HSSHWGTSLIDDISPLAY = 2;
/** hsHwgtSlid所在位置的标示,0为完全隐藏,1为显示一半,2为完全显示,默认为0 */
private int hsHwgtSlidPosition = HSSHWGTSLIDHIDE;
@SuppressWarnings("rawtypes")
public List mList;
private Context mContext;
/** 屏幕宽度 */
private int mScreentWidth;
/** 手指按下时的X坐标 */
private int mDownX;
/** 手指按下时的Y坐标 */
private int mDownY;
/** 手指移动时的X坐标 */
private int mMoveX;
/** 手指移动时的Y坐标 */
private int mMoveY;
/** 手指抬起时的X坐标 */
private int mUpX;
private View cacheView;
/** 判断手指是横向滑动还是纵向滑动的标示,true为横向滑动,false为纵向滑动 */
private boolean slideTransOrLongit;
/** 判断手指移动距离是否已到触发横向移动临界值的标示,true为已到,false为未到 */
private boolean slideTransverseTag;
/** 判断手指移动距离是否已到触发纵向移动临界值的标示,true为已到,false为未到 */
private boolean slideLongitudinalTag;
/** 是否需要做点击事件判断的标示,true为需要做,false为不需要做 */
private boolean judgeOnClickTag;
/** 删除按钮所在布局的宽度 */
private int delWidth;
@SuppressWarnings("rawtypes")
public HwgtAdapter(Context context, int screenWidth, Handler handler) {
mContext = context;
mScreentWidth = screenWidth;
mList = new ArrayList();
}
@Override
public int getCount() {
return 13/*mList.size()*/;
}
@Override
public Object getItem(int position) {
return mList.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@SuppressLint("ClickableViewAccessibility")
@Override
public View getView(final int position, View convertView, ViewGroup parent) {
final ViewHolder holder;
if (convertView == null) {
convertView = LayoutInflater.from(mContext).inflate(R.layout.list_item_hwgt_slid_del,
parent, false);
holder = new ViewHolder();
//删除按钮布局
holder.rlHwgtSlidDel = (RelativeLayout) convertView.findViewById(R.id.rl_hwgt_slid_del);
holder.ivHwgtSlidSet = (ImageView) convertView.findViewById(R.id.iv_hwgt_slid_set);
//滑动的整体布局
holder.hsHwgtSlid = (HorizontalScrollView) convertView.findViewById(R.id.hs_hwgt_slid_content);
holder.hsHwgtSlid.setTag(position);
holder.llHwgtSlidDelBgLeft = (LinearLayout) convertView.findViewById(R.id.ll_hwgt_slid_del_bg_left);
holder.llHwgtSlidDelBgRight = (LinearLayout) convertView.findViewById(R.id.ll_hwgt_slid_del_bg_right);
//滑动的内容布局
holder.llHwgtSlidContent = (LinearLayout) convertView.findViewById(R.id.ll_hwgt_slid_content);
// 设置llHwgtSlidContent的宽度为屏幕宽度,这样llHwgtSlidDelBg就正好被挤出屏幕外
LayoutParams lp = holder.llHwgtSlidContent.getLayoutParams();
lp.width = mScreentWidth;
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
// 删除按钮布局宽度
delWidth = holder.rlHwgtSlidDel.getWidth();
holder.hsHwgtSlid.setOnTouchListener(new OnTouchListener() {
@Override
public boolean onTouch(View view, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
//ACTION_DOWN里的逻辑主要是将一些变量和布局状态设置为默认值以及获取X和Y坐标
judgeOnClickTag = true;
slideTransverseTag = false;
slideLongitudinalTag = false;
mDownX = (int) event.getX();
mDownY = (int) event.getY();
int screenDownY = (int) event.getRawY();
HwgtListView.intDownX = mDownX;
HwgtListView.intDownY = mDownY;
HwgtListView.upOrDownStandard = screenDownY;
Log.d("HWGTXS", "ACTION_DOWN..mDownX..=.." + mDownX + "..mDownY..=.." + mDownY);
if (cacheView != null && cacheView != view) {
((HorizontalScrollView) cacheView).smoothScrollTo(0, 0);
hsHwgtSlidPosition = HSSHWGTSLIDHIDE;
holder.llHwgtSlidDelBgLeft.setVisibility(View.VISIBLE);
holder.llHwgtSlidDelBgRight.setVisibility(View.GONE);
holder.ivHwgtSlidSet.setImageResource(R.drawable.iv_hwgt_slid_guide);
return false;
}
if(hsHwgtSlidPosition == HSSHWGTSLIDHIDE){
holder.llHwgtSlidDelBgLeft.setVisibility(View.VISIBLE);
holder.llHwgtSlidDelBgRight.setVisibility(View.GONE);
}else{
holder.llHwgtSlidDelBgLeft.setVisibility(View.VISIBLE);
holder.llHwgtSlidDelBgRight.setVisibility(View.VISIBLE);
}
return true;
case MotionEvent.ACTION_MOVE:
mMoveX = (int) event.getX();
mMoveY = (int) event.getY();
Log.d("HWGTXS", "ACTION_MOVE..mMoveX..=.." + mMoveX + "..mMoveY..=.." + mMoveY);
// 如果手指是纵向移动,直接返回true
if (Math.abs(mMoveY - mDownY) >= 5 && !slideTransverseTag) {
slideLongitudinalTag = true;
slideTransOrLongit = false;
judgeOnClickTag = false;
return true;
}
// 如果是横向滑动,则处理滑动删除逻辑
if (Math.abs(mMoveX - mDownX) >= 5 && !slideLongitudinalTag) {
slideTransverseTag = true;
slideTransOrLongit = true;
judgeOnClickTag = false;
}
// 删除按钮布局宽度
delWidth = holder.rlHwgtSlidDel.getWidth();
int X = holder.hsHwgtSlid.getScrollX();
return false;
case MotionEvent.ACTION_UP:
cacheView = view;
mUpX = (int) event.getX();
Log.d("HWGTXS", "ACTION_UP..mUpX..=.." + mUpX);
if (judgeOnClickTag) {
// 删除按钮布局宽度
delWidth = holder.rlHwgtSlidDel.getWidth();
if (hsHwgtSlidPosition == HSSHWGTSLIDHIDE) {
//响应item的点击事件
Toast.makeText(mContext, "点击item了!", Toast.LENGTH_SHORT).show();
}
if(hsHwgtSlidPosition == HSSHWGTSLIDHALF){
if (mUpX > mScreentWidth - delWidth) {
Toast.makeText(mContext, "点击删除了!", Toast.LENGTH_SHORT).show();
}
if (mUpX > mScreentWidth - delWidth*2 && mUpX < mScreentWidth - delWidth) {
Toast.makeText(mContext.getApplicationContext(), "点击展开了!",
Toast.LENGTH_SHORT).show();
holder.ivHwgtSlidSet.setImageResource(R.drawable.iv_hwgt_slid_set);
holder.hsHwgtSlid.smoothScrollTo(delWidth*4, 0);
hsHwgtSlidPosition = HSSHWGTSLIDDISPLAY;
}
}
if(hsHwgtSlidPosition == HSSHWGTSLIDDISPLAY){
if (mUpX > mScreentWidth - delWidth) {
Toast.makeText(mContext, "点击删除了!", Toast.LENGTH_SHORT).show();
}
if (mUpX > mScreentWidth - delWidth*2 && mUpX < mScreentWidth - delWidth) {
Toast.makeText(mContext.getApplicationContext(), "点击设置了!",
Toast.LENGTH_SHORT).show();
}
if (mUpX > mScreentWidth - delWidth*3 && mUpX < mScreentWidth - delWidth*2) {
Toast.makeText(mContext, "点击分享了!", Toast.LENGTH_SHORT).show();
}
if (mUpX > mScreentWidth - delWidth*4 && mUpX < mScreentWidth - delWidth*3) {
Toast.makeText(mContext, "点击标记了!", Toast.LENGTH_SHORT).show();
}
}
}
if (slideTransOrLongit && !judgeOnClickTag) {
// 获得HorizontalScrollView水平方向的滑动距离
int scrollX = holder.hsHwgtSlid.getScrollX();
delWidth = holder.rlHwgtSlidDel.getWidth();
if(hsHwgtSlidPosition == HSSHWGTSLIDHIDE){
if (scrollX < delWidth / 2) {
holder.hsHwgtSlid.smoothScrollTo(0, 0);
hsHwgtSlidPosition = HSSHWGTSLIDHIDE;
holder.llHwgtSlidDelBgLeft.setVisibility(View.VISIBLE);
holder.llHwgtSlidDelBgRight.setVisibility(View.GONE);
holder.ivHwgtSlidSet.setImageResource(R.drawable.iv_hwgt_slid_guide);
} else {
holder.hsHwgtSlid.smoothScrollTo(delWidth*2, 0);
hsHwgtSlidPosition = HSSHWGTSLIDHALF;
holder.llHwgtSlidDelBgLeft.setVisibility(View.VISIBLE);
holder.llHwgtSlidDelBgRight.setVisibility(View.VISIBLE);
}
return true;
}
if(hsHwgtSlidPosition == HSSHWGTSLIDHALF){
if (scrollX > delWidth*2) {
holder.hsHwgtSlid.smoothScrollTo(delWidth*4, 0);
hsHwgtSlidPosition = HSSHWGTSLIDDISPLAY;
holder.llHwgtSlidDelBgLeft.setVisibility(View.VISIBLE);
holder.llHwgtSlidDelBgRight.setVisibility(View.VISIBLE);
holder.ivHwgtSlidSet.setImageResource(R.drawable.iv_hwgt_slid_set);
}
if (scrollX < delWidth*2) {
holder.hsHwgtSlid.smoothScrollTo(0, 0);
hsHwgtSlidPosition = HSSHWGTSLIDHIDE;
holder.llHwgtSlidDelBgLeft.setVisibility(View.VISIBLE);
holder.llHwgtSlidDelBgRight.setVisibility(View.VISIBLE);
holder.ivHwgtSlidSet.setImageResource(R.drawable.iv_hwgt_slid_guide);
}
return true;
}
if(hsHwgtSlidPosition == HSSHWGTSLIDDISPLAY){
if (scrollX < delWidth*4) {
holder.hsHwgtSlid.smoothScrollTo(0, 0);
hsHwgtSlidPosition = HSSHWGTSLIDHIDE;
holder.llHwgtSlidDelBgLeft.setVisibility(View.VISIBLE);
holder.llHwgtSlidDelBgRight.setVisibility(View.VISIBLE);
holder.ivHwgtSlidSet.setImageResource(R.drawable.iv_hwgt_slid_guide);
}
return true;
}
} else {
return true;
}
}
return true;
}
});
return convertView;
}
class ViewHolder {
//删除按钮布局
private RelativeLayout rlHwgtSlidDel;
private ImageView ivHwgtSlidSet;
//滑动的整体布局
private HorizontalScrollView hsHwgtSlid;
//滑动的内容布局
private LinearLayout llHwgtSlidContent;
//透明布局左
private LinearLayout llHwgtSlidDelBgLeft;
//透明布局右
private LinearLayout llHwgtSlidDelBgRight;
}
}
HwgtListView.java:
public class HwgtListView extends ListView implements OnScrollListener{
private final int NO_PULL_REFRESH = 0; // headerView没有下拉或是还没有完全可见的状态(footer对应上拉)
private final int DOWN_PULL_REFRESH = 1; // headerView下拉刷新状态(footer上拉加载)
private final int RELEASE_REFRESH = 2; // headerView松开刷新状态(footer松开加载更多)
private final int REFRESHING = 3; // headerView正在刷新中(footer正在加载中)
private int headerCurrentState = NO_PULL_REFRESH; // headerView当前状态,默认为NO_PULL_REFRESH
private int footerCurrentState = NO_PULL_REFRESH; // footerView当前状态,默认为NO_PULL_REFRESH
private View headerView; // headerView
private ImageView ivArrow; // headerView的箭头
private ProgressBar mHeaderProgressBar; // headerView的ProgressBar
private TextView tvHeaderState; // headerView的下拉状态提示
private Animation upAnimation; // 向上旋转的动画
private Animation downAnimation; // 向下旋转的动画
private boolean pullRefreshAnimationTag; // 进入下拉刷新状态是否需要执行动画的标识
private boolean refreshDownAnimationTag; // 保证下拉刷新状态动画只执行一次的标识
private boolean refreshUpAnimationTag; // 保证松开刷新状态动画只执行一次的标识
private int headerViewHeight; // headerView的高度
private boolean isReachTheTop; // 判断listview是否滑动到顶部
private int headerUpStartingPoint; // headerView向上滑动的起点
private int headerDownStartingPoint; // headerView向下滑动的起点
private boolean headerScrollUpTag; // 保证headerView上滑起点坐标的唯一性
private boolean headerScrollDownTag; // 保证headerView下滑起点坐标的唯一性
private int headerTempPaddingTop; // headerView的底部距离屏幕顶端的距离
private int headerPaddingTop; // headerView的顶部距离屏幕顶端的距离
private int headerTempUpPaddingTop; // 上滑时的headerTempPaddingTop起点值
private int headerTempDownPaddingTop; // 下滑时的headerTempPaddingTop起点值
private View footerView; // footerView
private ProgressBar mFooterProgressBar; // footerView的ProgressBar
private TextView tvFooterState; // footerView的下拉状态提示
private int footerViewHeight; // footerView的高度
private boolean isReachTheBottom; // 判断listview是否滑动到底部
private int footerUpStartingPoint; // footerView向上滑动的起点
private int footerDownStartingPoint; // footerView向下滑动的起点
private boolean footerScrollUpTag; // 保证footerView上滑起点坐标的唯一性
private boolean footerScrollDownTag; // 保证footerView下滑起点坐标的唯一性
private int footerTempPaddingBottom; // footerView的顶部距离屏幕底端的距离
private int footerPaddingBottom; // footerView的底部距离屏幕底端的距离
private int footerTempUpPaddingBottom; // 上滑时的footerTempPaddingBottom起点值
private int footerTempDownPaddingBottom; // 下滑时的footerTempPaddingBottom起点值
public static int intDownX; // 手指接触屏幕时的X坐标值
public static int intDownY; // 手指接触屏幕时的Y坐标值
private int mMoveX; // 滑动过程中手指的X坐标值
private int mMoveY; // 滑动过程中手指的Y坐标值
/** (当headerView完全显示之后)paddingTop大于这个距离才可以松开刷新
* (当footerView完全显示之后)paddingBottom大于这个距离才可以松开加载更多 */
private int refreshDistance;
/** 用来标识listview是向上还是向下滑动 true为向下滑动,false为向上滑动*/
private boolean scrollUpOrDownTag;
/** 该变量用来 记录一次move时手指的Y坐标值 并和 上一次move所得到的Y坐标值 进行比对
* 以确定listview是向上还是向下滑动(即确定scrollUpOrDownTag的值),同时,向上和向下
* 滑动的起点的Y坐标值也取自该变量*/
public static int upOrDownStandard;
private int firstVisibleItemPosition; // 屏幕显示在第一个的item的索引
private OnRefreshListener mOnRefershListener; // listview的刷新监听
public HwgtListView(Context context, AttributeSet attrs) {
super(context, attrs);
initHeaderView();
initFooterView();
setOnScrollListener(this);
initData();
initAnimation();
}
private void initHeaderView() {
headerView = View.inflate(getContext(), R.layout.hwgtlistview_header, null);
ivArrow = (ImageView) headerView.findViewById(R.id.iv_hwgtlistview_header_arrow);
mHeaderProgressBar = (ProgressBar) headerView.findViewById(R.id.pb_hwgtlistview_header_bar);
tvHeaderState = (TextView) headerView.findViewById(R.id.tv_hwgtlistview_header_state);
headerView.measure(0, 0);
headerViewHeight = headerView.getMeasuredHeight();
headerView.setPadding(0, -headerViewHeight, 0, 0);
addHeaderView(headerView); // 将headerView添加到ListView的顶部
headerCurrentState = NO_PULL_REFRESH; // 设置headerView的当前状态为默认状态
}
private void initFooterView() {
footerView = View.inflate(getContext(), R.layout.refresh_listview_footer, null);
mFooterProgressBar = (ProgressBar) footerView.findViewById(R.id.pull_to_load_footer_progressbar);
tvFooterState = (TextView) footerView.findViewById(R.id.pull_to_load_footer_hint_textview);
footerView.measure(0, 0);
footerViewHeight = footerView.getMeasuredHeight();
footerView.setPadding(0,0,0,-footerViewHeight);
addFooterView(footerView);// 将footerView添加到ListView的底部
footerCurrentState = NO_PULL_REFRESH; // 设置footerView的当前状态为默认状态
}
private void initData() {
//(当headerView完全显示之后)paddingTop大于这个距离才可以松开刷新
refreshDistance = ViewConfiguration.get(getContext()).getScaledTouchSlop() * 2;
}
private void initAnimation() {
upAnimation = new RotateAnimation(0f, -180f, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
upAnimation.setDuration(500);
upAnimation.setFillAfter(true); // 动画结束后, 停留在结束的位置上
downAnimation = new RotateAnimation(-180f, -360f, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
downAnimation.setDuration(500);
downAnimation.setFillAfter(true); // 动画结束后, 停留在结束的位置上
}
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
//如果处于正在刷新或正在加载状态,则listview不可滑动
if (headerCurrentState == REFRESHING || footerCurrentState == REFRESHING) {
return true;
}
return super.dispatchTouchEvent(ev);
}
@Override
public boolean onTouchEvent(MotionEvent ev) {
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
intDownX = (int) ev.getX();
intDownY = (int) ev.getY();//手指按下时的Y坐标值
upOrDownStandard = intDownY;//设置upOrDownStandard的初始值
headerCurrentState = NO_PULL_REFRESH;
Log.d("HWGTXP", "ACTION_DOWN..intDownX..=.." + intDownX + "..mDownY..=.." + intDownY);
break;
case MotionEvent.ACTION_MOVE:
mMoveX = (int) ev.getX();
mMoveY = (int) ev.getY();//在移动过程中,获取手指纵坐标的值
//确定listview是在向上还是向下滑动,该部分逻辑headerView和footerView共用
if (upOrDownStandard < mMoveY) {
scrollUpOrDownTag = true; //向下滑动
}
if (upOrDownStandard > mMoveY) {
scrollUpOrDownTag = false; //向上滑动
}
//确定向下滑动的起点,仅适用于headerView
if (scrollUpOrDownTag && isReachTheTop) {
if (!headerScrollDownTag) {
headerDownStartingPoint = upOrDownStandard;
}
headerScrollDownTag = true;
headerScrollUpTag = false;
}
//确定向上滑动的起点,仅适用于headerView
if (!scrollUpOrDownTag) {
if (!headerScrollUpTag) {
headerUpStartingPoint = upOrDownStandard;
}
headerScrollUpTag = true;
headerScrollDownTag = false;
}
//确定向下滑动的起点,仅适用于footerView
if (scrollUpOrDownTag) {
if (!footerScrollDownTag) {
footerDownStartingPoint = upOrDownStandard;
}
footerScrollDownTag = true;
footerScrollUpTag = false;
}
//确定向上滑动的起点,仅适用于footerView(并且是滑动到底部时)
if (!scrollUpOrDownTag && isReachTheBottom) {
if (!footerScrollUpTag) {
footerUpStartingPoint = upOrDownStandard;
}
footerScrollUpTag = true;
footerScrollDownTag = false;
}
upOrDownStandard = mMoveY;//headerView和footerView共用
//不论是向上还是向下滑动,ACTION_MOVE发生时对headerView的处理逻辑都仅限于在listview的第一个item可见时
if (firstVisibleItemPosition == 0) {
Log.d("HWGTXP", "现在是 : " + (scrollUpOrDownTag ? "向下滑动" : "向上滑动"));
if (scrollUpOrDownTag) { //如果是向下滑动,则
headerTempPaddingTop = (int) (headerTempDownPaddingTop + (mMoveY - headerDownStartingPoint) / 2.5);
headerTempUpPaddingTop = headerTempPaddingTop;
} else {//如果是向上滑动,则
if (headerTempPaddingTop > 0) {//向上滑动时,只在headerTempPaddingTop > 0 的情况下进行计算
headerTempPaddingTop = headerTempUpPaddingTop - (headerUpStartingPoint - mMoveY);
headerTempDownPaddingTop = headerTempPaddingTop;
}
}
headerPaddingTop = headerTempPaddingTop - headerViewHeight;
headerView.setPadding(0, headerPaddingTop, 0, 0);//设置headerView的位置
if (headerPaddingTop < 0) {
headerCurrentState = NO_PULL_REFRESH;
}
if (headerPaddingTop >= 0 && headerPaddingTop < refreshDistance) {//根据paddingTop处理相关逻辑
//当headerView完全显示,但手指移动距离还不足以导致松开刷新时,更改状态为下拉刷新
headerCurrentState = DOWN_PULL_REFRESH;
refreshUpAnimationTag = false;
//第一次处于下拉刷新状态是不需要执行动画的
if (pullRefreshAnimationTag) {
if (!refreshDownAnimationTag) {
//为了保证downAnimation动画在进入DOWN_PULL_REFRESH的状态下只执行一次
refreshDownAnimationTag = true;
tvHeaderState.setText("下拉刷新");
ivArrow.startAnimation(downAnimation);
}
}
pullRefreshAnimationTag = false;
return true;
} else if (headerPaddingTop >= refreshDistance) {
//当headerView完全显示,并且手指移动距离足以导致松开刷新时,更改状态为松开刷新
headerCurrentState = RELEASE_REFRESH;
refreshDownAnimationTag = false;
pullRefreshAnimationTag = true;
if (!refreshUpAnimationTag) {
//为了保证upAnimation动画在进入RELEASE_REFRESH的状态下只执行一次
refreshUpAnimationTag = true;
tvHeaderState.setText("松开刷新");
ivArrow.startAnimation(upAnimation);
}
return true;
} else {
//代表没有下拉或是headerView还没有完全可见的状态
headerCurrentState = NO_PULL_REFRESH;
pullRefreshAnimationTag = false;
refreshDownAnimationTag = false;
if (headerPaddingTop < 0 && -headerPaddingTop < headerViewHeight) {
return true;
}
}
}
//不论是向上还是向下滑动,ACTION_MOVE发生时对footerView的处理逻辑都仅限于在listview滑动到最底部时
if(isReachTheBottom){
if (scrollUpOrDownTag) { //如果是向下滑动,则
if (footerTempPaddingBottom > 0) {//向下滑动时,只在footerTempPaddingBottom > 0 的情况下进行计算
footerTempPaddingBottom = footerTempUpPaddingBottom - (mMoveY - footerDownStartingPoint);
footerTempDownPaddingBottom = footerTempPaddingBottom;
}
} else {//如果是向上滑动,则
footerTempPaddingBottom = (int) (footerTempDownPaddingBottom + (footerUpStartingPoint-mMoveY) / 2.5);
footerTempUpPaddingBottom = footerTempPaddingBottom;
}
footerPaddingBottom = footerTempPaddingBottom - footerViewHeight;
footerView.setPadding(0, 0, 0, footerPaddingBottom);//设置footerView的位置
if (footerPaddingBottom < 0) {
footerCurrentState = NO_PULL_REFRESH;
mFooterProgressBar.setVisibility(View.GONE);
tvFooterState.setText("上拉加载");
}
if (footerPaddingBottom >= 0 && footerPaddingBottom < refreshDistance) {
//当footerView完全显示,但手指移动距离还不足以导致松开加载更多时,更改状态为上拉加载
footerCurrentState = DOWN_PULL_REFRESH;
mFooterProgressBar.setVisibility(View.GONE);
tvFooterState.setText("上拉加载");
// return true;
} else if (footerPaddingBottom >= refreshDistance) {
//当footerView完全显示,并且footerPaddingBottom >= refreshDistance时,更改状态为松开加载更多
footerCurrentState = RELEASE_REFRESH;
mFooterProgressBar.setVisibility(View.GONE);
tvFooterState.setText("松开加载更多");
// return true;
} else {
//代表没有上拉或是footerView还没有完全可见的状态
footerCurrentState = NO_PULL_REFRESH;
}
}
break;
case MotionEvent.ACTION_UP:
if (headerCurrentState == RELEASE_REFRESH && firstVisibleItemPosition == 0) {
// 把headerView设置为完全显示状态
headerView.setPadding(0, 0, 0, 0);
// 进入到正在刷新中状态
headerCurrentState = REFRESHING;
ivArrow.clearAnimation();
ivArrow.setVisibility(View.GONE);
mHeaderProgressBar.setVisibility(View.VISIBLE);
tvHeaderState.setText("正在刷新中...");
if (mOnRefershListener != null) {
mOnRefershListener.onDownPullRefresh();
}
} else if (headerCurrentState == DOWN_PULL_REFRESH || headerCurrentState == NO_PULL_REFRESH) {
headerView.setPadding(0, -headerViewHeight, 0, 0);// 隐藏headerView
}
headerScrollUpTag = false;
headerScrollDownTag = false;
headerTempDownPaddingTop = 0;
headerTempUpPaddingTop = 0;
if (footerCurrentState == RELEASE_REFRESH && isReachTheBottom) {
// 把footerView设置为完全显示状态
footerView.setPadding(0, 0, 0, 0);
// 进入到正在加载中状态
footerCurrentState = REFRESHING;
mFooterProgressBar.setVisibility(View.VISIBLE);
tvFooterState.setText("正在加载中...");
if (mOnRefershListener != null) {
mOnRefershListener.onLoadingMore();
}
} else if (footerCurrentState == DOWN_PULL_REFRESH || footerCurrentState == NO_PULL_REFRESH) {
footerView.setPadding(0, -footerViewHeight, 0, 0);// 隐藏footerView
}
isReachTheBottom = false;
footerTempUpPaddingBottom = 0;
footerTempDownPaddingBottom = 0;
break;
default:
break;
}
return super.onTouchEvent(ev);
}
public void setOnRefreshListener(OnRefreshListener listener) {
mOnRefershListener = listener;
}
public void hideHeaderView() {
headerView.setPadding(0, -headerViewHeight, 0, 0);
ivArrow.setVisibility(View.VISIBLE);
mHeaderProgressBar.setVisibility(View.GONE);
tvHeaderState.setText("下拉刷新");
headerCurrentState = NO_PULL_REFRESH;
}
public void hideFooterView() {
footerView.setPadding(0, -footerViewHeight, 0, 0);
mFooterProgressBar.setVisibility(View.GONE);
tvFooterState.setText("上拉加载");
footerCurrentState = NO_PULL_REFRESH;
}
@SuppressLint("SimpleDateFormat")
@Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
firstVisibleItemPosition = firstVisibleItem;
if (firstVisibleItem == 0) {
View firstView = getChildAt(firstVisibleItem);
if (firstView != null) {
isReachTheTop = true;
}
} else {
isReachTheTop = false;
}
if(visibleItemCount+firstVisibleItem==totalItemCount){
Log.d("HWGTXPP", "滚动到最后一个item了.....呵呵...");
isReachTheBottom = true;
}else{
Log.d("HWGTXPP", "还在滚.....呵呵...");
isReachTheBottom = false;
}
}
@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
switch (scrollState) {
// 当不滚动时
case OnScrollListener.SCROLL_STATE_IDLE:
if (view.getLastVisiblePosition() == (view.getCount() - 1)) {
Log.d("HWGTXPP", "滚动到最后一个item了........");
}
break;
// 当正在滚动时
case OnScrollListener.SCROLL_STATE_TOUCH_SCROLL:
if (view.getLastVisiblePosition() == (view.getCount() - 1)) {
Log.d("HWGTXPP", "滚动到最后一个item了.....嗷呜...");
}
break;
case OnScrollListener.SCROLL_STATE_FLING:
if (view.getLastVisiblePosition() == (view.getCount() - 1)) {
Log.d("HWGTXPP", "滚动到最后一个item了.....卧槽...");
}
break;
}
}
}
OnRefreshListener.java:
public interface OnRefreshListener {
/**下拉刷新*/
void onDownPullRefresh();
/**上拉加载更多*/
void onLoadingMore();
}
/HwgtPullToRefresh/res/layout/activity_main.xml:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.hwgt.hwgtpulltorefresh.MainActivity" >
<com.hwgt.hwgtpulltorefresh.view.HwgtListView
android:id="@+id/refreshlistview"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scrollbars="none">
</com.hwgt.hwgtpulltorefresh.view.HwgtListView>
</RelativeLayout>
/HwgtPullToRefresh/res/layout/hwgtlistview_header.xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_marginBottom="13dp">
<FrameLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="13dp"
android:layout_marginLeft="13dp">
<ImageView
android:id="@+id/iv_hwgtlistview_header_arrow"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:minWidth="31dp"
android:src="@drawable/common_listview_headview_red_arrow" />
<ProgressBar
android:id="@+id/pb_hwgtlistview_header_bar"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:indeterminateDrawable="@drawable/common_progressbar"
android:visibility="gone" />
</FrameLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:gravity="center_horizontal"
android:orientation="vertical" >
<TextView
android:id="@+id/tv_hwgtlistview_header_state"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="下拉刷新"
android:textColor="#FF0000"
android:textSize="15dp" />
<TextView
android:id="@+id/tv_hwgtlistview_header_last_update_time"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="5dp"
android:text="最后刷新时间: 2014-10-10 12:56:12"
android:textColor="#f09c42"
android:textSize="15dp" />
</LinearLayout>
</LinearLayout>
</LinearLayout>
/HwgtPullToRefresh/res/layout/list_item_hwgt_slid_del.xml:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/rl_hwgt_slid_del_item"
android:layout_width="match_parent"
android:layout_height="87dp"
android:background="#ffffff">
<LinearLayout
android:id="@+id/ll_hwgt_slid_setting"
android:layout_width="268dp"
android:layout_height="match_parent"
android:layout_alignParentRight="true"
android:orientation="horizontal">
<RelativeLayout
android:id="@+id/rl_hwgt_slid_tagging"
android:layout_width="67dp"
android:layout_height="match_parent"
android:orientation="vertical"
android:background="#808a87">
<ImageView
android:id="@+id/iv_hwgt_slid_tagging"
android:layout_width="31dp"
android:layout_height="31dp"
android:layout_centerInParent="true"
android:src="@drawable/iv_hwgt_slid_tagging"/>
</RelativeLayout>
<RelativeLayout
android:id="@+id/rl_hwgt_slid_share"
android:layout_width="67dp"
android:layout_height="match_parent"
android:orientation="vertical"
android:background="#c0c0c0">
<ImageView
android:id="@+id/iv_hwgt_slid_share"
android:layout_width="31dp"
android:layout_height="31dp"
android:layout_centerInParent="true"
android:src="@drawable/iv_hwgt_slid_share"/>
</RelativeLayout>
<RelativeLayout
android:id="@+id/rl_hwgt_slid_set"
android:layout_width="67dp"
android:layout_height="match_parent"
android:orientation="vertical"
android:background="#f5f5f5">
<ImageView
android:id="@+id/iv_hwgt_slid_set"
android:layout_width="31dp"
android:layout_height="31dp"
android:layout_centerInParent="true"
android:src="@drawable/iv_hwgt_slid_guide"/>
</RelativeLayout>
<RelativeLayout
android:id="@+id/rl_hwgt_slid_del"
android:layout_width="67dp"
android:layout_height="match_parent"
android:orientation="vertical"
android:background="#e51515">
<ImageView
android:id="@+id/iv_hwgt_slid_del"
android:layout_width="31dp"
android:layout_height="31dp"
android:layout_centerInParent="true"
android:src="@drawable/iv_hwgt_slid_del"/>
</RelativeLayout>
</LinearLayout>
<HorizontalScrollView
android:id="@+id/hs_hwgt_slid_content"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:scrollbars="none">
<LinearLayout
android:id="@+id/ll_hwgt_slid_del_top"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_alignParentLeft="true"
android:orientation="horizontal">
<LinearLayout
android:id="@+id/ll_hwgt_slid_content"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:background="#ffffffff">
<TextView
android:id="@+id/tv_hwgt_slid_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="9dp"
android:paddingLeft="19dp"
android:paddingRight="19dp"
android:singleLine="true"
android:textSize="17dp"
android:textColor="#222222"
android:gravity="center_vertical"
android:text="网易邮件中心"/>
<TextView
android:id="@+id/tv_hwgt_slid_content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="3dp"
android:paddingLeft="19dp"
android:paddingRight="19dp"
android:textSize="13dp"
android:textColor="#666666"
android:maxLines="3"
android:ellipsize="start"
android:gravity="center_vertical|left"
android:text="1000万春运红包大放送,快来领取啊!!!"/>
<TextView
android:id="@+id/tv_hwgt_slid_info"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:paddingLeft="19dp"
android:paddingRight="19dp"
android:layout_marginTop="7dp"
android:textSize="13dp"
android:textColor="#999999"
android:text="2015-08-25 11:36"/>
</LinearLayout>
<LinearLayout
android:id="@+id/ll_hwgt_slid_del_bg_left"
android:layout_width="134dp"
android:layout_height="match_parent"
android:background="#00000000"
android:orientation="vertical"/>
<LinearLayout
android:id="@+id/ll_hwgt_slid_del_bg_right"
android:layout_width="134dp"
android:layout_height="match_parent"
android:background="#00000000"
android:orientation="vertical"/>
</LinearLayout>
</HorizontalScrollView>
</RelativeLayout>
/HwgtPullToRefresh/res/layout/refresh_listview_footer.xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/pull_to_load_footer_content"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:gravity="center">
<View
android:layout_width="fill_parent"
android:layout_height="0.5dp"
android:background="@color/background_gray"/>
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="48dp"
android:orientation="horizontal"
android:gravity="center">
<ProgressBar
android:id="@+id/pull_to_load_footer_progressbar"
style="?android:attr/progressBarStyleSmall"
android:layout_width="28dp"
android:layout_height="28dp"
android:visibility="invisible"/>
<TextView
android:id="@+id/pull_to_load_footer_hint_textview"
android:layout_width="wrap_content"
android:layout_height="48dp"
android:layout_marginLeft="6dp"
android:gravity="center_vertical"
android:text=""
android:textColor="#999999"
android:textSize="14dp"/>
</LinearLayout>
</LinearLayout>