最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Android實(shí)現(xiàn)微信側(cè)滑關(guān)閉頁(yè)面效果

 更新時(shí)間:2017年12月02日 09:43:59   作者:AriaLyy  
這篇文章主要為大家詳細(xì)介紹了Android實(shí)現(xiàn)微信側(cè)滑關(guān)閉頁(yè)面效果,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下

最近手機(jī)升級(jí)了5.0系統(tǒng)后,突然間發(fā)現(xiàn)微信竟然有IOS一樣的側(cè)滑關(guān)閉當(dāng)前頁(yè)面的效果,就想把這種效果也加進(jìn)自己的項(xiàng)目里面。本著不重復(fù)造輪子的原則,就在網(wǎng)上百度了很久,發(fā)現(xiàn)大多數(shù)人都是采用自定義View來(lái)實(shí)現(xiàn),但是對(duì)于我這種已經(jīng)基本完成的項(xiàng)目來(lái)說(shuō),如果全部的Activity再重新使用自定義的View無(wú)疑是一種可怕的噩夢(mèng)。

因此,我這里實(shí)現(xiàn)了另外一種不需要自定義View也能實(shí)現(xiàn)的方法,其子類只要繼承于它,便能擁有其側(cè)滑滑動(dòng)的功能。
隨便說(shuō)一句,此方法僅對(duì)5.0以上的手機(jī)有效(反正微信也是5.0上才能用),5.0以下的請(qǐng)無(wú)視?。?!

原理

在每個(gè)Activity里面都有一個(gè)底層的View,也就是所謂的rootView,當(dāng)我們加載一個(gè)xml布局時(shí),系統(tǒng)就會(huì)自動(dòng)給你生成這個(gè)rootView,由于它是一個(gè)View,那么也就意味著你可以通過(guò)一定的代碼隨意移動(dòng)這個(gè)根布局。
如下代碼所示,只要簡(jiǎn)單的幾行代碼便能實(shí)現(xiàn)布局的移動(dòng)。

public class SlideActivity extends AppCompatActivity {
  View mRootView;
  private GestureDetector mDetector;
  private int mWindowWidth;

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_demo);
    mRootView = getWindow().getDecorView();
    mRootView.setBackgroundColor(Color.BLUE);
    mDetector = new GestureDetector(this, new GestureListener());
    mWindowWidth = getWindow().getWindowManager().getDefaultDisplay().getWidth();
  }

  @Override
  public boolean onTouchEvent(MotionEvent event) {
    return mDetector.onTouchEvent(event);
  }

  /**
   * 手勢(shì)監(jiān)聽(tīng)
   */
  private class GestureListener extends GestureDetector.SimpleOnGestureListener {
    @Override
    public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
      if (e1 != null) {
        handlerCurrentActivityScroll(e2);
      }
      return super.onScroll(e1, e2, distanceX, distanceY);
    }

    /**
     * 處理當(dāng)前頁(yè)面滑動(dòng)
     */
    private void handlerCurrentActivityScroll(MotionEvent e2) {
      mRootView.setTranslationX(e2.getX());
      if (e2.getX() > mWindowWidth - 20) {
        finish();
      }
    }
  }
}

這是我們的效果

Activity聯(lián)動(dòng)

這差距還是很大的,最明顯的地方是,我們移動(dòng) 的時(shí)候,上一層Activity竟然沒(méi)有跟著聯(lián)動(dòng)。

解決這個(gè)問(wèn)題的方法也簡(jiǎn)單,如圖所示,每當(dāng)啟動(dòng)一個(gè)Activity時(shí),系統(tǒng)都會(huì)把Activity放到一個(gè)棧里面,由于棧的工作原理可知,APP里面的Activity是一層覆蓋一層的,就如上圖所示。為此,每當(dāng)啟動(dòng)一個(gè)Activity時(shí),就可以把當(dāng)前的Actiivty存儲(chǔ)到一個(gè)List里面,這樣,我們就可以在當(dāng)前的Activity里面取出上一個(gè)Activity進(jìn)行操作。

因此,在進(jìn)入一個(gè)新的Activity的時(shí)候,在其onCreate方法里面把當(dāng)前的Activity加載到列表里,當(dāng)退出時(shí),在finish的重載方法里面,將當(dāng)前Activity從列表里面移除。

注意?。?!在滑動(dòng)的時(shí)候必須需要考慮到Activity里面有可能會(huì)有類似于ListView一類的滑動(dòng)控件,因此,我們必須對(duì)事件進(jìn)行分發(fā)控制。

代碼如下

/**
 * Created by yuyu on 2015/10/29.
 */
