最近的一个项目仿照百度地图的滑动功能,各种特效的出现着实让我纠结了好几个星期。好在iOS那边好几个版本老板都不满意,这让我有时间来研究滑动的实现了。现在分享下滑动,希望朋友们不会因为滑动个纠结这么久!
一想到滑动,我们肯定会毫不犹豫的想到ScrollView,简单方便,但是我们在使用的时候要注意重写一下两个方法:
@Override
public boolean onTouchEvent(MotionEvent ev) {
super.onTouchEvent(ev);
return false;
}
@Override
public boolean onInterceptTouchEvent(MotionEvent event)
{
super.onInterceptTouchEvent(event);
return false;
}
屏蔽掉touch事件才能监听子view的touch事件。接下来实现滑动就行
<pre name="code" class="java">@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
int y = 0;
int offsetY = 0;
switch (ev.getActionMasked()) {
case MotionEvent.ACTION_DOWN:
point.y = (int) ev.getRawY();
offset = 0;
break;
case MotionEvent.ACTION_MOVE:
y = (int) ev.getRawY();
offsetY = y - point.y;
offset += offsetY;
point.y = (int) ev.getRawY();
this.scrollBy(0, -offsetY);
break;
case MotionEvent.ACTION_CANCEL:
break;
case MotionEvent.ACTION_UP:
if (offset > 0) {
if (isOpen) {
if (offset > 400) {
this.scrollTo(0, 400);
isOpen = false;
} else {
this.scrollTo(0, 400);
isOpen = true;
}
} else {
this.scrollTo(0, 0);
isOpen = false;
}
} else {// offsetsum小于0时是往上拉,只有当隐藏详情页是下拉才有效果,所以这里先判断isOpen的值。
if (!isOpen) {
if (offset < -400) {
scrollTo(0, 400 - dip2px(getContext(), 200));
isOpen = true;
} else {
scrollTo(0, 0);
isOpen = false;
}
} else {
scrollTo(0, 400 - dip2px(getContext(), 200));
isOpen = true;
}
}
break;
}
return super.dispatchTouchEvent(ev);
}
代码启示很简单吧,只是我们平时都不愿意动手,自己写写还是一下就实现了。
简单点的就是layout的方法,其实就是上面方法类似的,只不过是在onTouchEvent(MotionEvent event)方法中实现,但是在我这个项目中效果是一样的。但是要注意event.getY()和event.getRawY的区别。
实际上View本身还有scrollTo和scrollBy这两方法,以前都没发现,还以为是ScrollerView专有的,所以在确定偏移量的时候就可以使用者两个方法了。
当然不能忘了Scroller这个类,著名的代表方法就是重写computeScroll()这个方法模拟实现滑动,滑动的时候别忘了刷新invalidate()。
属性动画也是一种措施哦!
当然,还有一种我项目中使用的,这是在一位架构师提醒下才知道有这个强大功能的类:ViewDragHelper。神奇的是这是个v4包里面的,用法也不是想象中的那么艰难。
首先初始化:mViewDragHelper= ViewDragHelper.create(this,1f,newDragHelperCallback());
拦截事件:
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
final int action = MotionEventCompat.getActionMasked(ev);
if (action == MotionEvent.ACTION_CANCEL || action == MotionEvent.ACTION_UP) {
<span style="color: rgb(102, 14, 122); font-family: Menlo; "><strong>mViewDragHelper</strong></span>.cancel();
return false;
}
return <span style="color: rgb(102, 14, 122); font-family: Menlo; "><strong>mViewDragHelper</strong></span>.shouldInterceptTouchEvent(ev);
}
处理滑动:computeScroll(),这个很无奈,人家也是需要处理这个东西的。
处理回调:这个是关键点。
@Override
public boolean tryCaptureView(View child, int pointerId) {
if (mViewDragCapture) {
return child == mDragView1;
}
return true;
}
@Override
public int clampViewPositionVertical(View child, int top, int dy) {
if (mDragVertical) {
final int topBound = getPaddingTop();
final int bottomBound = getHeight() - mDragView1.getHeight();
final int newTop = Math.min(Math.max(top, topBound), bottomBound);
return newTop;
}
return super.clampViewPositionVertical(child, top, dy);
}
@Override
public int clampViewPositionHorizontal(View child, int left, int dx) {
if (mDragHorizontal || mViewDragCapture || mDragEdge) {
final int leftBound = getPaddingLeft();
final int rightBound = getWidth() - mDragView1.getWidth();
final int newLeft = Math.min(Math.max(left, leftBound), rightBound);
return newLeft;
}
return super.clampViewPositionHorizontal(child, left, dx);
}
这三个方法是必须要实现的,但是可以根据需要进行实现,看方法名字就知道用来干嘛的吧!不要忘了回调结束之后要处理哦!
@Override
public void onViewPositionChanged(View changedView, int left, int top, int dx, int dy) {
invalidate();
}
@Override
public void onViewCaptured(View capturedChild, int activePointerId) {
super.onViewCaptured(capturedChild, activePointerId);
}
@Override
public void onViewReleased(View releasedChild, float xvel, float yvel) {
super.onViewReleased(releasedChild, xvel, yvel);
}
@Override
public void onEdgeTouched(int edgeFlags, int pointerId) {
super.onEdgeTouched(edgeFlags, pointerId);
}
@Override
public void onEdgeDragStarted(int edgeFlags, int pointerId) {
if (mDragEdge) {
mDragHelper.captureChildView(mDragView1, pointerId);
}
}
具体的实现就交给各位自己去实现了,这仅仅是基本的用法,至于源码什么的还没研究透彻,不好意思放上来,这个以后在补充,菜鸟也是要时间才能长大嘛!