[Android開源框架]AnyLayer使用說明

AnyLayer

Android穩(wěn)定高效的浮層創(chuàng)建管理框架。

可取代系統(tǒng)自帶Dialog/Popup/BottomSheet等彈窗,可實(shí)現(xiàn)單Activity架構(gòu)的Toast提示,可定制任意樣式的Guide引導(dǎo)層,可實(shí)現(xiàn)依附Activity的Float懸浮按鈕。

GitHub主頁

Demo下載

簡介

  • 同時(shí)兼容support和androidx
  • 鏈?zhǔn)秸{(diào)用
  • 支持自由擴(kuò)展
  • 實(shí)現(xiàn)幾種常用效果
    • Dialog效果
      • 占用區(qū)域不會(huì)超過當(dāng)前Activity避免導(dǎo)航欄遮擋
      • 支持自定義大小和顯示位置
      • 支持自定義數(shù)據(jù)綁定
      • 支持自定義進(jìn)出場動(dòng)畫
      • 支持自定義背景顏色/圖片/高斯模糊
      • 支持在Activity的onCreate生命周期彈出
      • 支持從ApplicationContext中彈出
    • Popup效果
      • 擁有Dialog效果特性
      • 支持跟隨目標(biāo)View移動(dòng)
    • Toast效果
      • 支持自定義圖標(biāo)和文字
      • 支持自定義顯示時(shí)長
      • 支持自定義位置
      • 支持自定義背景資源和顏色
      • 支持自定義透明度
      • 支持自定義進(jìn)出場動(dòng)畫
    • Guide效果
      • 引導(dǎo)層效果待開發(fā)
    • Float效果
      • 懸浮按鈕效果待開發(fā)

說明

詳細(xì)原理和使用說明本人會(huì)在后續(xù)補(bǔ)上,但因個(gè)人開發(fā),時(shí)間不定,請(qǐng)諒解。

或有大佬在看過源碼后,愿意寫下分析文章或使用說明來分享的,歡迎聯(lián)系本人。寫得比較詳細(xì)的本人將會(huì)放到README中供大家查閱,提前謝過。

當(dāng)然也歡迎加群共同探討,共同進(jìn)步。

QQ群:147715512(愛Android)

使用該庫的產(chǎn)品

如果你的產(chǎn)品正在使用AnyLayer,歡迎留下相關(guān)信息

這些信息將用來幫助更多開發(fā)者關(guān)注并使用本框架,增加框架的活躍度。而高活躍度則意味著更多隱藏BUG被發(fā)現(xiàn)并修復(fù),即活躍度等同于框架的健壯性。同時(shí)這也是我維護(hù)項(xiàng)目的最大動(dòng)力,感謝。

APP名 APP圖標(biāo) 公司名
玩安卓
個(gè)人
熊貓?zhí)詫W(xué)
西安熊貓寶寶網(wǎng)絡(luò)科技有限公司
MBA大師
MBA大師

截圖

截圖效果較差且版本較老,建議下載Demo體驗(yàn)最新功能

使用說明

集成

  • 添加jitpack庫

// build.gradle(Project:)
allprojects {
    repositories {
        ...
            maven { url 'https://www.jitpack.io' }
    }
}
  • 添加依賴

    點(diǎn)擊查看最新版本號(hào)

    引用時(shí)需注意版本號(hào),從2.3.1版本開始,版本號(hào)前不加v。

    通用庫為在2.4.0版本新增,有效引用為2.4.0~2.5.0之間版本。

    從3.0.0版本開始,框架重構(gòu),刪除通用庫。因重構(gòu)代碼變化較大,不建議使用較多的老項(xiàng)目升級(jí),保持2.5.0版即可,在實(shí)現(xiàn)Dialog/Popup等效果上無本質(zhì)差別。

    從3.1.0版本開始移除對(duì)support-v7的依賴,可同時(shí)兼容support和androidx

// build.gradle(Module:)
dependencies {
    // 完整引入
    implementation 'com.github.goweii:AnyLayer:3.2.0'
    
    // 基礎(chǔ)庫
    // implementation 'com.github.goweii.AnyLayer:anylayer:2.5.0'
    
    // 通用彈窗(依賴基礎(chǔ)庫)
    // 從3.0.0版本暫時(shí)刪除
    // implementation 'com.github.goweii.AnyLayer:anylayer-common:2.5.0'
}