public class TestActivity extends AppCompatActivity {
  View mRootView;
  private GestureDetector mGestureDetector;
  private static List<TestActivity> mActivitys = new ArrayList<>();
  /**
   * 移動(dòng)距離
   */
  private float mWindowWidth;
  private TestActivity mBeforeActivity;
  /**
   * 上一個(gè)Activity偏移量
   */
  private float mOffsetX;
  /**
   * 上一個(gè)頁(yè)面移出的位置
   */
  private float mOutsideWidth;

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_demo);
    /**
     * 把當(dāng)前Activity加到列表里面
     */
    mActivitys.add(this);
    initScrollBack();
  }

  /**
   * 初始化左滑退出功能
   */
  private void initScrollBack() {
    mWindowWidth = getWindowManager().getDefaultDisplay().getWidth();
    mOutsideWidth = -mWindowWidth / 4;
    mOffsetX = mOutsideWidth;
    mGestureDetector = new GestureDetector(this, new GestureListener());
    mRootView = getWindow().getDecorView();
    mRootView.setBackgroundColor(Color.BLUE);
  }

  /**
   * 控制分發(fā)事件,在這里控制能能觸發(fā)拖動(dòng)的范圍
   */
  @Override
  public boolean dispatchTouchEvent(@NonNull MotionEvent ev) {
    if (ev.getX() < mWindowWidth / 10) {
      if (mActivitys.size() > 1) {
        mBeforeActivity = mActivitys.get(mActivitys.size() - 2);
        beforeActivityTranslationX(mOutsideWidth);
      }
      return onTouchEvent(ev);
    }
    return super.dispatchTouchEvent(ev);
  }

  @Override
  public void finish() {
    mActivitys.remove(this);
    if (mOffsetX < 0.0001 || mOffsetX > 0.0001) {
      beforeActivityTranslationX(0);
    }
    super.finish();
  }

  public void onClick(View view) {
    Intent intent = new Intent(this, Activity5.class);
    startActivity(intent);
  }

  public View getRootView() {
    return mRootView;
  }

  /**
   * 控制上一個(gè)Activity移動(dòng)
   */
  private void beforeActivityTranslationX(float translationX) {
    if (mBeforeActivity != null) {
      mBeforeActivity.getRootView().setTranslationX(translationX);
    }
  }

  @Override
  public boolean onTouchEvent(MotionEvent event) {
    return mGestureDetector.onTouchEvent(event);
  }

  /**
   * 手勢(shì)監(jiān)聽(tīng)
   */
  private class GestureListener extends GestureDetector.SimpleOnGestureListener {
    @Override
    public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
      if (e1 != null) {
        handlerCurrentActivityScroll(e2);
        handleBeforeActivityScroll(e2, distanceX);
      }
      return super.onScroll(e1, e2, distanceX, distanceY);
    }

    /**
     * 處理當(dāng)前頁(yè)面滑動(dòng)
     */
    private void handlerCurrentActivityScroll(MotionEvent e2) {
      mRootView.setTranslationX(e2.getX());
      if (e2.getX() > mWindowWidth - 20) {
        finish();
      }
    }

    /**
     * 處理上一個(gè)頁(yè)面滑動(dòng)
     */
    private void handleBeforeActivityScroll(MotionEvent e2, float distanceX) {
      if (mBeforeActivity != null) {
        mOffsetX = distanceX < 0 ? mOffsetX + Math.abs(distanceX) / 4 : mOffsetX - Math.abs(distanceX) / 4;
        if (mOffsetX > 0.0001) {
          mOffsetX = 0f;
        }
        mBeforeActivity.getRootView().setTranslationX(mOffsetX);
      }
    }
  }
}

這是聯(lián)動(dòng)后的效果圖

現(xiàn)在算是有點(diǎn)效果了,但是和微信的差距還是很大,接下來(lái)我們便需要開(kāi)始處理自動(dòng)滑動(dòng)了

自動(dòng)滑動(dòng)

這個(gè)就不需要多說(shuō)了,這個(gè)主要就是利用屬性動(dòng)畫(huà)進(jìn)行移動(dòng)

以下是完整的代碼

