国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

史上最完美的Android沉浸式狀態(tài)導(dǎo)航欄攻略

這篇具有很好參考價(jià)值的文章主要介紹了史上最完美的Android沉浸式狀態(tài)導(dǎo)航欄攻略。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問。

前言

最近我在小破站開發(fā)一款新App,叫高能鏈。我是一個完美主義者,所以不管對架構(gòu)還是UI,我都是比較摳細(xì)節(jié)的,在狀態(tài)欄和導(dǎo)航欄沉浸式這一塊,我還是踩了挺多坑,費(fèi)了挺多精力的。這次我將我踩坑,適配各機(jī)型總結(jié)出來的史上最完美的Android沉浸式狀態(tài)導(dǎo)航欄攻略分享給大家,大家也可以去 高能鏈官網(wǎng) 下載體驗(yàn)一下我們的App,實(shí)際感受一下沉浸式狀態(tài)導(dǎo)航欄的效果(登錄,實(shí)名等賬號相關(guān)頁面由于不是我開發(fā)的,就沒有適配沉浸式導(dǎo)航欄啦,嘻嘻)

注:此攻略只針對 Android 5.0 及以上機(jī)型,即 minSdkVersion >= 21

實(shí)際效果

在開始攻略之前,我們先看看完美的沉浸式狀態(tài)導(dǎo)航欄效果

傳統(tǒng)三鍵式導(dǎo)航欄

史上最完美的Android沉浸式狀態(tài)導(dǎo)航欄攻略

史上最完美的Android沉浸式狀態(tài)導(dǎo)航欄攻略

全面屏導(dǎo)航條

史上最完美的Android沉浸式狀態(tài)導(dǎo)航欄攻略

史上最完美的Android沉浸式狀態(tài)導(dǎo)航欄攻略

理論分析

在上具體實(shí)現(xiàn)代碼之前,我們先分析一下,實(shí)現(xiàn)沉浸式狀態(tài)導(dǎo)航欄需要幾步

  1. 狀態(tài)欄導(dǎo)航欄底色透明

  2. 根據(jù)當(dāng)前頁面的背景色,給狀態(tài)欄字體和導(dǎo)航欄按鈕(或?qū)Ш綏l)設(shè)置亮色或暗色

  3. 狀態(tài)欄導(dǎo)航欄設(shè)置透明后,我們頁面的布局會延伸到原本狀態(tài)欄導(dǎo)航欄的位置,這時候需要一些手段將我們需要顯示的正文內(nèi)容回縮到其正確的顯示范圍內(nèi)

    這里我給大家提供以下幾種思路,大家可以根據(jù)實(shí)際情況自行選擇:

    • 設(shè)置fitsSystemWindows屬性
    • 根據(jù)狀態(tài)欄導(dǎo)航欄的高度,給根布局設(shè)置相應(yīng)的paddingToppaddingBottom
    • 根據(jù)狀態(tài)欄導(dǎo)航欄的高度,給需要移位的控件設(shè)置相應(yīng)的marginTopmarginBottom
    • 在頂部和底部增加兩個占位的View,高度分別設(shè)置成狀態(tài)欄和導(dǎo)航欄的高度
    • 針對滑動視圖,巧用clipChildrenclipToPadding屬性(可參照高能鏈藏品詳情頁樣式)

沉浸式狀態(tài)欄

思路說完了,我們現(xiàn)在開始進(jìn)入實(shí)戰(zhàn),沉浸式狀態(tài)欄比較簡單,沒什么坑

狀態(tài)欄透明

首先第一步,我們需要將狀態(tài)欄的背景設(shè)置為透明,這里我直接放代碼

fun transparentStatusBar(window: Window) {
    window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS)
    window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS)
    var systemUiVisibility = window.decorView.systemUiVisibility
    systemUiVisibility =
        systemUiVisibility or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN or View.SYSTEM_UI_FLAG_LAYOUT_STABLE
    window.decorView.systemUiVisibility = systemUiVisibility
    window.statusBarColor = Color.TRANSPARENT

    //設(shè)置狀態(tài)欄文字顏色
    setStatusBarTextColor(window, NightMode.isNightMode(window.context))
}

首先,我們需要將FLAG_TRANSLUCENT_STATUS這個windowFlag換成FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS,否則狀態(tài)欄不會完全透明,會有一個半透明的灰色蒙層

FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS這個flag表示系統(tǒng)Bar的背景將交給當(dāng)前window繪制

SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN這個flag表示Activity全屏顯示,但狀態(tài)欄不會被隱藏,依然可見

SYSTEM_UI_FLAG_LAYOUT_STABLE這個flag表示保持整個View穩(wěn)定,使View不會因?yàn)橄到y(tǒng)UI的變化而重新layout

SYSTEM_UI_FLAG_LAYOUT_FULLSCREENSYSTEM_UI_FLAG_LAYOUT_STABLE這兩個flag通常是一起使用的,我們設(shè)置這兩個flag,然后再將statusBarColor設(shè)置為透明,就達(dá)成了狀態(tài)欄背景透明的效果

狀態(tài)欄文字顏色

接著我們就該設(shè)置狀態(tài)欄文字顏色了,細(xì)心的小伙伴們應(yīng)該已經(jīng)注意到了,我在transparentStatusBar方法的末尾加了一個setStatusBarTextColor的方法調(diào)用,一般情況下,如果是日間模式,頁面背景通常都是亮色,所以此時狀態(tài)欄文字顏色設(shè)置為黑色比較合理,而在夜間模式下,頁面背景通常都是暗色,此時狀態(tài)欄文字顏色設(shè)置為白色比較合理,對應(yīng)代碼如下

fun setStatusBarTextColor(window: Window, light: Boolean) {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
        var systemUiVisibility = window.decorView.systemUiVisibility
        systemUiVisibility = if (light) { //白色文字
            systemUiVisibility and View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR.inv()
        } else { //黑色文字
            systemUiVisibility or View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR
        }
        window.decorView.systemUiVisibility = systemUiVisibility
    }
}

Android 8.0以上才支持導(dǎo)航欄文字顏色的修改,SYSTEM_UI_FLAG_LIGHT_STATUS_BAR這個flag表示亮色狀態(tài)欄,即黑色狀態(tài)欄文字,所以如果希望狀態(tài)欄文字為黑色,就設(shè)置這個flag,如果希望狀態(tài)欄文字為白色,就將這個flagsystemUiVisibility中剔除

可能有小伙伴不太了解kotlin中的位運(yùn)算,kotlin中的orand、inv分別對應(yīng)著或、與、取反運(yùn)算

所以

systemUiVisibility and View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR.inv()

翻譯成java即為

systemUiVisibility & ~View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR

在原生系統(tǒng)上,這么設(shè)置就可以成功設(shè)置狀態(tài)欄文字顏色,但我發(fā)現(xiàn),在某些系統(tǒng)上,這樣設(shè)置后的效果是不可預(yù)期的,譬如MIUI系統(tǒng)的狀態(tài)欄文字顏色似乎是根據(jù)狀態(tài)欄背景顏色自適應(yīng)的,且日間模式和黑夜模式下的自適應(yīng)策略還略有不同。不過在大多數(shù)情況下,它自適應(yīng)的顏色都是正常的,我們就按照我們希望的結(jié)果設(shè)置就可以了。

矯正顯示區(qū)域

fitsSystemWindows

矯正狀態(tài)欄顯示區(qū)域最簡單的辦法就是設(shè)置fitsSystemWindows屬性,設(shè)置了該屬性的View的所有padding屬性都將失效,并且系統(tǒng)會自動為其添加paddingTop(設(shè)置了透明狀態(tài)欄的情況下)和paddingBottom(設(shè)置了透明導(dǎo)航欄的情況下)

我個人是不用這種方式的,首先它會覆蓋你設(shè)置的padding,其次,如果你同時設(shè)置了透明狀態(tài)欄和透明導(dǎo)航欄,這個屬性沒有辦法分開來處理,很不靈活

獲取狀態(tài)欄高度

除了fitsSystemWindows這種方法外,其他的方法都得依靠獲取狀態(tài)欄高度了,這里直接上代碼

fun getStatusBarHeight(context: Context): Int {
    val resId = context.resources.getIdentifier(
        "status_bar_height", "dimen", "android"
    )
    return context.resources.getDimensionPixelSize(resId)
}

狀態(tài)欄不像導(dǎo)航欄那樣多變,所以直接這樣獲取高度就可以了,導(dǎo)航欄的高度飄忽不定才是真正的噩夢

這里再給兩個設(shè)置View marginpadding的工具方法吧,幫助大家快速使用

