1. 程式人生 > >Activity新增滑動關閉功能-[Android_YangKe]

Activity新增滑動關閉功能-[Android_YangKe]

code小生,一個專注 Android 領域的技術分享平臺

作者:Android_YangKe
地址:https://www.jianshu.com/p/d62cda41017c
宣告:本文已獲 Android_YangKe 授權,轉發等請聯絡原作者授權

微信是騰訊家族的一款旗艦產品,前些日子實在無聊就可勁刷朋友圈,剎那間發現微信具有二級頁面滑動關閉功能,(屏隨指動,縱享絲滑)使用者好感倍增,頓時兩眼泛水花開始膜拜大廠產品,工程師。

努力成為自己想要成為的人,心中默唸:“當你停下來休息的時候,不要忘記別人還在奔跑”。於是開始學習相關技術豐富自己。百度,Google,Github,功夫不負有心人,通過自己幾個小時的努力實現了自己想要的效果。我們看圖:

640Android_YangKe.gif640Android_YangKe.gif

由於動態圖壓縮比較嚴重,這裡進行簡單講解。圖一效果主要是:當我們手指沒有將頁面拖動到螢幕中間及後半部分時,應用會自動回彈到原始狀態,當我們將頁面拖動到屏幕後半部分時頁面會 finish 掉。功能實現了,具體思路是什麼呢?如果你對Activity,Window,View 整體輪廓不是很熟悉,請做知識儲備 點我。

下面我們看下專案結構:

640Android_YangKe.png

不要重複造輪子,沒錯這是一個三方庫。但我們爭取做到知其然,知其所以然。下面開始我們的分析,注意其中這樣幾個 API:

  • SwipeBackActivity

  • SwipeBackActivityHelper

  • SwipeBackActivityBase

  • SwipeBackLayout

  • ViewDragHelper

SwipeBackActivityBase

SwipeBackActivityBase從命名上我們可以看出此類為基類,它是滑動關閉 Activity 的抽象。為什麼選擇基類入手?一般閱讀原始碼程式碼量都比較大,從基類入手便於我們瞭解整體框架輪廓,至於實現細節,我們根據需要再來分析。

程式碼之旅,即將開始:3,2,1…

public interface SwipeBackActivityBase {
    /**
     * 從當前 Activity 返回關聯的 SwipeBackLayout 物件
     */

    public abstract SwipeBackLayout getSwipeBackLayout();
    /**
      * 設定開啟或者關閉滑動關閉 Activity 功能
      */

    public abstract void setSwipeBackEnable(boolean enable);

    /**
     * 滑動 Activity 關閉 Activity 函式的抽象
     */

    public abstract void scrollToFinishActivity();
}

從以上程式碼我們可以 get 到三個技能點:
1> 獲取當前 Activity 關聯的 SwipeBackLayout 物件
2> 開啟或者關閉滑動 Activity 關閉 Activity 的功能
3> 滑動關閉 Activity

SwipeBackActivity

SwipeBackActivity是SwipeBackActivityBase的具體實現。也就是說我們的 Activity 繼承此類後相應的頁面就具有了滑動關閉功能。我們繼續,前方有大量原始碼即將來襲,請注意查收!

public class SwipeBackActivity extends AppCompatActivity implements SwipeBackActivityBase {
    private SwipeBackActivityHelper mHelper;

    @Override protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mHelper = new SwipeBackActivityHelper(this);
        mHelper.onActivityCreate();
    }

    @Override protected void onPostCreate(Bundle savedInstanceState) {
        super.onPostCreate(savedInstanceState);
        mHelper.onPostCreate();
    }

    @Override public SwipeBackLayout getSwipeBackLayout() {
        return mHelper.getSwipeBackLayout();
    }

    @Override public void setSwipeBackEnable(boolean enable) {
        getSwipeBackLayout().setEnableGesture(enable);
    }

    @Override public void scrollToFinishActivity() {
        Utils.convertActivityToTranslucent(this);
        getSwipeBackLayout().scrollToFinishActivity();
    }
}

程式碼是不是看起來很簡潔,但簡潔並不代表簡單。我們可以看到SwipeBackActivity實現了SwipeBackActivityBase並重寫了相應函式。同時,使用者的滑動方向,手勢判斷,滑動陰影一併完成。良好的設計模式在這裡體現的淋漓盡致,內功很重要,扯遠了哈。通過以上程式碼我們可以獲取到以下資訊:
1> 首次出現的 SwipeBackActivityHelper
2> 我通過 SwipeBackActivityHelper 物件獲取 SwipeBackLayout 物件
3> scrollToFinishActivity 函式的實現

不知道大家有沒有發現一個共同點就是,所有的操作都必須依託於SwipeBackLayout物件,而SwipeBackLayout物件又依託於SwipeBackActivityHelper,好吧,我們來看下SwipeBackActivityHelper。

當我翻開原始碼的時候其實內心是拒絕的,作者竟然沒有給出一行註釋。不過好在程式碼量不大,硬著頭皮讀吧。

public class SwipeBackActivityHelper {
    private Activity mActivity;
    private SwipeBackLayout mSwipeBackLayout;