類間關(guān)系

  • AnyLayer(提供常用效果的調(diào)用入口)

  • ViewManager(管理View的動(dòng)態(tài)添加移除和KeyEvent事件注冊(cè))

  • Layer(對(duì)ViewManager的包裝,實(shí)現(xiàn)進(jìn)出場動(dòng)畫邏輯和事件監(jiān)聽,規(guī)范接口形式,分離出ViewHolder/ListenerHolder/Config三大內(nèi)部類)

    • DecorLayer(規(guī)范父布局為DecorView的特殊Layer,引入了Layer層級(jí)概念)
      • DialogLayer(規(guī)范子布局層級(jí),加入背景層,分離動(dòng)畫為背景動(dòng)畫和內(nèi)容動(dòng)畫)
        • PopupLayer(可依據(jù)錨點(diǎn)View定位)
      • ToastLayer(定時(shí)消失,不響應(yīng)事件的Layer)
      • GuideLayer(引導(dǎo)層Layer)
      • FloatLayer(懸浮按鈕Layer)
  • AnimatorHelper(創(chuàng)建常用屬性動(dòng)畫)

類說明

AnyLayer

一個(gè)工廠效果的工具類,與Layer類族的關(guān)系就像Executors于Executor的關(guān)系這樣。

只是提供了靜態(tài)方法方便調(diào)用,不用new來new去的。

/**
 * 初始化高斯模糊,可在用到高斯模糊背景的Activity的onCreate方法調(diào)用
 * 其實(shí)不調(diào)用也沒關(guān)系,第一次顯示的時(shí)候也會(huì)初始化的,只是這樣第一次顯示就會(huì)比后面顯示稍微慢一點(diǎn)
 */
public static void initBlurred(Context context)

/**
 * 回收高斯模糊內(nèi)存占用,可在用到高斯模糊背景的Activity的onDestroy方法調(diào)用,也可以在內(nèi)存不足時(shí)調(diào)用
 */
public static void recycleBlurred()

/**
 * 創(chuàng)建一個(gè)DialogLayer
 * 這個(gè)Context不能是ApplicationContext
 */
public static DialogLayer dialog(Context context)

/**
 * 創(chuàng)建一個(gè)DialogLayer
 * 依附的是當(dāng)前顯示的Activity
 */
public static DialogLayer dialog()

/**
 * 創(chuàng)建一個(gè)DialogLayer
 * 依附的是特定Class的Activity實(shí)例,這個(gè)Activity必須是已經(jīng)啟動(dòng)的
 */
public static DialogLayer dialog(Class<Activity> clazz)

/**
 * 創(chuàng)建一個(gè)DialogLayer
 * 會(huì)啟動(dòng)一個(gè)新的全透明Activity依附
 */
public static void dialog(LayerActivity.OnLayerCreatedCallback callback)

/**
 * 創(chuàng)建一個(gè)PopupLayer
 */
public static PopupLayer popup(View targetView)

/**
 * 創(chuàng)建一個(gè)ToastLayer
 * 依附的是當(dāng)前顯示的Activity
 */
public static ToastLayer toast()

/**
 * 創(chuàng)建一個(gè)ToastLayer
 * 這個(gè)Context不能是ApplicationContext
 */
public static ToastLayer toast(Context context)

ViewManager

這個(gè)就不介紹了吧?一般用的時(shí)候也用不到,后面原理剖析的時(shí)候再說吧!

Layer

上面類間關(guān)系簡單描述了一下

對(duì)ViewManager的包裝,實(shí)現(xiàn)進(jìn)出場動(dòng)畫邏輯和事件監(jiān)聽,規(guī)范接口形式,分離出ViewHolder/ListenerHolder/Config三大內(nèi)部類