fun fixStatusBarMargin(vararg views: View) {
    views.forEach { view ->
        (view.layoutParams as? ViewGroup.MarginLayoutParams)?.let { lp ->
            lp.topMargin = lp.topMargin + getStatusBarHeight(view.context)
            view.requestLayout()
        }
    }
}

fun paddingByStatusBar(view: View) {
    view.setPadding(
        view.paddingLeft,
        view.paddingTop + getStatusBarHeight(view.context),
        view.paddingRight,
        view.paddingBottom
    )
}

沉浸式導(dǎo)航欄

沉浸式導(dǎo)航欄相比沉浸式狀態(tài)欄坑會多很多,具體原因我們后面再說

導(dǎo)航欄透明

和沉浸式狀態(tài)欄一樣,第一步我們需要將導(dǎo)航欄的背景設(shè)置為透明

fun transparentNavigationBar(window: Window) {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
        window.isNavigationBarContrastEnforced = false
    }
    window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION)
    window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS)
    var systemUiVisibility = window.decorView.systemUiVisibility
    systemUiVisibility =
        systemUiVisibility or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
    window.decorView.systemUiVisibility = systemUiVisibility
    window.navigationBarColor = Color.TRANSPARENT

    //設(shè)置導(dǎo)航欄按鈕或?qū)Ш綏l顏色
    setNavigationBarBtnColor(window, NightMode.isNightMode(window.context))
}

Android 10以上,當(dāng)設(shè)置了導(dǎo)航欄欄背景為透明時,isNavigationBarContrastEnforced如果為true,則系統(tǒng)會自動繪制一個半透明背景來提供對比度,所以我們要將這個屬性設(shè)為false

ps:狀態(tài)欄其實(shí)也有對應(yīng)的屬性isStatusBarContrastEnforced,只不過這個屬性默認(rèn)即為false,我們不需要特意去設(shè)置

導(dǎo)航欄按鈕或?qū)Ш綏l顏色

和設(shè)置狀態(tài)欄文字顏色一樣,我這里就不多介紹了

fun setNavigationBarBtnColor(window: Window, light: Boolean) {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
        var systemUiVisibility = window.decorView.systemUiVisibility
        systemUiVisibility = if (light) { //白色按鈕
            systemUiVisibility and View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR.inv()
        } else { //黑色按鈕
            systemUiVisibility or View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR
        }
        window.decorView.systemUiVisibility = systemUiVisibility
    }
}

矯正顯示區(qū)域

fitsSystemWindows

和狀態(tài)欄使用一樣,我就不重復(fù)說明了

獲取導(dǎo)航欄高度

自從全面屏手勢開始流行,導(dǎo)航欄也從原先的三鍵式,變成了三鍵式、導(dǎo)航條、全隱藏這三種情況,這三種情況下的高度也是互不相同的

三鍵式和導(dǎo)航條這兩種情況我們都可以通過android.R.dimen.navigation_bar_height這個資源獲取到準(zhǔn)確高度,但現(xiàn)在很多系統(tǒng)都支持隱藏導(dǎo)航欄的功能,在這種情況下,雖然實(shí)際導(dǎo)航欄的高度應(yīng)該是0,但是通過資源獲取到的高度卻為三鍵式或?qū)Ш綏l的高度,這就給我們沉浸式導(dǎo)航欄的適配帶來了很大困難

經(jīng)過我的各種嘗試,我發(fā)現(xiàn)只有一種方式可以準(zhǔn)確的獲取到當(dāng)前導(dǎo)航欄的高度,那就是WindowInsets,至于WindowInsets是什么我就不多介紹了,我們直接看代碼

/**
* 僅當(dāng)view attach window后生效
*/
private fun getRealNavigationBarHeight(view: View): Int {
    val insets = ViewCompat.getRootWindowInsets(view)
        ?.getInsets(WindowInsetsCompat.Type.navigationBars())
    //WindowInsets為null則默認(rèn)通過資源獲取高度
    return insets?.bottom ?: getNavigationBarHeight(view.context)
}

這里需要注意到我在方法上寫的注釋,只有當(dāng)ViewWindow attach 后,才能獲得到WindowInsets,否則為null,所以我一開始的想法是先檢查View是否 attach 了Window,如果有的話則直接調(diào)用getRealNavigationBarHeight方法,如果沒有的話,調(diào)用View.addOnAttachStateChangeListener方法,當(dāng)出發(fā)attach回調(diào)后,再調(diào)用getRealNavigationBarHeight方法獲取高度

