android qq下拉菜单样式,Android仿qq下拉刷新及向左滑动列表----PullToRefresh, SwipeMenuListView开源项目整合...

若是项目对您有帮助,欢迎小伙伴们在github上Star个人项目~

git

PullToRefresh是一个很是完美的下拉刷新的开源项目,SwipeMenuListView是一个向左滑动ListView中item实现能够删除功能的开源项目。笔者在此将两套开源项目整合造成一套,相似于手机qq那样同时支持下拉刷新和向左滑动的列表。效果以下:github

de5e25932e8c4eec9a69a201.html

两套框架整合的关键在于对Touch事件处理的把握,Touch事件的处理主要由Action_Down, Action_Move,Action_Up组成。Action_Down表示用户按下屏幕的操做,Action_Up表示用户按下屏幕后抬起的操做,Action_Move表示用户在屏幕上的移动操做。Touch事件处理流程图以下:框架

364c97ba9697afaff1902adcec971519.png

1.      当ACTION_UP事件生效的时候,判断若是是下拉操做,执行onRefresh(), 实现下拉刷新,而后执行resetHeaderHeight()恢复Header的高度;判断若是是上拉操做,当mFooterView的高度大于自定义的高度,那么就执行startLoadMore()加载更多,而后执行resetFooterHeight()恢复Footer的高度。判断若是是侧滑那么就结束SwipeMenu的滑动。异步

2.      当ACTION_MOVE事件生效的时候,分别记录X,Y方向上的偏移。若是是X方向上的偏移,那么对应的就是SwipeMenuListView的特效操做;若是是Y方向上的偏移, Y方向向下,那么对应的就是下拉刷新操做,Y方向向上,那么对应的就是上拉操做。ide

Touch事件相关代码以下:spa

@Override

