欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

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

 更新時間:2017年06月03日 15:14:31   作者:鐘光燕  
這篇文章主要為大家詳細介紹了手勢滑動結束Activity基本功能的實現(xiàn)方法,具有一定的參考價值,感興趣的小伙伴們可以參考一下

喜歡聽音樂的朋友可能都看過天天動聽這款 app, 這款 app 有一個亮點就是在切換頁面(Fragment)的時候可以通過手勢滑動來結束當前頁面,這里先說一下,我為什么會這么關心這個功能呢,因為前兩天 PM說我們即將開始做的這款app 也要實現(xiàn)頁面能通過手勢滑動來結束的功能,所以我就拿著這款 app 滑了一上午;但是我要實現(xiàn)的跟天天動聽這款 app又有點不同,細心觀察的朋友可能會發(fā)現(xiàn),天天動聽是 Fragment 之間的切換,而我這里要實現(xiàn)的是 Activity 之間的切換,不過,不管是哪種,最終效果都是一樣,就是頁面能隨著手勢的滑動而滑動,最終達到某個特定條件,結束此頁面。
要實現(xiàn)這個功能其實也不是特別難,這里我把這個功能的實現(xiàn)分為了以下兩個步驟:

1、識別手勢滑動自定義ViewGroup 的實現(xiàn)
2、實現(xiàn)自定義 ViewGroup 和 Activity 綁定

根據(jù)以上兩個步驟,我們發(fā)現(xiàn),這其中涉及到的知識點有:Android 事件處理機制、自定義 View(ViewGroup)的實現(xiàn),Activity Window的知識,在開發(fā)的過程中還涉及到Activity 主題的配置。Android 事件處理和自定義 View 都在我前面的 blog 中有講到,如果不了解的朋友可以去看看。下面開始按步驟來實現(xiàn)功能

一、自定義 ViewGroup

這個 ViewGroup 的功能只要是對事件的攔截,能夠實現(xiàn)手勢滑動效果;顯示 Activity 的內容包括 ActionBar 和內容區(qū)。

1、實現(xiàn)測量和布局

  @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);
        /*這里判讀,如果這個觸摸區(qū)域是允許滑動攔截的,則攔截事件*/
        if (thisTouchAllowed(ev)) {
          mIsBeingDragged = false;
          mIsUnableToDrag = false;
        } else {
          mIsUnableToDrag = true;
        }
        break;
      case MotionEvent.ACTION_MOVE:
        /*繼續(xù)判斷是否需要攔截*/
        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 分發(fā),直接執(zhí)行本級 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;
        }
        /*如果已經(jīng)是滑動狀態(tài),則根據(jù)手勢滑動,而改變View 的位置*/
        if (mIsBeingDragged) {
          // 以下代碼用來判斷和執(zhí)行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:
        /*如果已經(jīng)是滑動狀態(tài),抬起手指,需要判斷滾動的位置*/
        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 的效果


可以看到,這里我們已經(jīng)實現(xiàn)了手勢識別的 ViewGroup,其實這個ViewGroup如果發(fā)揮想象,它能實現(xiàn)很多效果,不單單是我今天要講的效果,還可以用作側拉菜單,或者是做 QQ5.0版本側滑效果都可以實現(xiàn)的。

二、側滑 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 顯示內容區(qū)域的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"
 />

再來看看效果,效果圖:


完美實現(xiàn)!

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

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

相關文章

  • Android 獲取未安裝的APK圖標、版本號、包名等信息方法

    Android 獲取未安裝的APK圖標、版本號、包名等信息方法

    下面小編就為大家分享一篇Android 獲取未安裝的APK圖標、版本號、包名等信息方法,具有很好的參考價值,希望對大家有所幫助。
    2018-01-01
  • android 顯示gif圖片實例詳解

    android 顯示gif圖片實例詳解

    本文主要介紹android 顯示gif圖片的知識,這里整理相關資料及簡單實例代碼,有需要的小伙伴可以參考下
    2016-09-09
  • Android燒錄指令fastboot簡介

    Android燒錄指令fastboot簡介

    fastboot 是作為 Android 系統(tǒng)編譯器的客戶端,編譯后位于 ./out/host/?Linux?-x86/bin/fastboot 目錄下,這篇文章主要介紹了Android燒錄指令fastboot簡介,需要的朋友可以參考下
    2024-01-01
  • 快速了解Android Room使用細則

    快速了解Android Room使用細則

    這篇文章主要為大家介紹了快速了解Android Room使用細則,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-03-03
  • 利用Android實現(xiàn)比較炫酷的自定義View

    利用Android實現(xiàn)比較炫酷的自定義View

    自定義View、多線程、網(wǎng)絡,被認為是Android開發(fā)者必須牢固掌握的最基礎的三大基本功,這篇文章主要給大家介紹了關于如何利用Android實現(xiàn)比較炫酷的自定義View的相關資料,需要的朋友可以參考下
    2021-07-07
  • Android入門之TableLayout應用解析(一)

    Android入門之TableLayout應用解析(一)

    這篇文章主要介紹了Android入門之TableLayout應用,需要的朋友可以參考下
    2014-08-08
  • Android學習之Fragment

    Android學習之Fragment

    Fragment是什么?碎片(Fragment)是一種可以嵌入在活動(activity)當中的UI片段,想要了解碎片的簡單用法的朋友可以參考一下
    2016-01-01
  • 深入理解Android中的Window和WindowManager

    深入理解Android中的Window和WindowManager

    這篇文章給大家介紹了Window和WindowManager知識,非常不錯,具有參考借鑒價值,需要的朋友參考下吧
    2017-02-02
  • Flutter網(wǎng)絡請求庫DIO的基本使用

    Flutter網(wǎng)絡請求庫DIO的基本使用

    這篇文章主要介紹了Flutter網(wǎng)絡請求庫DIO的基本使用,幫助大家更好的理解和學習使用Flutter,感興趣的朋友可以了解下
    2021-04-04
  • Flutter路由框架Fluro使用教程詳細講解

    Flutter路由框架Fluro使用教程詳細講解

    在Flutter應用開發(fā)過程中,除了使用Flutter官方提供的路由外,還可以使用一些第三方路由框架來實現(xiàn)頁面管理和導航,F(xiàn)luro作為一款優(yōu)秀的Flutter企業(yè)級路由框架,F(xiàn)luro的使用比官方提供的路由框架要復雜一些,但是卻非常適合中大型項目
    2022-10-10

最新評論