public class SlideActivity extends AppCompatActivity {
  private static final String TAG = "SlideActivity";
  private static List<SlideActivity> mActivitys = new ArrayList<>();
  /**
   * 手勢(shì)監(jiān)聽(tīng)
   */
  private GestureDetector mGestureDetector;
  private View mRootView;
  private boolean isScroll = false;
  /**
   * 移動(dòng)距離
   */
  private float mWindowWidth;
  private SlideActivity mBeforeActivity;
  /**
   * 上一個(gè)Activity偏移量
   */
  private float mOffsetX;
  /**
   * 上一個(gè)頁(yè)面移出的位置
   */
  private float mOutsideWidth;
  private boolean canScrollBack = true;
  private boolean canScroll = false;

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    getWindow().requestFeature(Window.FEATURE_CONTENT_TRANSITIONS);
    getWindow().setEnterTransition(new Slide(Gravity.RIGHT));
    super.onCreate(savedInstanceState);
    /**
     * 把當(dāng)前Activity加到列表里面
     */
    mActivitys.add(this);
    initScrollBack();
  }

  @Override
  public void startActivity(Intent intent) {
    startActivity(intent, ActivityOptions.makeSceneTransitionAnimation(this).toBundle());
  }

  /**
   * 初始化左滑退出功能
   */
  private void initScrollBack() {
    mWindowWidth = getWindowManager().getDefaultDisplay().getWidth();
    mOutsideWidth = -mWindowWidth / 4;
    mOffsetX = mOutsideWidth;
    mGestureDetector = new GestureDetector(this, new GestureListener());
    mRootView = getWindow().getDecorView();

  }

  /**
   * 控制上一個(gè)Activity移動(dòng)
   */
  private void beforeActivityTranslationX(float translationX) {
    if (mBeforeActivity != null) {
      mBeforeActivity.getRootView().setTranslationX(translationX);
    }
  }

  /**
   * 設(shè)置是否能滑動(dòng)
   *
   * @param canScrollBack true 可以滑動(dòng)
   */
  protected void setCanScrollBack(boolean canScrollBack) {
    this.canScrollBack = canScrollBack;
  }

  public View getRootView() {
    return mRootView;
  }

  @Override
  public void finish() {
    mActivitys.remove(this);
    if (mOffsetX < 0.0001 || mOffsetX > 0.0001) {
      beforeActivityTranslationX(0);
    }
    super.finish();
  }

  /**
   * 控制分發(fā)事件
   */
  @Override
  public boolean dispatchTouchEvent(@NonNull MotionEvent ev) {
    if (canScrollBack && ev.getX() < mWindowWidth / 10) {
      if (mActivitys.size() > 1) {
        mBeforeActivity = mActivitys.get(mActivitys.size() - 2);
        beforeActivityTranslationX(mOutsideWidth);
      }
      canScroll = true;
      return onTouchEvent(ev);
    }
    return super.dispatchTouchEvent(ev);
  }

  @Override
  public boolean onTouchEvent(MotionEvent event) {
    if (canScrollBack && canScroll) {
      if (event.getAction() == MotionEvent.ACTION_UP && isScroll) {
        isScroll = false;
        canScroll = false;
        //退出當(dāng)前Activity
        if (event.getX() > mWindowWidth / 2) {
          if (mBeforeActivity != null) {
            ObjectAnimator.ofFloat(mBeforeActivity.getRootView(), "translationX", mOffsetX, 0).setDuration(500).start();
          }
          ObjectAnimator moveIn = ObjectAnimator.ofFloat(mRootView, "translationX", event.getX(), mWindowWidth);
          moveIn.addListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationEnd(Animator animation) {
              super.onAnimationEnd(animation);
              finish();
            }
          });
          moveIn.setDuration(500).start();
          //反彈回來(lái)
        } else if (event.getX() < mWindowWidth / 2) {
          ObjectAnimator.ofFloat(mRootView, "translationX", event.getX(), 0).setDuration(500).start();
          if (mBeforeActivity != null) {
            ObjectAnimator.ofFloat(mBeforeActivity.getRootView(), "translationX", mOffsetX, mOutsideWidth).setDuration(500).start();
          }
          mOffsetX = mOutsideWidth;
        }
      } else {
        mGestureDetector.onTouchEvent(event);
      }
    }
    return true;
  }

  /**
   * 手勢(shì)監(jiān)聽(tīng)
   */
  private class GestureListener extends GestureDetector.SimpleOnGestureListener {
    @Override
    public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
      if (e1 != null) {
        handlerCurrentActivityScroll(e2);
        handleBeforeActivityScroll(e2, distanceX);
      }
      return super.onScroll(e1, e2, distanceX, distanceY);
    }

    /**
     * 處理當(dāng)前頁(yè)面滑動(dòng)
     */
    private void handlerCurrentActivityScroll(MotionEvent e2) {
      isScroll = true;
      mRootView.setTranslationX(e2.getX());
      if (e2.getX() > mWindowWidth - 20) {
        finish();
      }
    }

    /**
     * 處理上一個(gè)頁(yè)面滑動(dòng)
     */
    private void handleBeforeActivityScroll(MotionEvent e2, float distanceX) {
      if (mBeforeActivity != null) {
        mOffsetX = distanceX < 0 ? mOffsetX + Math.abs(distanceX) / 4 : mOffsetX - Math.abs(distanceX) / 4;
        if (mOffsetX > 0.0001) {
          mOffsetX = 0f;
        }
        mBeforeActivity.getRootView().setTranslationX(mOffsetX);
      }
    }
  }
}