可以看出這個(gè)類是所有效果的基類,有以下幾個(gè)特定:

  • 對(duì)ViewManager的包裝

    可以自由指定父布局和子布局,可以通過繼承在onGetParent和onCreateChild中返回,也可以通過parent()和child()方法設(shè)置。

    其次是幾個(gè)生命周期回調(diào)方法

    • onAttach(View剛被添加到父布局)
    • onPreDraw(View開始繪制前,這里開始執(zhí)行進(jìn)場動(dòng)畫)
    • onShow(View顯示,進(jìn)場動(dòng)畫結(jié)束)
    • onPreRemove(View準(zhǔn)備移除時(shí),這里開始執(zhí)行出場動(dòng)畫)
    • onDetach(View已被移除,出場動(dòng)畫結(jié)束)
  • 實(shí)現(xiàn)進(jìn)出場動(dòng)畫邏輯

    在onPreDraw和onPreRemove中實(shí)現(xiàn)了進(jìn)出場動(dòng)畫的流程。可通過繼承在onCreateInAnimator和onCreateOutAnimator中返回,也可以通過animator()方法設(shè)置。

    其中AnimatorCreator為創(chuàng)建自定義進(jìn)出場動(dòng)畫的接口

  • 事件監(jiān)聽

    有幾個(gè)常用的事件監(jiān)聽,在ListenerHolder中統(tǒng)一管理

    • DataBinder(綁定數(shù)據(jù))
    • OnClickListener(點(diǎn)擊事件監(jiān)聽)
    • OnShowListener(顯示動(dòng)畫開始和結(jié)束監(jiān)聽)
    • OnDismissListener(消失時(shí)動(dòng)畫開始和結(jié)束監(jiān)聽)
    • OnVisibleChangeListener(顯示隱藏狀態(tài)改變的監(jiān)聽)
  • 分離出ViewHolder/ListenerHolder/Config三大內(nèi)部類

    這個(gè)看名字應(yīng)該就知道了,就不介紹了。

  • 常用方法

    /**
     * 一組控制顯示隱藏的方法
     */
    public void show()
    public void show(boolean withAnim)
    public void dismiss()
    public void dismiss(boolean withAnim)
        
    /**
     * 判斷當(dāng)前顯示隱藏狀態(tài)
     */  
    public boolean isShow()
        
    /**
     * 根據(jù)ID獲取對(duì)應(yīng)View
     */  
    public <V extends View> V getView(int id)
        
    /**
     * 指定父布局
     */  
    public Layer parent(ViewGroup parent)
        
    /**
     * 指定子布局
     */  
    public Layer child(View child)
        
    /**
     * 自定義進(jìn)出場動(dòng)畫
     */  
    public Layer animator(AnimatorCreator creator)
    
    /**
     * 是否攔截物理按鍵,為true時(shí)cancelableOnKeyBack才有效
     */  
    public Layer interceptKeyEvent(boolean intercept)
        
    /**
     * 是否可點(diǎn)擊返回鍵關(guān)閉浮層,interceptKeyEvent為true才有效
     */  
    public Layer cancelableOnKeyBack(boolean cancelable)
        
    /**
     * 一組事件監(jiān)聽,見上面介紹
     */  
    public Layer bindData(DataBinder dataBinder)
    public Layer onVisibleChangeListener(OnVisibleChangeListener onVisibleChangeListener)
    public Layer onShowListener(OnShowListener onShowListener)
    public Layer onDismissListener(OnDismissListener onDismissListener)
        
    /**
     * 點(diǎn)擊某些控件關(guān)閉浮層
     */  
    public Layer onClickToDismiss(OnClickListener listener, int... viewIds)
    public Layer onClickToDismiss(int... viewIds)
        
    /**
     * 對(duì)控件綁定點(diǎn)擊事件
     */  
    public Layer onClick(OnClickListener listener, int... viewIds)
    

DecorLayer

繼承自Layer,強(qiáng)制父布局為DecorView。主要就是引入了Layer層級(jí)概念。

而這個(gè)層級(jí)就是由兩個(gè)靜態(tài)內(nèi)部類實(shí)現(xiàn)的

  • LayerLayout

    繼承自FrameLayout,是各個(gè)層級(jí)浮層的容器,直接添加進(jìn)DecorView。

  • LevelLayout

    繼承自FrameLayout,定義了Level概念,是每個(gè)浮層的父布局,也就是在外面包了一層,用來控制浮層上下層級(jí)的容器。這個(gè)是直接添加進(jìn)LayerLayout的。

好了就這么多了。更多了細(xì)節(jié)還是看源碼吧。

DialogLayer

這個(gè)就是模仿傳說中Dialog效果的浮層。用上面的描述就是:

規(guī)范子布局層級(jí),加入背景層,分離動(dòng)畫為背景動(dòng)畫和內(nèi)容動(dòng)畫