    public SwipeBackActivityHelper(Activity activity) this.mActivity = activity; }

    /**
     * 1> 處理 Activity 關聯的 Window 背景
     * 2> 處理 Window 關聯的 DecorView 物件
     * 3> 初始化 SwipeBackLayout 物件
     */

    public void onActivityCreate() {
        mActivity.getWindow().setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
        mActivity.getWindow().getDecorView().setBackgroundDrawable(null);
        mSwipeBackLayout = (SwipeBackLayout) LayoutInflater.from(mActivity).inflate(
                me.imid.swipebacklayout.lib.R.layout.swipeback_layout, null);
    }

    public void onPostCreate() {
        mSwipeBackLayout.attachToActivity(mActivity);
    }

    public SwipeBackLayout getSwipeBackLayout() {
        return mSwipeBackLayout;
    }
}

onActivityCreate文中已經給出了註釋,這裡不再進行說明。程式碼掐頭去尾就剩下onPostCreate函式,現在讓我們找到SwipeBackLayout.java,然後定位到attachToActivity函式。

//SwipeBackLayout.java
public void attachToActivity(Activity activity) {
        ...程式碼省略...
        mActivity = activity;
        ViewGroup decor = (ViewGroup) activity.getWindow().getDecorView();
        ViewGroup decorChild = (ViewGroup) decor.getChildAt(0);
        decorChild.setBackgroundResource(background);
        decor.removeView(decorChild);
        addView(decorChild);
        setContentView(decorChild);
        addSwipeListener(new SwipeBackListenerActivityAdapter(activity));
        decor.addView(this);
    }

通過對上文的分析我們可以獲取到以下幾點資訊:
1> 從當前 Activity 中獲取 DecorView。DecorView 與 Activity 的恩怨情仇
2> 將手勢監聽與當前 Activity 繫結
3> 將 SwipeBackLayout 新增到 DecorView,也可以理解為將檢視依託在 Activity 上進行展示。

SwipeBackLayout

public class SwipeBackLayout extends FrameLayout {
    ...程式碼省略百行...
}

對於自定義 View、ViewGroup 來說,一般程式碼量都比較大,動則成百上千,那麼我們該使用什麼樣的姿勢來開啟它呢。其實從自定義 View 的幾個關鍵函式開始就行,當然還有就是建構函式。

public SwipeBackLayout(Context context, AttributeSet attrs, int defStyle) {
    ...程式碼省略...
    mDragHelper = ViewDragHelper.create(thisnew ViewDragCallback());//構建ViewDragHelper
    int mode = EDGE_FLAGS[a.getInt(R.styleable.SwipeBackLayout_edge_flag, 0)];
    setEdgeTrackingEnabled(mode);//設定滑動關閉 Activity 的模式。例:左側關閉,右側關閉等。

    int shadowLeft = a.getResourceId(R.styleable.SwipeBackLayout_shadow_left, R.drawable.shadow_left);
    int shadowRight = a.getResourceId(R.styleable.SwipeBackLayout_shadow_right, R.drawable.shadow_right);
    int shadowBottom = a.getResourceId(R.styleable.SwipeBackLayout_shadow_bottom, R.drawable.shadow_bottom);
    setShadow(shadowLeft, EDGE_LEFT);//設定左側滑動時的陰影
    setShadow(shadowRight, EDGE_RIGHT);//設定右側滑動時的陰影
    setShadow(shadowBottom, EDGE_BOTTOM);//設定底部滑動時的陰影
}

經過分析建構函式中大概做了如下幾件事情:
1> 初始化屬性資訊
2> 構建 ViewDragHelper 物件
3> 初始化頁面滾動時左、右、下側陰影部分

然後就是 set 函式:
1> setEdgeTrackingEnabled //設定滑動方向。例:左側滑動,右側滑動
2> setShadow //設定陰影方向。例:左側,右側
3> setSwipeBackEnable // 設定是否開啟滑動關閉功能,預設為 true
… 等等

總結:

如何給自己的應用新增滑動關閉 Activity 功能?

  • 將自己 Activity 繼承自 SwipeBackActivity

如何開啟或關閉“滑動關閉功能”?

  • 呼叫 setSwipeBackEnable(false); 可以禁止滑動關閉功能

如何修改滑動關閉 Activity 的方向?

  • setEdgeTrackingEnabled(SwipeBackLayout.EDGE_XXX);

對於 SwipeBackLayout 的理解:
1> 將依附在 Activity 上的 Window、DecorView 背景設定為空,透明
2> 將 DecorView 替換為 SwipeBackLayout
3> 對 SwipeBackLayout 進行手勢監聽,處理滑動事件動態更新頁面

APK 下載
http://yangwenxue.gitee.io/test/personfile/search-1.0-2018-06-19-release.apk

640

相關推薦

Activity新增滑動關閉功能-[Android_YangKe]

code小生,一個專注 Android 領域的技術分享平臺作者:Android_YangKe地址

使用Snake,安卓也能輕鬆實現類iOS滑動關閉功能