這種方式在大部分情況下運(yùn)行良好,但在我一次無意中切換了系統(tǒng)夜間模式后發(fā)現(xiàn),獲取到的導(dǎo)航欄高度變成了0,并且這還是一個偶現(xiàn)的問題,于是我嘗試使用View.setOnApplyWindowInsetsListener,監(jiān)聽WindowInsets的變化發(fā)現(xiàn),這個回調(diào)有可能會觸發(fā)多次,在觸發(fā)多次的情況下,前幾次的值都為0,只有最后一次的值為真正的導(dǎo)航欄高度

于是我準(zhǔn)備用View.setOnApplyWindowInsetsListener代替View.addOnAttachStateChangeListener,但畢竟一個是setListener,一個是addListener,setListener有可能會把之前設(shè)置好的Listener覆蓋,或者被別的Listener覆蓋掉,再考慮到之后會提到的底部Dialog沉浸式導(dǎo)航欄適配的問題,我折中了一下,決定只對Activity下的rootView設(shè)置回調(diào)

以下是完整代碼

private class NavigationViewInfo(
    val hostRef: WeakReference<View>,
    val viewRef: WeakReference<View>,
    val rawBottom: Int,
    val onNavHeightChangeListener: (View, Int, Int) -> Unit
)

private val navigationViewInfoList = mutableListOf<NavigationViewInfo>()

private val onApplyWindowInsetsListener = View.OnApplyWindowInsetsListener { v, insets ->
    val windowInsetsCompat = WindowInsetsCompat.toWindowInsetsCompat(insets, v)
    val navHeight =
        windowInsetsCompat.getInsets(WindowInsetsCompat.Type.navigationBars()).bottom
    val it = navigationViewInfoList.iterator()
    while (it.hasNext()) {
        val info = it.next()
        val host = info.hostRef.get()
        val view = info.viewRef.get()
        if (host == null || view == null) {
            it.remove()
            continue
        }

        if (host == v) {
            info.onNavHeightChangeListener(view, info.rawBottom, navHeight)
        }
    }
    insets
}

private val actionMarginNavigation: (View, Int, Int) -> Unit =
    { view, rawBottomMargin, navHeight ->
        (view.layoutParams as? ViewGroup.MarginLayoutParams)?.let {
            it.bottomMargin = rawBottomMargin + navHeight
            view.requestLayout()
        }
    }

private val actionPaddingNavigation: (View, Int, Int) -> Unit =
    { view, rawBottomPadding, navHeight ->
        view.setPadding(
            view.paddingLeft,
            view.paddingTop,
            view.paddingRight,
            rawBottomPadding + navHeight
        )
    }

fun fixNavBarMargin(vararg views: View) {
    views.forEach {
        fixSingleNavBarMargin(it)
    }
}

private fun fixSingleNavBarMargin(view: View) {
    val lp = view.layoutParams as? ViewGroup.MarginLayoutParams ?: return
    val rawBottomMargin = lp.bottomMargin

    val viewForCalculate = getViewForCalculate(view)

    if (viewForCalculate.isAttachedToWindow) {
        val realNavigationBarHeight = getRealNavigationBarHeight(viewForCalculate)
        lp.bottomMargin = rawBottomMargin + realNavigationBarHeight
        view.requestLayout()
    }
    
	//isAttachedToWindow方法并不能保證此時的WindowInsets是正確的,仍然需要添加監(jiān)聽
    val hostRef = WeakReference(viewForCalculate)
    val viewRef = WeakReference(view)
    val info = NavigationViewInfo(hostRef, viewRef, rawBottomMargin, actionMarginNavigation)
    navigationViewInfoList.add(info)
    viewForCalculate.setOnApplyWindowInsetsListener(onApplyWindowInsetsListener)
}