這是我們最終的效果圖

以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • Android?NDK開(kāi)發(fā)之FFmpeg視頻添加水印

    Android?NDK開(kāi)發(fā)之FFmpeg視頻添加水印

    這篇文章主要介紹了在Android?NDK開(kāi)發(fā)中如何通過(guò)FFmpeg為視頻添加水印,文中的示例代碼講解詳細(xì),對(duì)我們了解Android開(kāi)發(fā)有一定的幫助,感興趣的可以學(xué)習(xí)一下
    2021-12-12
  • 一步步教你寫(xiě)Slack的Loading動(dòng)畫(huà)

    一步步教你寫(xiě)Slack的Loading動(dòng)畫(huà)

    這篇文章主要為大家詳細(xì)手摸手教你寫(xiě)Slack的Loading動(dòng)畫(huà),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2016-09-09
  • android打開(kāi)本地圖像的方法

    android打開(kāi)本地圖像的方法

    這篇文章主要介紹了android打開(kāi)本地圖像的方法,涉及Android操作圖像的相關(guān)技巧,需要的朋友可以參考下
    2015-04-04
  • Spi機(jī)制在Android開(kāi)發(fā)的應(yīng)用示例詳解

    Spi機(jī)制在Android開(kāi)發(fā)的應(yīng)用示例詳解

    這篇文章主要為大家介紹了Spi機(jī)制在Android開(kāi)發(fā)的應(yīng)用示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-08-08
  • Android 沉浸式改變小米魅族狀態(tài)欄顏色的實(shí)例代碼

    Android 沉浸式改變小米魅族狀態(tài)欄顏色的實(shí)例代碼

    這篇文章主要介紹了Android 沉浸式改變小米魅族狀態(tài)欄顏色的實(shí)例代碼,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下
    2017-02-02
  • Android編程實(shí)現(xiàn)自定義分享列表ACTION_SEND功能的方法

    Android編程實(shí)現(xiàn)自定義分享列表ACTION_SEND功能的方法

    這篇文章主要介紹了Android編程實(shí)現(xiàn)自定義分享列表ACTION_SEND功能的方法,結(jié)合實(shí)例形式詳細(xì)分析了自定義分享列表功能的步驟與具體操作技巧,需要的朋友可以參考下
    2017-02-02
  • Android Studio手動(dòng)配置Gradle的方法

    Android Studio手動(dòng)配置Gradle的方法

    Gradle:Gradle是一個(gè)基于Apache Ant和Apache Maven概念的項(xiàng)目自動(dòng)化建構(gòu)工具。它使用一種基于Groovy的特定領(lǐng)域語(yǔ)言(DSL)來(lái)聲明項(xiàng)目設(shè)置,拋棄了基于XML的各種繁瑣配置,本文給大家介紹Android Studio手動(dòng)配置Gradle的方法,一起看看吧
    2017-11-11
  • Android網(wǎng)絡(luò)編程之UDP通信模型實(shí)例

    Android網(wǎng)絡(luò)編程之UDP通信模型實(shí)例

    這篇文章主要介紹了Android網(wǎng)絡(luò)編程之UDP通信模型實(shí)例,本文給出了服務(wù)端代碼和客戶端代碼,需要的朋友可以參考下
    2014-10-10
  • Android全面屏與異形(劉海)屏的適配教程

    Android全面屏與異形(劉海)屏的適配教程

    Apple一直在引領(lǐng)設(shè)計(jì)的潮流,自從 iPhone X 發(fā)布之后,各種異形屏、劉海屏也都出來(lái),下面這篇文章主要給大家分享介紹了關(guān)于Android全面屏與異形(劉海)屏的適配教程,文中通過(guò)示例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2018-07-07
  • Android Studio ADB網(wǎng)絡(luò)調(diào)試匯總

    Android Studio ADB網(wǎng)絡(luò)調(diào)試匯總

    這篇文章主要為大家詳細(xì)介紹了Android Studio ADB網(wǎng)絡(luò)調(diào)試的方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2018-05-05

最新評(píng)論

平利县| 南汇区| 花垣县| 商都县| 通海县| 普陀区| 明溪县| 双峰县| 南川市| 奉新县| 甘肃省| 浑源县| 万宁市| 习水县| 新干县| 祁连县| 襄城县| 科技| 青冈县| 固阳县| 德阳市| 桐庐县| 肃宁县| 元谋县| 伊金霍洛旗| 永康市| 天峨县| 庄河市| 百色市| 长海县| 惠安县| 隆化县| 克什克腾旗| 五家渠市| 尚志市| 定西市| 米脂县| 保德县| 平顺县| 尚义县| 大名县|