首页 > 技术文章 > Android - 解决下拉刷新与滑动删除的冲突

hwgt 2016-04-18 13:43 原文

本篇文章是之前的两篇博文:模仿网易邮箱的滑动删除 和  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>

  

 

 

推荐阅读