public boolean onTouchEvent(MotionEvent ev) {

if (mLastY == -1) {

mLastY = ev.getRawY();

}

switch (ev.getAction()) {

case MotionEvent.ACTION_DOWN:

mLastY = ev.getRawY();

int oldPos = mTouchPosition;

mDownX = ev.getX();

mDownY = ev.getY();

mTouchState = TOUCH_STATE_NONE;

mTouchPosition = pointToPosition((int) ev.getX(), (int) ev.getY());

if (mTouchPosition == oldPos && mTouchView != null && mTouchView.isOpen()) {

mTouchState = TOUCH_STATE_X;

mTouchView.onSwipe(ev);

return true;

}

View view = getChildAt(mTouchPosition - getFirstVisiblePosition());

if (mTouchView != null && mTouchView.isOpen()) {

mTouchView.smoothCloseMenu();

mTouchView = null;

return super.onTouchEvent(ev);

}

if (view instanceof SwipeMenuLayout) {

mTouchView = (SwipeMenuLayout) view;

}

if (mTouchView != null) {

mTouchView.onSwipe(ev);

}

break;

case MotionEvent.ACTION_MOVE:

final float deltaY = ev.getRawY() - mLastY;

mLastY = ev.getRawY();

// 很是感谢github上面的G友提出的宝贵建议和启发,这个地方要作一个判断。

// 在侧滑的过程中不该该同时出现用户本不指望的下拉操做,

// 这样会给用户带来一种很不稳定的感觉,是一种很是槽糕的用户体验。

// Modified on 9/16/2015

if (mTouchView == null || !mTouchView.isActive()) {

// 这个地方调换了if和else if的顺序,若是反过来会出现有时没法下拉刷新的bug

// Modified on 9/17/2015

if (getFirstVisiblePosition() == 0 && (mHeaderView.getVisiableHeight() > 0 || deltaY > 0)) {

// the first item is showing, header has shown or pull down.

updateHeaderHeight(deltaY / OFFSET_RADIO);

invokeOnScrolling();

} else if ((mFooterView.getBottomMargin() > 0 || deltaY < 0)) {

// last item, already pulled up or want to pull up.

updateFooterHeight(-deltaY / OFFSET_RADIO);

}

}

float dy = Math.abs((ev.getY() - mDownY));

float dx = Math.abs((ev.getX() - mDownX));

if (mTouchState == TOUCH_STATE_X) {

if (mTouchView != null) {

mTouchView.onSwipe(ev);

}

getSelector().setState(new int[] { 0 });

ev.setAction(MotionEvent.ACTION_CANCEL);

super.onTouchEvent(ev);

return true;

} else if (mTouchState == TOUCH_STATE_NONE) {

if (Math.abs(dy) > MAX_Y) {

mTouchState = TOUCH_STATE_Y;

} else if (dx > MAX_X) {

mTouchState = TOUCH_STATE_X;

if (mOnSwipeListener != null) {

mOnSwipeListener.onSwipeStart(mTouchPosition);

}

}

}

break;

// default:

// 很是感谢博友私信提出的修改意见,这个地方不该该写default,若是写成default的话,

// ACTION_POINTER_DOWN和ACTION_POINTER_UP事件也会执行下面的语句,

// 这样就会出现两个bug:

// 1.当下拉未松开时,屏幕上有其它点按下,下拉状态会变成松开;

// 2.当向左滑动列表的时候,屏幕上有其它点按下,再所有松开,滑出的列表会停在中间状态.

// Modified on 8/26/2015

case MotionEvent.ACTION_UP:

mLastY = -1; // reset

if (mEnablePullLoad && mFooterView.getBottomMargin() > PULL_LOAD_MORE_DELTA) {

startLoadMore();

resetFooterHeight();

// 再次感谢同一位博友的来信提出的新的bug

// 这个地方应该在加一个以下所示的resetHeaderHeight()异步操做,

// 若是不加这个操做的话,会致使下拉接着上拉后,刷新的Header卡住不动的情况,

// 因为resetHeaderHeight()和resetFooterHeight()牵涉同一变量mScroller,

// 所以这里经过Android封装的异步类AsyncTask实现footerHeight和headerHeight的恢复。

// resetFooterHeight(),resetHeaderHeight()实际上是同步的,前者执行完毕才执行后者。

// Modified on 8/28/2015

new ResetHeaderHeightTask().execute();

} else if (getFirstVisiblePosition() == 0) {

// invoke refresh

if (mEnablePullRefresh && mHeaderView.getVisiableHeight() > mHeaderViewHeight) {

mPullRefreshing = true;

mHeaderView.setState(PullToRefreshListHeader.STATE_REFRESHING);

if (mListViewListener != null) {

mListViewListener.onRefresh();

}

}

resetHeaderHeight();

}

if (mTouchState == TOUCH_STATE_X) {

if (mTouchView != null) {

mTouchView.onSwipe(ev);

if (!mTouchView.isOpen()) {

mTouchPosition = -1;

mTouchView = null;

}

}

if (mOnSwipeListener != null) {

mOnSwipeListener.onSwipeEnd(mTouchPosition);

}

ev.setAction(MotionEvent.ACTION_CANCEL);

super.onTouchEvent(ev);

return true;

}

break;

}

return super.onTouchEvent(ev);

}

class ResetHeaderHeightTask extends AsyncTask {

protected Void doInBackground(Void... params) {

try {

Thread.sleep(400);

} catch (InterruptedException e) {

e.printStackTrace();

}

return null;

}

protected void onPostExecute(Void result) {

mPullRefreshing = false;

mHeaderView.setState(PullToRefreshListHeader.STATE_NORMAL);

resetHeaderHeight();

}

}

其实在整合这两套开源框架的时候遇到了很多的问题,归结起来实际上是对Android的Touch事件把握的不充分致使的,真正把原理、基础搞透彻了,作起项目来才能驾轻就熟啊。这里专门写了一篇关于Touch事件的博客:.net

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值