栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 移动开发 > Android

手势滑动结束Activity基本功能的实现(一)

Android 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

手势滑动结束Activity基本功能的实现(一)

喜欢听音乐的朋友可能都看过天天动听这款 app, 这款 app 有一个亮点就是在切换页面(Fragment)的时候可以通过手势滑动来结束当前页面,这里先说一下,我为什么会这么关心这个功能呢,因为前两天 PM说我们即将开始做的这款app 也要实现页面能通过手势滑动来结束的功能,所以我就拿着这款 app 滑了一上午;但是我要实现的跟天天动听这款 app又有点不同,细心观察的朋友可能会发现,天天动听是 Fragment 之间的切换,而我这里要实现的是 Activity 之间的切换,不过,不管是哪种,最终效果都是一样,就是页面能随着手势的滑动而滑动,最终达到某个特定条件,结束此页面。
要实现这个功能其实也不是特别难,这里我把这个功能的实现分为了以下两个步骤:

1、识别手势滑动自定义ViewGroup 的实现
2、实现自定义 ViewGroup 和 Activity 绑定

根据以上两个步骤,我们发现,这其中涉及到的知识点有:Android 事件处理机制、自定义 View(ViewGroup)的实现,Activity Window的知识,在开发的过程中还涉及到Activity 主题的配置。Android 事件处理和自定义 View 都在我前面的 blog 中有讲到,如果不了解的朋友可以去看看。下面开始按步骤来实现功能

一、自定义 ViewGroup

这个 ViewGroup 的功能只要是对事件的拦截,能够实现手势滑动效果;显示 Activity 的内容包括 ActionBar 和内容区。

1、实现测量和布局

  @Override
  protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    
    int width = getDefaultSize(0, widthMeasureSpec);
    
    int height = getDefaultSize(0, heightMeasureSpec);
    
    setMeasuredDimension(width, height);
    
    final int contentWidth = getChildMeasureSpec(widthMeasureSpec, 0, width);
    
    final int contentHeight = getChildMeasureSpec(heightMeasureSpec, 0, height);
    
    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, 0, width, height);
  }

因为每个 Activity 都只有一个 Layout,所以这里只有一个子 View,布局和测量就显得非常简单。

2、事件拦截

  @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:
 
 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方法;

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;
 }
 
 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 totalDelta = (int) (x - mInitialMotionX);
     
     int nextPage = determineTargetPage(pageOffset, initialVelocity, totalDelta);
     setCurrentItemInternal(nextPage, true, initialVelocity);
   } else {
     setCurrentItemInternal(mCurItem, true, initialVelocity);
   }
   mActivePointerId = INVALID_POINTER;
   endToDrag();
 } else {
//   setCurrentItemInternal(0, true, 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 的效果


可以看到,这里我们已经实现了手势识别的 ViewGroup,其实这个ViewGroup如果发挥想象,它能实现很多效果,不单单是我今天要讲的效果,还可以用作侧拉菜单,或者是做 QQ5.0版本侧滑效果都可以实现的。

二、侧滑 View绑定 Activity

这里为了代码的简洁,还是通过一个 ViewGroup 来封装了一层。


public class SlidingLayout extends frameLayout {
  
  private SlidingView mSlidingView ;
  
  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, attrs, 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) ;
  }

  
  private void bindActivity(Activity activity){
    
    ViewGroup root = (ViewGroup) activity.getWindow().getDecorView();
    
    ViewGroup child = (ViewGroup) root.getChildAt(0);
    root.removeView(child);
    mSlidingView.setContent(child);
    root.addView(this);
  }
}

测试 Activity 这事就变的非常简单了

public class SecondActivity extends ActionBarActivity {

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_second);
    
    new SlidingLayout(this) ;
  }

}

来看看效果怎么样:

咦!能滑动结束页面,但为什么边滑走的同时看不到第一个 Acitivity,而是要等结束了才能看到呢?我们猜测,应该是滑动的时候,这个 Activity 还有哪里把第一个 Activity 覆盖了,每个 Activity 都是附在一个 Window 上面,所以这里就涉及到一个 Activity 的 window背景颜色问题, OK,把第二个 Activity 的 window 背景设为透明


 true
 @android:color/transparent
 @null




再来看看效果,效果图:


完美实现!

好了,今天就到这里,下期文章就是对这个功能的进一步优化和改善,如果感兴趣,可以继续关注我!

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持考高分网。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/158537.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号