国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 系統 > Android > 正文

手勢滑動結束Activity基本功能的實現(一)

2019-12-12 02:45:11
字體:
來源:轉載
供稿:網友

喜歡聽音樂的朋友可能都看過天天動聽這款 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);    /*設置ViewGroup 的寬高*/    setMeasuredDimension(width, height);    /*獲取子 View 的寬度*/    final int contentWidth = getChildMeasureSpec(widthMeasureSpec, 0, width);    /*獲取子View 的高度*/    final int contentHeight = getChildMeasureSpec(heightMeasureSpec, 0, 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, 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:        /*計算 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方法;

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 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 來封裝了一層。

/** * 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, 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) ;  }  /**   * 側滑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 這事就變的非常簡單了

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 背景設為透明

<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" />

再來看看效果,效果圖:


完美實現!

好了,今天就到這里,下期文章就是對這個功能的進一步優化和改善,如果感興趣,可以繼續關注我!

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持武林網。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 涿州市| 苍梧县| 铁力市| 扬中市| 正镶白旗| 岳阳县| 榆社县| 鄂伦春自治旗| 丹巴县| 外汇| 沽源县| 寿阳县| 岑溪市| 永丰县| 诸暨市| 寿阳县| 墨脱县| 泉州市| 柳林县| 吴旗县| 晋江市| 平昌县| 和顺县| 确山县| 永济市| 海宁市| 迁西县| 长武县| 桂平市| 册亨县| 阿坝| 阿拉尔市| 侯马市| 涞源县| 咸丰县| 阜康市| 九江县| 南漳县| 三亚市| 颍上县| 肥西县|