一個(gè)一個(gè)來看。

  • 規(guī)范子布局層級(jí),加入背景層

    從DecorLayer的介紹中可以知道LevelLayout是該類浮層的直接父布局。但它并不是DialogLayer中contentView的直接父布局。就是因?yàn)橛旨恿艘粋€(gè)ViewGroup把contextView和background包裹起來。布局文件是這樣子的。

    <?xml version="1.0" encoding="utf-8"?>
    <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:id="@+id/fl_container"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:clickable="true">
    
        <ImageView
            android:id="@+id/iv_background"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:scaleType="centerCrop"/>
    
        <FrameLayout
            android:id="@+id/fl_content_wrapper"
            android:layout_width="match_parent"
            android:layout_height="match_parent" />
    
    </FrameLayout>
    

    contentView其實(shí)是直接添加至fl_content_wrapper中的。

  • 分離動(dòng)畫為背景動(dòng)畫和內(nèi)容動(dòng)畫

    因?yàn)橛辛薱ontextView和background的概念,原來的動(dòng)畫就不好用了。所以從寫了動(dòng)畫的創(chuàng)建邏輯,分離了背景和前景應(yīng)用不同的動(dòng)畫。

最后看下常用的方法。

/**
 * 設(shè)置自定義布局View/資源ID
 */
public DialogLayer contentView(View contentView)
public DialogLayer contentView(int contentViewId)

/**
 * 設(shè)置自定義布局文件中狀態(tài)欄的占位View
 * 該控件高度將設(shè)置為狀態(tài)欄高度,可用來使布局整體下移,避免狀態(tài)欄遮擋
 */
public DialogLayer asStatusBar(int statusBarId)

/**
 * 設(shè)置避開狀態(tài)欄
 */
public DialogLayer avoidStatusBar(boolean avoid)

/**
 * 設(shè)置子布局的gravity
 * 可直接在布局文件指定layout_gravity屬性,作用相同
 */
public DialogLayer gravity(int gravity)

/**
 * 自定義浮層的進(jìn)入和退出動(dòng)畫
 */
public DialogLayer contentAnimator(AnimatorCreator contentAnimatorCreator)

/**
 * 自定義背景的進(jìn)入和退出動(dòng)畫
 */
public DialogLayer backgroundAnimator(AnimatorCreator backgroundAnimatorCreator)

/**
 * 設(shè)置背景高斯模糊/圖片/顏色
 */
public DialogLayer backgroundBlurRadius(float radius)
public DialogLayer backgroundBlurPercent(float percent)
public DialogLayer backgroundBlurScale(float scale)
public DialogLayer backgroundBitmap(Bitmap bitmap)
public DialogLayer backgroundDimAmount(float dimAmount)
public DialogLayer backgroundResource(int resource)
public DialogLayer backgroundDrawable(Drawable drawable)
public DialogLayer backgroundColorInt(int colorInt)
public DialogLayer backgroundColorRes(int colorRes)

/**
 * 設(shè)置點(diǎn)擊浮層以外區(qū)域是否可關(guān)閉
 */
public DialogLayer cancelableOnTouchOutside(boolean cancelable)

/**
 * 設(shè)置點(diǎn)擊返回鍵是否可關(guān)閉
 */
public DialogLayer cancelableOnClickKeyBack(boolean cancelable)

算了,再看下調(diào)用代碼湊湊字?jǐn)?shù)把。

AnyLayer.dialog(this)
        .contentView(R.layout.dialog_test_2)
        .backgroundColorRes(R.color.dialog_bg)
        .gravity(Gravity.CENTER)
        .cancelableOnTouchOutside(true)
        .cancelableOnClickKeyBack(true)
        .bindData(new Layer.DataBinder() {
            @Override
            public void bindData(Layer layer) {
                // TODO 綁定數(shù)據(jù)
            }
        })
        .onClickToDismiss(R.id.fl_dialog_no)
        .show();

PopupLayer

因?yàn)槔^承自DialogLayer,所以可以使用定義過的方法(這不是廢話嗎)。

主要就是加入了可依據(jù)錨點(diǎn)View定位。

這個(gè)效果可能還要重構(gòu),暫時(shí)就不介紹了。

看下其他新增方法。

