StatusBarUtils沉浸式状态栏适配(第二种实现方式)

上一篇我们说了第一种沉浸式状态栏实现方式,但其实现虽然可以满足大部分需求了,发现对于接入swipebacklayout(仿微信侧滑返回)状态栏不会跟随界面滑动,得等到界面退出后才改变状态栏颜色。现在我们通过直接设置状态栏透明,然后手动在添加一个伪状态栏来实现。此伪状态栏非第一种实现方式的伪状态栏(文字描叙起来还是比较抽象,可以看下面布局图)

实现方式.png

看图写代码O(∩_∩)O,先看效果图,否则说我瞎忽悠
statusbarutils.gif

咱还是挺实诚的,看效果还是挺不错的。

/**
 * 状态栏id
 */
private const val STATUS_BAR_UTILS_STATUS_BAR_VIEW_ID = R.id.status_bar_utils_status_bar_view

/**
 * 主布局id
 */
private const val STATUS_BAR_UTILS_CONTENT_VIEW_ID = R.id.status_bar_utils_content_view

/**
 * 设置状态栏颜色
 */
fun setStatusBarColorRes(activity: Activity, @ColorRes colorRes: Int) {
    setStatusBarColor(activity, activity.resources.getColor(colorRes))
}

/**
 * 设置状态栏颜色
 */
fun setStatusBarColor(activity: Activity, @ColorInt color: Int) {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
        setTransparentForWindow(activity)
        findDrawerLayout(activity)?.also {
            setDrawLayouterStatusBarColor(activity, it, color)
        } ?: addPreviousSetting(activity, color)
    }
}

/**
 * 去除状态栏(即状态栏透明,整体布局与状态栏重叠)
 */
fun setStatusBarTraslucent(activity: Activity) {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
        setTransparentForWindow(activity)
        findDrawerLayout(activity)?.also {
            setDrawerLayoutProperty(it)
            clearDrawLayouterStatusBarColor(it)
        } ?: clearPreviousSetting(activity)
    }
}

/**
 * 设置状态栏字体颜色(黑)
 */
fun setLightMode(activity: Activity) {
    setMIUIStatusBarDarkIcon(activity, true)
    setMeizuStatusBarDarkIcon(activity, true)
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
        activity.window.decorView.systemUiVisibility = View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
    }
}

/**
 * 设置状态栏字体颜色(白)
 */
fun setDarkMode(activity: Activity) {
    setMIUIStatusBarDarkIcon(activity, false)
    setMeizuStatusBarDarkIcon(activity, false)
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
        activity.window.decorView.systemUiVisibility = View.SYSTEM_UI_FLAG_LAYOUT_STABLE or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
    }
}

/**
 * 获取状态栏高度
 */
fun getStatusBarHeight(context: Context): Int {
    return context.resources.getDimensionPixelSize(context.resources.getIdentifier("status_bar_height", "dimen", "android"))
}

/**
 * 设置状态栏透明
 */
private fun setTransparentForWindow(activity: Activity) {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
        activity.window.also {
            it.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS)
            it.statusBarColor = Color.TRANSPARENT
            it.decorView.systemUiVisibility = View.SYSTEM_UI_FLAG_LAYOUT_STABLE or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
        }
    } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
        activity.window.setFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS, WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS)
    }
}

private fun findDrawerLayout(activity: Activity): DrawerLayout? {
    return activity.window.decorView.findViewById(android.R.id.content).getChildAt(0).run {
        this as? DrawerLayout
    }
}

private fun setDrawLayouterStatusBarColor(activity: Activity, drawerLayout: DrawerLayout, @ColorInt color: Int) {
    val contentLayout = drawerLayout.getChildAt(0)
    contentLayout.findViewById(STATUS_BAR_UTILS_STATUS_BAR_VIEW_ID)?.also {
        if (it.visibility == View.GONE) {
            it.visibility = View.VISIBLE
        }
        it.setBackgroundColor(color)
    } ?: run {
        drawerLayout.removeView(contentLayout)
        val linearLayout = LinearLayout(activity).apply {
            layoutParams = DrawerLayout.LayoutParams(DrawerLayout.LayoutParams.MATCH_PARENT, DrawerLayout.LayoutParams.MATCH_PARENT)
            orientation = LinearLayout.VERTICAL
            addView(createStatusBarView(activity, color))
            addView(contentLayout)
        }
        drawerLayout.addView(linearLayout, 0)
    }
    setDrawerLayoutProperty(drawerLayout)
}