坦率地講,我並不是一個果粉。我也不覺得iOS系統比Android優秀,曾經有過一段時間將iPhone用作主流機。最後還是換成了安卓機,原因是iPhone的價效比的確不高,加上系統的一些限制,可玩性非常有限。而如果你問我,iOS系統裡面有什麼你特別喜歡的功能,滑動關閉無疑

實現對Activity的定時關閉功能

package com.zbar.lib.decode;import android.app.Activity;import android.content.DialogInterface;public final c

Android 滑動關閉Activity 示例

先看效果圖 : 要用到的 知識點 :1. 滑動處理         2.滑動衝突處理        3.設定Activity的主題        4. 位移動畫         5. 滑動的監聽

Android activity 單手操作 滑動關閉

介紹 在知乎客戶端上看到了這種效果,左滑Activity可以返回到上一介面,非常適合單手操作。 找了很久,終於在github上看到了SwipeBackLayout這個開源專案,地址: 實現 需要使用到的類: SwipeBackActivity.java SwipeBackLayout.java

android 向右滑動關閉Activity

import android.content.Context; import android.view.MotionEvent; import android.view.VelocityTracker; import android.view.View; /** *

【android開發】手勢滑動關閉Activity(隨手指消失)的輔助類的實現

【CSDN抽風,把我寫一個多小時的東西覆蓋了。真的是嗶了狗了,自己又沒有備份。。。重寫吧。。。】 這個類主要是實現向右滑動關閉Activity,效果如下: 老套路,先寫思路: 1)將Activity的背景設定為透明模式。(從而可以看到下一層Activi

android手勢滑動關閉當前activity

package com.bruce.testeventandscroll; import android.app.Activity; import android.os.Bundle; import android.util.Log; import android.vie

RecyclerView借助ItemTouchHelper實現拖動和滑動刪除功能

enable all istview aslist mar -- main erl pub RecyclerView是官方推薦代替ListView的空間,怎樣實現RecyclerView列表元素的拖動呢? 官方提供了ItemTouchHelper類使用過程例如以下

控制臺中屏蔽Ctrl+C快捷鍵對窗體的關閉功能

error -s tin else blog gof 發送 led ext 導入SetCtrlHandlerHandler API 1 //定義處理程序委托 2 public delegate bool ConsoleCtrlDelegate(int ctrlType

基於Intent實現ActivityActivity之間的數據傳遞,實現二個Activity的跳轉功能

set second start pub category 方式 nds efi dac 在講參數傳遞之前,先講下intent的定義: Intent intent = new Intent(MainActivity.this,SecondActivity.class

laydate點擊月份實現自動關閉功能

laydate<pre> laydate.render({ elem:‘#settleMonth‘, type:‘month‘, format:‘yyyy-MM‘, showBottom:false, ready:function(date){

vue 動態生成input進行操作——簡單實現新增刪除聯絡人功能

實現類似的如圖功能: 程式碼如下: <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>修改實現新增聯絡人

webapi 利用 ActionFilter 為 ASP.NET Web API 新增 GZip 壓縮功能

webapi 利用 ActionFilter 為 ASP.NET Web API 新增 GZip 壓縮功能 先直接上程式碼 /// <summary> /// 對結果進行壓縮處理 /// </summary> public class De

Vue 新增滑動條監聽

在鉤子中新增監聽  mounted () { const _this = this document.documentElement.addEventListener('scroll', _this.handleScroll, true) }, &nbs

用css巧妙實現移動端橫向滑動展示功能

公司需要做一個手機橫向滑動的效果,不想用js外掛,太麻煩,匯入程式碼也多。所以去網上找了一下,用css就能實現,挺方便的。主要利用了display:-webkit-box來實現。 <!DOCTYPE html> <html> <head> <ti

vue專案中實現新增收藏的功能,以及利用vue-resource傳送請求

1.新增收藏功能     建立一張表,儲存歌手id,使用者id,利用外來鍵將歌手錶與使用者表關聯起來。如果新增收藏之後,為該使用者新增一條資料,取消收藏後,將該條資料刪除。     當用戶登入之後才能顯示歌手列表中該使用者已經收藏過的歌手,然後將這些收

為我們的 Vue SSR程式新增熱更新功能

前沿 通過上一篇文章 通過vue-cli3構建一個SSR應用程式 我們知道了什麼是SSR,以及如何通過vue-cli3構建一個SSR應用程式。但是最後遺留了一些問題沒有處理,就是沒有新增開發時的熱更新功能,難道要每次更新程式碼都要重新編譯打包嗎?顯然不是很合理。那接下來我們將為該SSR程式新增熱更新的功能。

RDIFramework.NET V3.3 Web版新增日程管理功能模塊

iso 掃描二維碼 windows服務 framework 系統 images web 時間 完全 功能描述 在RDIFramework.NET V3.3 Web版本我們新增了日程管理。基於月、周、日的日歷視圖,把安排到每一天的具體時間點,讓每一天的時間都充分利用;甚至您也

php實現一個簡單的新增查詢統計功能

<?php require('config.inc.php'); date_default_timezone_set("Asia/Shanghai"); header("Content-type: text/html; charset=utf-8"); $str_from = $