Android DialogFragment、BottomSheetDialogFragment的基本使用

在前面兩篇我們介紹了Fragment的基本使用和Fragment配套ViewPager的使用,接下來我們就來看看除此之外其他的平時不常用但是我們很有必要掌握的其他的Fragment的基本使用。主要介紹的就是兩種:DialogFragment和BottomSheetDialogFragment。

(一)DialogFragment

DialogFragment看名字就知道是Dialog樣式的Fragment,其推出的初衷就是為了解決傳統(tǒng)Dialog無法與宿主的生命周期綁定導致需要后臺時刻監(jiān)聽其動態(tài)變化,特別當在旋轉(zhuǎn)屏幕的時候會出現(xiàn)問題。而使用DialogFragment就可以很好的去解決這個問題,下面就一起來看看DialogFragment。

DialogFragment的使用:

DialogFragment的使用很簡單,首先新建一個類繼承自DialogFragment:

class BlankDialogFragment : DialogFragment() {

    override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
        val dialog = AlertDialog.Builder(context,R.style.dialogFullScreen)
        dialog.setTitle("測試Dialog")
        dialog.setMessage("使用Dialog顯示DialogFragment")
        return dialog.create()
    }

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        return inflater.inflate(R.layout.dialog_fragment_layout,container,false)
    }

    override fun onStart() {
        val params = dialog?.window?.attributes
        params?.width = ViewGroup.LayoutParams.WRAP_CONTENT
        params?.height = ViewGroup.LayoutParams.WRAP_CONTENT
        dialog?.window?.attributes = params
        dialog?.window?.decorView?.background = ColorDrawable(Color.TRANSPARENT)
        super.onStart()
    }
}

在宿主Activity點擊顯示

fun showNormal(view: View) {
    val dialogFragment = BlankDialogFragment()
    dialogFragment.setStyle(DialogFragment.STYLE_NORMAL,R.style.dialogFullScreen)
    dialogFragment.show(supportFragmentManager,"dialogFragment")
}
DialogFragment的使用比較簡單,但是需要注意以下幾點:

(1)當onCreateDialog與onCreateView同時都工作的時候,onCreateDialog的優(yōu)先級高于onCreateView。

(2)無論是我們在onCreateDialog中創(chuàng)建的Dialog還是在onCreateView中創(chuàng)建的View都無法讓整個View在寬度上填充整個屏幕,那是因為dialog自帶的padding內(nèi)邊距屬性導致的,可以通過設置Dialog的樣式來解決。

(3)設置樣式的時候分為兩種,當顯示方式為onCreateDialog的時候,直接在創(chuàng)建AlertDialog實例的時候加上style。當顯示方式為onCreateView的時候,直接dialogFragment.setStyle(DialogFragment.STYLE_NORMAL,R.style.dialogFullScreen)。

(4)點擊外部不關閉對話框的設置方式有兩種:

  《1》在style樣式中加上
   <item name="android:windowCloseOnTouchOutside">false</item>
 《2》直接通過代碼設置 
  dialog?.setCanceledOnTouchOutside(false)

(5)屏蔽返回鍵 dialog?.setCancelable(false),同時也會導致點擊外部無法關閉對話框。

(6)給對話框設置透明背景:
dialog?.window?.decorView?.background = ColorDrawable(Color.TRANSPARENT)

Dialog的常見樣式:
//Theme.AppCompat.Dialog主題常用的一般有以下屬性:
<!-- 背景透明 -->  
<item name="android:windowBackground">@android:color/transparent</item>  
<!-- 邊框 -->  
<item name="android:windowFrame">@null</item>  
<!-- 是否浮現(xiàn)在activity之上 -->  
<item name="android:windowIsFloating">true</item>  
<!-- 是否半透明 -->  
<item name="android:windowIsTranslucent">true</item>  
<!-- 是否無標題 -->  
<item name="android:windowNoTitle">true</item>  
<!-- Dialog背景樣式 --> 
<item name="android:background">@android:color/transparent</item>  
<!-- 模糊 -->  
<item name="android:backgroundDimEnabled">true</item>  
<!-- 遮罩層 -->  
<item name="android:backgroundDimAmount">0.5</item> 
設置動畫:
override fun onStart() {
    val params = dialog?.window?.attributes
    params?.width = ViewGroup.LayoutParams.WRAP_CONTENT
    params?.height = ViewGroup.LayoutParams.WRAP_CONTENT
    dialog?.window?.attributes = params
    dialog?.window?.decorView?.background = ColorDrawable(Color.TRANSPARENT)
    dialog?.window?.setWindowAnimations(R.style.dialog_animation_style)
    super.onStart()
}

其中dialog?.window?.setWindowAnimations(R.style.dialog_animation_style)就是給dialogFragment設置動畫效果。其中dialog_animation_style的寫法為:

<style name="dialog_animation_style">
    <item name="android:windowEnterAnimation">@anim/dialog_show_anim</item>
    <item name="android:windowExitAnimation">@anim/dialog_miss_anim</item>
</style>

好了,到這里,dialogFragment的使用就結(jié)束了,是不是很容易。

(二)BottomSheetDialogFragment

首先貼一張圖