private fun clearDrawLayouterStatusBarColor(drawerLayout: DrawerLayout) {
    drawerLayout.findViewById(STATUS_BAR_UTILS_STATUS_BAR_VIEW_ID)?.also {
        if (it.visibility == View.VISIBLE) {
            it.visibility = View.GONE
        }
    }
}

private fun addPreviousSetting(activity: Activity, @ColorInt color: Int) {
    val root = activity.window.decorView.findViewById(android.R.id.content)
    root.findViewById(STATUS_BAR_UTILS_CONTENT_VIEW_ID)?.apply {
        findViewById(STATUS_BAR_UTILS_STATUS_BAR_VIEW_ID)?.also {
            if (it.visibility == View.GONE) {
                it.visibility = View.VISIBLE
            }
            it.setBackgroundColor(color)
        } ?: addView(createStatusBarView(activity, color), 0)
    } ?: run {
        val content = root.getChildAt(0)
        root.removeView(content)
        val linearLayout = LinearLayout(activity).apply {
            id = STATUS_BAR_UTILS_CONTENT_VIEW_ID
            layoutParams = DrawerLayout.LayoutParams(DrawerLayout.LayoutParams.MATCH_PARENT, DrawerLayout.LayoutParams.MATCH_PARENT)
            orientation = LinearLayout.VERTICAL
            addView(createStatusBarView(activity, color))
            addView(content)
        }
        root.addView(linearLayout, 0)
    }
}

private fun clearPreviousSetting(activity: Activity) {
    activity.window.decorView.findViewById(STATUS_BAR_UTILS_STATUS_BAR_VIEW_ID)?.also {
        if (it.visibility == View.VISIBLE) {
            it.visibility = View.GONE
        }
    }
}

/**
 * 创建伪状态栏
 */
private fun createStatusBarView(activity: Activity, @ColorInt color: Int): View {
    return View(activity).apply {
        this.layoutParams = LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, getStatusBarHeight(activity))
        this.setBackgroundColor(color)
        this.id = STATUS_BAR_UTILS_STATUS_BAR_VIEW_ID
    }
}

private fun setDrawerLayoutProperty(drawerLayout: DrawerLayout) {
    drawerLayout.fitsSystemWindows = false
    drawerLayout.getChildAt(1).fitsSystemWindows = false
}

/**
 * 修改 MIUI V6  以上状态栏颜色
 */
@SuppressLint("PrivateApi")
private fun setMIUIStatusBarDarkIcon(activity: Activity, darkIcon: Boolean) {
    val clazz = activity.window.javaClass
    try {
        val layoutParams = Class.forName("android.view.MiuiWindowManager\$LayoutParams")
        val field = layoutParams.getField("EXTRA_FLAG_STATUS_BAR_DARK_MODE")
        val darkModeFlag = field.getInt(layoutParams)
        val extraFlagField = clazz.getMethod("setExtraFlags", Int::class.javaPrimitiveType, Int::class.javaPrimitiveType)
        extraFlagField.invoke(activity.window, if (darkIcon) darkModeFlag else 0, darkModeFlag)
    } catch (e: Exception) {
        e.printStackTrace()
    }
}

/**
 * 修改魅族状态栏字体颜色 Flyme 4.0
 */
private fun setMeizuStatusBarDarkIcon(activity: Activity, darkIcon: Boolean) {
    try {
        val lp = activity.window.attributes
        val darkFlag = WindowManager.LayoutParams::class.java.getDeclaredField("MEIZU_FLAG_DARK_STATUS_BAR_ICON")
        val meizuFlags = WindowManager.LayoutParams::class.java.getDeclaredField("meizuFlags")
        darkFlag.isAccessible = true
        meizuFlags.isAccessible = true
        val bit = darkFlag.getInt(null)
        var value = meizuFlags.getInt(lp)
        value = if (darkIcon) {
            value or bit
        } else {
            value and bit.inv()
        }
        meizuFlags.setInt(lp, value)
        activity.window.attributes = lp
    } catch (e: Exception) {
        e.printStackTrace()
    }
}

当然,还是得给伪状态栏及我们手动加上的LinearLayout设置id(在values下新建一资源文件ids),否则对于多Fragment的同一Activiy跟随其变化状态栏方便找到对应View进行修改。

    
    
    
    

你可能感兴趣的:(StatusBarUtils沉浸式状态栏适配(第二种实现方式))