美文网首页Android基础
StatusBarUtils沉浸式状态栏适配(第二种实现方式)

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

作者: kksoCoud | 来源:发表于2018-11-15 20:23 被阅读127次

    上一篇我们说了第一种沉浸式状态栏实现方式,但其实现虽然可以满足大部分需求了,发现对于接入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<ViewGroup>(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<View>(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<View>(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<ViewGroup>(android.R.id.content)
        root.findViewById<LinearLayout>(STATUS_BAR_UTILS_CONTENT_VIEW_ID)?.apply {
            findViewById<View>(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<View>(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进行修改。

        <!--状态栏id-->
        <item name="status_bar_utils_status_bar_view" type="id" />
        <!--content外面添加的LinearLayout id-->
        <item name="status_bar_utils_content_view" type="id" />
    

    相关文章

      网友评论

        本文标题:StatusBarUtils沉浸式状态栏适配(第二种实现方式)

        本文链接:https://www.haomeiwen.com/subject/zprufqtx.html