1.png

這是Android 官方網(wǎng)站上面的一個介紹BottomSheetDialogFragment的結(jié)構(gòu)圖,從官方文檔可以看出,BottomSheetDialogFragment是繼承自AppCompatDialogFragment,而
AppCompatDialogFragment又是繼承自DialogFragment,而DialogFragment是繼承自Fragment。所以,BottomSheetDialogFragment是DialogFragment的子類,具有DialogFragment的所有特性。

一個最簡單的BottomSheetDialogFragment的完整代碼為:

class BlankBottomSheetDialogFragment : BottomSheetDialogFragment() {

    override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
        return BottomSheetDialog(context!!)
    }

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        return inflater.inflate(R.layout.dialog_fragment_layout,container,false)
    }

    override fun onStart() {
        super.onStart()
    }
}

最終呈現(xiàn)的效果為:


3.png

其中我們點擊從底部彈出就呈現(xiàn)出BottomSheetDialogFragment的最終效果,其中藍色部分就是我們在onCreateView里面設置的自定義布局。需要注意的是BottomSheetDialogFragment本身是支持向上、向下滑動的,在沒有人為設置的情況下,其基本的滑動邏輯是這樣的:

(1)當我們在onCreateView里面設置的最終顯示的View的高度小于屏幕的60%的時候,是無法向上滑動的,而在手指進行拖動的時候,如果里面的View可以滑動,則這時候的手指滑動事件交由里面的View進行消費(無論是向上或者向下滑動),而一旦手指離開屏幕,再次下滑的時候事件會交給BottomSheetDialogFragment進行消費,這個時候會發(fā)現(xiàn)BottomSheetDialogFragment會被關閉。

(2)當我們在onCreateView里面設置的最終顯示的View的高度大于屏幕的60%的時候,是可以向上滑動的,最終向上滑動的距離取決于View最終的高度。當我們手指進行滑動的時候,如果手指向上滑動,則事件交由BottomSheetDialogFragment進行消費,當滑動到頂部的時候,這個時候再繼續(xù)向上滑動,事件則交由View進行消費。當向下滑動的時候,如果View展示的高度大于屏幕的60%的時候,松開手指,BottomSheetDialogFragment會自動停留在屏幕的60%的位置,如果View展示的高度小于屏幕的60%的時候,松開手指,BottomSheetDialogFragment會自動關閉。

(3)在進行滑動的時候,如果事件是由里面的View處理的話,無論是向上或者向下滑動,手指都不能離開屏幕,否則一旦離開屏幕后,再次滑動事件就由BottomSheetDialogFragment進行消費了。

一般情況下我們會在BottomSheetDialogFragment的onStart方法里面去做一些基本的設置,如下代碼所示:

override fun onStart() {
    super.onStart()
    // 獲取dialog對象
    val dialog = dialog
    // 獲取dialog的根布局
    val bottomSheet = dialog?.window?.findViewById<FrameLayout>(R.id.design_bottom_sheet)
    // 把windows的默認背景顏色去掉,不然圓角看不見
    bottomSheet?.background = ColorDrawable(Color.TRANSPARENT)
    // 獲取根布局的LayoutParams對象
    val layoutParams = bottomSheet?.layoutParams
    // 修改彈窗的最大高度,不允許上滑
    layoutParams?.height = getPeekHeight()
    bottomSheet?.layoutParams = layoutParams
    val behavior = BottomSheetBehavior.from(bottomSheet!!)
    behavior.peekHeight = getPeekHeight()
    // 初始化為展開狀態(tài)(默認為展開狀態(tài))
    // BottomSheetBehavior.STATE_HIDDEN:對應為隱藏狀態(tài)
    behavior.state = BottomSheetBehavior.STATE_EXPANDED
}

在這段代碼里面實現(xiàn)了很重要的兩個點:
(1)設置BottomSheetDialogFragment的背景為透明,方便自己設置的布局展現(xiàn)為自己想要的效果。
(2)修改彈窗的最大高度,不讓BottomSheetDialogFragment實現(xiàn)上滑。

禁用BottomSheetDialog的滑動

第一步:

private val mBottomSheetBehaviorCallback: BottomSheetCallback = object : BottomSheetCallback() {
    override fun onStateChanged(bottomSheet: View, newState: Int) {
        //禁止拖拽,
        if (newState == BottomSheetBehavior.STATE_DRAGGING) {
            //設置為收縮狀態(tài)
            behavior?.state = BottomSheetBehavior.STATE_COLLAPSED
        }
    }

    override fun onSlide(bottomSheet: View, slideOffset: Float) {}
}

第二步:

behavior?.addBottomSheetCallback(mBottomSheetBehaviorCallback)

最后需要重點強調(diào)一點的就是,因為BottomSheetDialogFragment自己有滑動,如果在我們的View里面也有可以滑動的控件并且是同方向的,比如RecyclerView、ScrollView等等,會產(chǎn)生滑動沖突,這個時候只需要在我們的View里面使用NestedScrollView來進行嵌套,就能完美的解決滑動沖突問題。

關于BottomSheetDialogFragment的介紹就到這里了,歡迎大家在下面留言~

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

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

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