大佬教程收集整理的这篇文章主要介绍了手势滑动结束Activity基本功能的实现(一),大佬教程大佬觉得挺不错的,现在分享给大家,也给大家做个参考。
喜欢听音乐的朋友可能都看过天天动听这款 app, 这款 app 有一个亮点就是在切换页面(Fragment)的时候可以通过手势滑动来结束当前页面,这里先说一下,我为什么会这么关心这个功能呢,因为前两天 PM说我们即将开始做的这款app 也要实现页面能通过手势滑动来结束的功能,所以我就拿着这款 app 滑了一上午;但是我要实现的跟天天动听这款 app又有点不同,细心观察的朋友@R_579_9381@,天天动听是 Fragment 之间的切换,而我这里要实现的是 Activity 之间的切换,不过,不管是哪种,最终效果都是一样,就是页面能随着手势的滑动而滑动,最终达到某个特定条件,结束此页面。
要实现这个功能其实也不是特别难,这里我把这个功能的实现分为了以下两个步骤:
@H_696_3@
1、识别手势滑动自定义viewGroup 的实现
2、实现自定义 ViewGroup 和 Activity 绑定@H_696_3@
根据以上两个步骤,我们发现,这其中涉及到的知识点有:Android 事件处理机制、自定义 View(ViewGroup)的实现,Activity Window的知识,在开发的过程中还涉及到Activity 主题的配置。Android 事件处理和自定义 View 都在我前面的 blog 中有讲到,如果不了解的朋友可以去看看。下面开始按步骤来实现功能@H_696_3@
这个 ViewGroup 的功能只要是对事件的拦截,能够实现手势滑动效果;显示 Activity 的内容包括 ActionBar 和内容区。
@H_696_3@
1、实现测量和布局@H_696_3@
@Override protected void onMeasure(int widthMeasureSpec,int heightMeasureSpeC) { /*获取默认的宽度*/ int width = getDefaultSize(0,widthMeasureSpec); /*获取默认的高度*/ int height = getDefaultSize(0,heightMeasureSpec); /*设置ViewGroup 的宽高*/ setMeasuredDimension(width,height); /*获取子 View 的宽度*/ final int contentWidth = getChildMeasureSpec(widthMeasureSpec,width); /*获取子View 的高度*/ final int contentHeight = getChildMeasureSpec(heightMeasureSpec,height); /*设置子View 的大小*/ mContent.measure(contentWidth,contentHeight); }
@Override protected void onLayout(Boolean changed,int l,int t,int r,int b) { final int width = r - l; final int height = b - t; mContent.layout(0,width,height); }
因为每个 Activity 都只有一个 Layout,所以这里只有一个子 View,布局和测量就显得非常简单。@H_696_3@
@Override public Boolean onInterceptTouchEvent(MotionEvent ev) { if (!isEnablE) { return false; } final int action = ev.getAction() & MotionEventCompat.ACTION_MASK; if (action == MotionEvent.ACTION_CANCEL || action == MotionEvent.ACTION_UP || action != MotionEvent.ACTION_DOWN && mIsUnableToDrag) { /*结束手势的滑动,不拦截*/ endToDrag(); return false; } switch (action) { case MotionEvent.ACTION_DOWN: /*计算 x,y 的距离*/ int index = MotionEventCompat.getActionIndex(ev); mActivePointerId = MotionEventCompat.getPointerId(ev,indeX); if (mActivePointerId == INVALID_POINTER) break; mLastMotionX = mInitialMotionX = MotionEventCompat.getX(ev,indeX); mLastMotionY = MotionEventCompat.getY(ev,indeX); /*这里判读,如果这个触摸区域是允许滑动拦截的,则拦截事件*/ if (thisTouchAllowed(ev)) { mIsBeingDragged = false; mIsUnableToDrag = false; } else { mIsUnableToDrag = true; } break; case MotionEvent.ACTION_MOVE: /*继续判断是否需要拦截*/ determineDrag(ev); break; case MotionEvent.ACTION_UP: break; case MotionEvent.ACTION_POINTER_UP: /*这里做了对多点触摸的处理,当有多个手指触摸的时候依然能正确的滑动*/ onSecondaryPointerUp(ev); break; } if (!mIsBeingDragged) { if (mVeLocityTracker == null) { mVeLocityTracker = VeLocityTracker.obtain(); } mVeLocityTracker.addMovement(ev); } return mIsBeingDragged; }
事件拦截,是拦截而是其不会向子 View 分发,直接执行本级 View的 onTouchEvent方法;@H_696_3@
3、事件处理@H_696_3@
@Override public Boolean onTouchEvent(MotionEvent event) { if (!isEnablE) { return false; } if (!mIsBeingDragged && !thisTouchAllowed(event)) return false; final int action = event.getAction(); if (mVeLocityTracker == null) { mVeLocityTracker = VeLocityTracker.obtain(); } mVeLocityTracker.addMovement(event); switch (action & MotionEventCompat.ACTION_MASK) { case MotionEvent.ACTION_DOWN: /*按下则结束滚动*/ completeScroll(); int index = MotionEventCompat.getActionIndex(event); mActivePointerId = MotionEventCompat.getPointerId(event,indeX); mLastMotionX = mInitialMotionX = event.getX(); break; case MotionEventCompat.ACTION_POINTER_DOWN: { /*有多个点按下的时候,取最后一个按下的点为有效点*/ final int indexx = MotionEventCompat.getActionIndex(event); mLastMotionX = MotionEventCompat.getX(event,indexX); mActivePointerId = MotionEventCompat.getPointerId(event,indexX); break; } case MotionEvent.ACTION_MOVE: if (!mIsBeingDragged) { determineDrag(event); if (mIsUnableToDrag) return false; } /*如果已经是滑动状态,则根据手势滑动,而改变View 的位置*/ if (mIsBeingDragged) { // 以下代码用来判断和执行View 的滑动 final int activePointerIndex = getPointerIndex(event,mActivePointerId); if (mActivePointerId == INVALID_POINTER) break; final float x = MotionEventCompat.getX(event,activePointerIndeX); final float deltaX = mLastMotionX - x; mLastMotionX = x; float oldScrollX = getScrollX(); float scrollX = oldScrollX + deltaX; final float leftBound = getLeftBound(); final float rightBound = getrightBound(); if (scrollX < leftBound) { scrollX = leftBound; } else if (scrollX > rightBound) { scrollX = rightBound; } mLastMotionX += scrollX - (int) scrollX; scrollTo((int) scrollX,getScrollY()); } break; case MotionEvent.ACTION_UP: /*如果已经是滑动状态,抬起手指,需要判断滚动的位置*/ if (mIsBeingDragged) { final VeLocityTracker veLocityTracker = mVeLocityTracker; veLocityTracker.computeCurrentVeLocity(1000,mMaxMunVeLocity); int initialVeLocity = (int) VeLocityTrackerCompat.getXVeLocity( veLocityTracker,mActivePointerId); final int scrollX = getScrollX(); final float pageOffset = (float) (-scrollX) / getContentWidth(); final int activePointerIndex = getPointerIndex(event,mActivePointerId); if (mActivePointerId != INVALID_POINTER) { final float x = MotionEventCompat.getX(event,activePointerIndeX); final int @R_620_10586@lDelta = (int) (x - mInitialMotionX); /*这里判断是否滚动到下一页,还是滚回原位置*/ int nextPage = determineTargetPage(pageOffset,initialVeLocity,@R_620_10586@lDelta); setCurrentItemInternal(nextPage,true,initialVeLocity); } else { setCurrentItemInternal(mCurItem,initialVeLocity); } mActivePointerId = INVALID_POINTER; endToDrag(); } else { // setCurrentItemInternal(0,0); endToDrag(); } break; case MotionEventCompat.ACTION_POINTER_UP: /*这里有事多点处理*/ onSecondaryPointerUp(event); int pointerIndex = getPointerIndex(event,mActivePointerId); if (mActivePointerId == INVALID_POINTER) break; mLastMotionX = MotionEventCompat.getX(event,pointerIndeX); break; } return true; }
因为这里加入了多点控制,所以代码看起来有点复杂,其实原理很简单,就是不断的判断是否符合滑动的条件。其他就不细讲了,来看看这个自定义 ViewGroup 的效果@H_696_3@
可以看到,这里我们已经实现了手势识别的 ViewGroup,其实这个ViewGroup如果发挥想象,它能实现很多效果,不单单是我今天要讲的效果,还可以用作侧拉菜单,或者是做 QQ5.0版本侧滑效果都可以实现的。@H_696_3@
二、侧滑 View绑定 Activity
@H_696_3@
这里为了代码的简洁,还是通过一个 ViewGroup 来封装了一层。@H_696_3@
/** * Created by moon.zhong on 2015/3/13. */ public class SlidingLayout extends FrameLayout { /*侧滑View*/ private SlidingView mSlidingView ; /*需要侧滑结束的Activity*/ private Activity mActivity ; public SlidingLayout(Context context) { this(context,null); } public SlidingLayout(Context context,AttributeSet attrs) { this(context,attrs,0); } public SlidingLayout(Context context,AttributeSet attrs,int defStyleAttr) { super(context,defStyleAttr); mSlidingView = new SlidingView(context) ; addView(mSlidingView); mSlidingView.setOnPagechangelistener(new SlidingView.onPagechangelistener() { @Override public void onPageScrolled(int position,float positionOffset,int positionOffsetPixels) { if (position == 1){ Log.v("zgy","========position=========") ; mActivity.finish(); } } @Override public void onPageSELEcted(int position) { } }); mActivity = (Activity) context; bindActivity(mActivity) ; } /** * 侧滑View 和Activity 绑定 * @param activity */ private void bindActivity(Activity activity){ /*获取Activity 的最顶级ViewGrouP*/ ViewGroup root = (ViewGroup) activity.getWindow().getDecorView(); /*获取Activity 显示内容区域的ViewGroup,包行ActionBar*/ ViewGroup child = (ViewGroup) root.getChildAt(0); root.removeView(child); mSlidingView.setContent(child); root.addView(this); } }
测试 Activity 这事就变的非常简单了@H_696_3@
public class SecondActivity extends ActionBarActivity { @Override protected void onCreate(Bundle savedInstanceStatE) { super.onCreate(savedInstanceStatE); setContentView(R.layout.activity_second); /*绑定Activity*/ new SlidingLayout(this) ; } }
咦!能滑动结束页面,但为什么边滑走的同时看不到第一个 Acitivity,而是要等结束了才能看到呢?我们猜测,应该是滑动的时候,这个 Activity 还有哪里把第一个 Activity 覆盖了,每个 Activity 都是附在一个 Window 上面,所以这里就涉及到一个 Activity 的 window背景颜色问题, OK,把第二个 Activity 的 window 背景设为透明@H_696_3@
<style name="TranslucentTheme" parent="AppTheme"> <item name="android:windowIsTranslucent">true</item> <item name="android:windowBACkground">@android:color/transparent</item> <item name="android:windowContentOverlay">@null</item> </style>
<activity android:name=".SecondActivity" android:label="SecondActivity" android:screenOrientation="porTrait" android:theme="@style/TranslucentTheme" />
完美实现!
@H_696_3@
好了,今天就到这里,下期文章就是对这个功能的进一步优化和改善,如果感兴趣,可以继续关注我!
@H_696_3@
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持编程小技巧。
@H_696_3@
以上是大佬教程为你收集整理的手势滑动结束Activity基本功能的实现(一)全部内容,希望文章能够帮你解决手势滑动结束Activity基本功能的实现(一)所遇到的程序开发问题。
如果觉得大佬教程网站内容还不错,欢迎将大佬教程推荐给程序员好友。
本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
如您有任何意见或建议可联系处理。小编QQ:384754419,请注明来意。