Android - 解决下拉刷新与滑动删除的冲突
本篇文章是之前的两篇博文:模仿网易邮箱的滑动删除 和 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>