fun paddingByNavBar(view: View) {
    val rawBottomPadding = view.paddingBottom

    val viewForCalculate = getViewForCalculate(view)

    if (viewForCalculate.isAttachedToWindow) {
        val realNavigationBarHeight = getRealNavigationBarHeight(viewForCalculate)
        view.setPadding(
            view.paddingLeft,
            view.paddingTop,
            view.paddingRight,
            rawBottomPadding + realNavigationBarHeight
        )
    }

	//isAttachedToWindow方法并不能保證此時的WindowInsets是正確的,仍然需要添加監(jiān)聽
    val hostRef = WeakReference(viewForCalculate)
    val viewRef = WeakReference(view)
    val info =
        NavigationViewInfo(hostRef, viewRef, rawBottomPadding, actionPaddingNavigation)
    navigationViewInfoList.add(info)
    viewForCalculate.setOnApplyWindowInsetsListener(onApplyWindowInsetsListener)
}

/**
* Dialog下的View在低版本機(jī)型中獲取到的WindowInsets值有誤,
* 所以嘗試去獲得Activity的contentView,通過Activity的contentView獲取WindowInsets
*/
@SuppressLint("ContextCast")
private fun getViewForCalculate(view: View): View {
    return (view.context as? ContextWrapper)?.let {
        return@let (it.baseContext as? Activity)?.findViewById<View>(android.R.id.content)?.rootView
    } ?: view.rootView
}

/**
* 僅當(dāng)view attach window后生效
*/
private fun getRealNavigationBarHeight(view: View): Int {
    val insets = ViewCompat.getRootWindowInsets(view)
        ?.getInsets(WindowInsetsCompat.Type.navigationBars())
    return insets?.bottom ?: getNavigationBarHeight(view.context)
}

我簡單解釋一下這段代碼:為所有需要沉浸的頁面的根View設(shè)置同一個回調(diào),并將待適配導(dǎo)航欄高度的View添加到列表中,當(dāng)WindowInsets回調(diào)觸發(fā)后,遍歷這個列表,判斷觸發(fā)回調(diào)的Viewhost是否與待適配導(dǎo)航欄高度的View對應(yīng),對應(yīng)的話則處理View適配導(dǎo)航欄高度

這里需要注意,WindowInsets的分發(fā)其實(shí)是在dispatchAttachedToWindow之后的,所以isAttachedToWindow方法并不能保證此時的WindowInsets是正確的,具體可以去看ViewRootImpl中的源碼,關(guān)鍵方法:dispatchApplyInsets,這里判斷isAttachedToWindow并設(shè)置高度是為了防止出現(xiàn)View已經(jīng)完全布局完成,之后再也不會觸發(fā)OnApplyWindowInsets的情況

這里我也測試了內(nèi)存泄漏情況,確認(rèn)無內(nèi)存泄漏,大家可以放心食用

底部Dialog適配沉浸式

底部Dialog適配沉浸式要比正常的Activity更麻煩一些,主要問題也是集中在沉浸式導(dǎo)航欄上

獲取導(dǎo)航欄高度

仔細(xì)的小伙伴們可以已經(jīng)注意到了我在沉浸式導(dǎo)航欄獲取高度那里代碼中的注釋,Dialog下的View在低版本機(jī)型(經(jīng)測試,Android 9一下就會有這個問題)中獲取到的WindowInsets值有誤,所以嘗試去獲得ActivitycontentView,通過ActivitycontentView獲取WindowInsets

LayoutParams導(dǎo)致的異常

在某些系統(tǒng)上(比如MIUI),當(dāng)我window.setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)時,沉浸式會出現(xiàn)問題,狀態(tài)欄會被蒙層蓋住,Dialog底部的內(nèi)容也會被一個莫名其妙的東西遮擋住

我的解決方案是,window.setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT),然后布局最外層全部占滿,內(nèi)部留一個底部容器

<!-- dialog_pangu_bottom_wrapper -->
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@android:color/transparent">

    <FrameLayout
        android:id="@+id/pangu_bottom_dialog_container"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_gravity="bottom"
        android:clickable="true"
        android:focusable="true" />

</FrameLayout>

然后在代碼中重寫setContentView方法

private var canceledOnTouchOutside = true

override fun setContentView(layoutResID: Int) {
    setContentView(
        LayoutInflater.from(context).inflate(layoutResID, null, false)
    )
}

override fun setContentView(view: View) {
    setContentView(
        view,
        ViewGroup.LayoutParams(
            ViewGroup.LayoutParams.MATCH_PARENT,
            ViewGroup.LayoutParams.WRAP_CONTENT
        )
    )
}