/**
 * 設(shè)置浮層外部是否攔截觸摸
 * 默認(rèn)為true,false則事件有activityContent本身消費(fèi)
 */
public PopupLayer outsideInterceptTouchEvent(boolean intercept)

/**
 * 是否裁剪contentView至包裹邊界
 */
public PopupLayer contentClip(boolean clip)

/**
 * 是否偏移背景對(duì)齊目標(biāo)控件
 */
public PopupLayer backgroundAlign(boolean align)

/**
 * 背景應(yīng)用offset設(shè)置
 */
public PopupLayer backgroundOffset(boolean offset)

/**
 * 當(dāng)以target方式創(chuàng)建時(shí)為參照View位置顯示
 * 可自己指定浮層相對(duì)于參照View的對(duì)齊方式
 */
public PopupLayer align(Align.Direction direction,
                        Align.Horizontal horizontal,
                        Align.Vertical vertical,
                        boolean inside)

/**
 * 指定浮層相對(duì)于參照View的對(duì)齊方式
 */
public PopupLayer direction(Align.Direction direction)

/**
 * 指定浮層相對(duì)于參照View的對(duì)齊方式
 */
public PopupLayer horizontal(Align.Horizontal horizontal)

/**
 * 指定浮層相對(duì)于參照View的對(duì)齊方式
 */
public PopupLayer vertical(Align.Vertical vertical)

/**
 * 指定浮層是否強(qiáng)制位于屏幕內(nèi)部
 */
public PopupLayer inside(boolean inside)

/**
 * X軸偏移
 */
public PopupLayer offsetX(float offsetX, int unit)
public PopupLayer offsetXdp(float dp)
public PopupLayer offsetXpx(float px)
/**
 * Y軸偏移
 */
public PopupLayer offsetY(float offsetY, int unit)
public PopupLayer offsetYdp(float dp)
public PopupLayer offsetYpY(float px)

國際慣例,最后看下調(diào)用代碼湊湊字?jǐn)?shù)。

AnyLayer.popup(targetView)
        .contentView(R.layout.dialog_test_4)
        .backgroundColorRes(R.color.dialog_bg)
        .direction(Align.Direction.VERTICAL)
        .horizontal(Align.Horizontal.CENTER)
        .vertical(Align.Vertical.BELOW)
        .inside(true)
        .contentAnim(new LayerManager.IAnim() {
            @Override
            public Animator inAnim(View content) {
                return AnimHelper.createTopInAnim(content);
            }

            @Override
            public Animator outAnim(View content) {
                return AnimHelper.createTopOutAnim(content);
            }
        })
        .show();

ToastLayer

累了,這個(gè)寫簡單點(diǎn),就看下調(diào)用代碼算了。

AnyLayer.toast()
        .duration(3000)
        .icon(isSucc ? R.drawable.ic_success : R.drawable.ic_fail)
        .message(isSucc ? "哈哈,成功了" : "哎呀,失敗了")
        .show();

GuideLayer

待實(shí)現(xiàn)

FloatLayer

待實(shí)現(xiàn)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 178,781評(píng)論 25 709
  • 用兩張圖告訴你,為什么你的 App 會(huì)卡頓? - Android - 掘金 Cover 有什么料? 從這篇文章中你...
    hw1212閱讀 13,913評(píng)論 2 59
  • 1、通過CocoaPods安裝項(xiàng)目名稱項(xiàng)目信息 AFNetworking網(wǎng)絡(luò)請(qǐng)求組件 FMDB本地?cái)?shù)據(jù)庫組件 SD...
    陽明AI閱讀 16,172評(píng)論 3 119
  • 你香染如玉,你詩畫如墨,你是八旗中的貴族,你是千古一帝的寵臣。 你曾意氣風(fēng)發(fā),你曾揮斥方遒,數(shù)百年如白駒過隙,你卻...
    曜墨閱讀 464評(píng)論 0 3
  • 設(shè)計(jì)師一般只提供一套尺寸的設(shè)計(jì)稿,如何實(shí)現(xiàn)一套代碼實(shí)現(xiàn)多端自適應(yīng)?一般設(shè)計(jì)師出的設(shè)計(jì)稿都是2倍圖 效果演示 假設(shè)一...
    神秘者007閱讀 2,588評(píng)論 0 5

友情鏈接更多精彩內(nèi)容