override fun setContentView(view: View, params: ViewGroup.LayoutParams?) {
    val root =
        LayoutInflater.from(context).inflate(R.layout.dialog_pangu_bottom_wrapper, null, false)
    root.setOnClickListener {
        if (canceledOnTouchOutside) {
            dismiss()
        }
    }
    val container = root.findViewById<ViewGroup>(R.id.pangu_bottom_dialog_container)
    container.addView(view, params)

    super.setContentView(
        root,
        ViewGroup.LayoutParams(
            ViewGroup.LayoutParams.MATCH_PARENT,
            ViewGroup.LayoutParams.MATCH_PARENT
        )
    )
}

override fun setCanceledOnTouchOutside(cancel: Boolean) {
    super.setCanceledOnTouchOutside(cancel)
    canceledOnTouchOutside = cancel
}

這樣的話視覺效果就和普通的底部Dialog一樣了,為了進(jìn)一步減小底部Dialog顯示隱藏動畫之間的差異,我將動畫插值器從linear_interpolator換成了decelerate_interpolatoraccelerate_interpolator

<!-- dialog_enter_from_bottom_to_top -->
<translate xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="300"
    android:fromYDelta="100%"
    android:interpolator="@android:anim/decelerate_interpolator"
    android:toYDelta="0" />
<!-- dialog_exit_from_top_to_bottom -->
<translate xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="300"
    android:fromYDelta="0"
    android:interpolator="@android:anim/accelerate_interpolator"
    android:toYDelta="100%" />

尾聲

自此,目前沉浸式遇到的問題全部都解決了,如果以后發(fā)現(xiàn)了什么新的問題,我會在這篇文章中補(bǔ)充說明,如果還有什么不明白的地方可以評論,我考慮要不要拿幾個具體的場景實(shí)戰(zhàn)講解,各位看官老爺麻煩點(diǎn)個贊收個藏不迷路??文章來源地址http://www.zghlxwxcb.cn/news/detail-425283.html

到了這里,關(guān)于史上最完美的Android沉浸式狀態(tài)導(dǎo)航欄攻略的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • 【UI篇】Android 沉浸式狀態(tài)欄的那些事

    【UI篇】Android 沉浸式狀態(tài)欄的那些事

    此篇文章介紹的內(nèi)容都是考慮到5.0 版本以上。5.0以下的不做介紹。演示的代碼皆為kotlin實(shí)現(xiàn) 首先一般設(shè)置是包括兩方面的,第一是設(shè)置 window.decorView.systemUiVisibility ,第二是設(shè)置 window.addFlags() 這些方法都有一些常量的設(shè)置。但是在API 30 版本之后又新出了一個 WindowInsetsContro

    2024年01月25日
    瀏覽(15)
  • Android 沉浸式狀態(tài)欄的實(shí)現(xiàn)以及布局重疊的適配(Kotlin)

    Android 沉浸式狀態(tài)欄的實(shí)現(xiàn)以及布局重疊的適配(Kotlin)

    本文章分以下內(nèi)容: 沉浸式狀態(tài)欄的實(shí)現(xiàn) 沉浸式導(dǎo)航欄的實(shí)現(xiàn) 適配實(shí)現(xiàn)沉浸式狀態(tài)欄后導(dǎo)致的布局偏移 其他常見問題 該方法用于表示內(nèi)容是否超出至狀態(tài)欄和底部導(dǎo)航欄顯示,false表明超出。(這也就我們實(shí)現(xiàn)沉浸式后需要做適配的原因) 注意:當(dāng)使用setDecorFitsSystemWind

    2024年02月04日
    瀏覽(21)
  • 【Android】獲取導(dǎo)航欄、狀態(tài)欄高度

    【Android】獲取導(dǎo)航欄、狀態(tài)欄高度

    或者 或者 系統(tǒng)的各種數(shù)據(jù)定義位于SDK的xml文件中: android-30/data/res/values/dimens.xml 通過key可以獲取對應(yīng)的值。 導(dǎo)航欄和狀態(tài)欄源碼相似 調(diào)用 updateColorViews 更新背景色的方法,還有如下位置: WindowInsets 可以翻譯為窗口附加物,一般是指一個界面中,不由開發(fā)者直接控制的部分

    2024年02月12日
    瀏覽(18)
  • Android WindowInsetsController 設(shè)置狀態(tài)欄、導(dǎo)航欄

    Android WindowInsetsController 設(shè)置狀態(tài)欄、導(dǎo)航欄

    有 hide() ,也有 show() 在更早的版本中,使用 ViewCompat.getWindowInsetsController() 獲取 WindowInsetsControllerCompat 實(shí)例 而現(xiàn)在推薦使用 WindowCompat.etInsetsController() 獲取 WindowInsetsControllerCompat 實(shí)例 底部的三個按鍵就是導(dǎo)航欄 (navigation bar): back / home / recent 。 高版本系統(tǒng),recent,可能沒有圖

    2024年02月15日
    瀏覽(32)
  • MySQL Workbench 操作詳解(史上最細(xì))

    MySQL Workbench 操作詳解(史上最細(xì))

    右鍵新建的數(shù)據(jù)庫BMI,設(shè)置為此次連接的默認(rèn)數(shù)據(jù)庫,接下來的所有操作都將在這個數(shù)據(jù)庫下進(jìn)行 將bmi下拉單展開,點(diǎn)擊Table,右鍵創(chuàng)建Table: 給Table命名,添加Column,設(shè)置Column的Datatype,PrimaryKey等屬性。點(diǎn)擊Apply后,Workbench仍會自動生成SQL語句,再次點(diǎn)擊Apply,成功創(chuàng)建新表

    2023年04月08日
    瀏覽(24)
  • 史上最簡單的Kafka安裝教程

    ?解壓apache-zookeeper-3.8.0-bin.tar.gz到指定目錄,復(fù)制conf目錄下zoo_sample.cfg到zoo.cfg,并修改配置。 進(jìn)入bin目錄,啟動zookeeper 解壓kafka_2.12-3.0.0.tgz到指定目錄。 進(jìn)入到config目錄,修改server.properties配置 advertised.listeners才是真正的對外代理地址,listeners的作用不是對外提供服務(wù)代理,

    2024年02月07日
    瀏覽(28)
  • C++:史上最坑小游戲

    史上最坑小游戲,先別使用,往后看! 破解: 輸入1~4的破解方法(二次開機(jī))或: 輸入5,6:的破解方法(一旦運(yùn)行此程序,只有按下Windows開始鍵(其實(shí)我也不知道它叫什么,就是那個按一下就能顯示開始窗口的鍵)然后按 cmd就會彈出一個窗口,根平時代碼運(yùn)行時的窗口一

    2024年01月21日
    瀏覽(23)
  • Android 顯示、隱藏狀態(tài)欄和導(dǎo)航欄

    控制狀態(tài)欄顯示,Activity的主題中配置全屏屬性 控制狀態(tài)欄顯示,在setContentView之前設(shè)置全屏的flag 復(fù)制代碼 getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN); 控制狀態(tài)欄顯示,在任何位置通過添加和移除全屏的flag 控制狀態(tài)欄和導(dǎo)航欄顯示,

    2024年02月08日
    瀏覽(26)
  • 史上最詳細(xì)的八大排序詳解?。ńㄗh收藏)

    史上最詳細(xì)的八大排序詳解?。ńㄗh收藏)

    ??write in front?? ??所屬專欄:初階數(shù)據(jù)結(jié)構(gòu) ???博客主頁:睿睿的博客主頁 ???代碼倉庫:??VS2022_C語言倉庫 ??您的點(diǎn)贊、關(guān)注、收藏、評論,是對我最大的激勵和支持?。?! 關(guān)注我,關(guān)注我,關(guān)注我 , 你們將會看到更多的優(yōu)質(zhì)內(nèi)容??! ??從今天開始,我們就進(jìn)入

    2023年04月20日
    瀏覽(23)
  • OpenStack搭建史上最詳細(xì)步驟 (快速入手)

    OpenStack搭建史上最詳細(xì)步驟 (快速入手)

    搭建openstack平臺所需要的兩個鏡像包:CentOS-7-X86_64-DVD-1804.iso 和 chinaskill_cloud_iaas.iso鏡像文件。 在VMware上準(zhǔn)備兩臺虛擬機(jī),分別作為controller(控制)節(jié)點(diǎn)和compute節(jié)點(diǎn). 下面是VMware上虛擬機(jī)的基礎(chǔ)配置。 computecontroller 雙網(wǎng)卡,NAT模式和僅主機(jī)模式,配置硬盤各給50G 多添的一塊

    2024年02月02日
    瀏覽(48)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包