问题描述:
当页面使用fitsSystemWindow属性时,目的之一是想让窗口自动适配状态栏,但是目前发现有特殊设备在特殊情况下会丢失状态栏(的高度),比如三星折叠屏在多窗口运行时fitsSystemWindow属性不能生效,具体现象是顶部内容被一个横杠遮挡
解决方案:
运行时获取statusBar的高度,并修正页面根布局的高度
工具类代码如下:
import android.app.Activity
import android.content.Context
import android.graphics.Color
import android.os.Build
import android.view.View
import android.view.ViewGroup
import android.view.WindowManager
import android.widget.FrameLayout
import androidx.annotation.ColorRes
import com.kongfz.app.core.R
import com.kongfz.app.core.common.drive.extend.catchExceptions
import com.kongfz.app.core.common.utils.blankj.util.Utils
object StatusBarUtils {
@Target(AnnotationTarget.VALUE_PARAMETER, AnnotationTarget.TYPE)
@Retention(AnnotationRetention.SOURCE)
annotation class FakeStatusBarCfg {
companion object {
//永远不需要,上层自行调整布局高度。
//适用页面:顶部是沉浸式图片类型
const val NEVER_NEED = 0
//永远需要
//适用页面:普通的顶部,并且没有使用fitsSystemWindow
const val ALWAYS_NEED = 1
//如果丢失就需要,否则不需要
//适用页面:普通的顶部,并且使用了fitsSystemWindow
const val NEED_WHEN_LOST = 2
}
}
fun setStatusBarFontIconLight(activity: Activity, isLightIcon: Boolean) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
val decorView = activity.window.decorView
val option = (View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
or View.SYSTEM_UI_FLAG_LAYOUT_STABLE)
decorView.systemUiVisibility = option
if (isLightIcon) {
activity.window.statusBarColor = Color.TRANSPARENT
} else {
activity.window.statusBarColor = Color.WHITE
}
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
val localLayoutParams = activity.window.attributes
localLayoutParams.flags =
WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS or localLayoutParams.flags
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && !isLightIcon) {
//android6.0以后可以对状态栏文字颜色和图标进行修改
activity.window.decorView.systemUiVisibility =
View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN or View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR
}
}
fun getStatusBarHeight(context: Context): Int {
val resources = context.resources
val resourceId = resources.getIdentifier("status_bar_height", "dimen", "android")
return resources.getDimensionPixelSize(resourceId)
}
@JvmStatic
val statusBarHeight: Int
get() {
val resources =
Utils.getApp().resources
val resourceId =
resources.getIdentifier("status_bar_height", "dimen", "android")
return resources.getDimensionPixelSize(resourceId)
}
/**
* 运行时获取statusBar的高度,并修正根布局的h
*/
@JvmStatic
fun fixStatusHeight(view: View) {
val h = getStatusBarHeight(Utils.getApp())
val lp = view.layoutParams as ViewGroup.MarginLayoutParams
lp.setMargins(0, h, 0, 0)
view.layoutParams = lp
}
fun tryAddingFakeStatusBar(
activity: Activity,
fakeStatusBarCfg: @FakeStatusBarCfg Int,
rootView: ViewGroup,
@ColorRes color: Int
) {
if (fakeStatusBarCfg == FakeStatusBarCfg.NEED_WHEN_LOST) {
addFakeStatusBarWhenLost(activity, rootView, color)
} else if (fakeStatusBarCfg == FakeStatusBarCfg.ALWAYS_NEED) {
addFakeStatusBar(activity, rootView, color)
}
}
private fun addFakeStatusBarWhenLost(
activity: Activity,
rootView: ViewGroup,
@ColorRes color: Int
) {
if (willLossStatusBar(activity))
addFakeStatusBar(activity, rootView, color)
}
private fun addFakeStatusBar(
activity: Activity,
rootView: ViewGroup,
@ColorRes color: Int
) {
catchExceptions {
val decorView = activity.window.decorView as ViewGroup
decorView.findViewById<View>(R.id.un_status_bar_view)?.let {
decorView.removeView(it)
}
val view = View(activity).apply {
id = R.id.un_status_bar_view
layoutParams =
ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, statusBarHeight)
setBackgroundResource(color)
}
decorView.addView(view)
//添加status view后,需将原始布局下移
val lp = rootView.layoutParams as FrameLayout.LayoutParams
lp.topMargin = statusBarHeight
}
}
/**
* 状态栏是否会丢失
*
* 少量特殊设备在多窗口模式下运行,会丢失状态栏!
*
* 这个方法上层可以直接使用,自行处理根布局的高度
*
*/
fun willLossStatusBar(activity: Activity): Boolean {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
//这个条件以后也许会变!
if (activity.isInMultiWindowMode
&& Build.MODEL == "SM-F9160"
// && Build.VERSION.SDK_INT == 33
) {
//SM-F9160是三星折叠屏手机,它在多窗口下,会丢失status bar
return true
}
}
return false
}
}
实际使用:
activity的基类
private fun initStatus() {
StatusBarUtils.tryAddingFakeStatusBar(
this,
fakeStatusBarCfg(), //StatusBarUtils中FakeStatusBarCfg的值
baseBinding.root,
statusBarColor() //沉浸式状态栏的颜色
)
//设置沉浸状态栏——根据实际情况来写
immersionBar = ImmersionBar.with(this)
immersionBar?.run {
statusBarColor(statusBarColor())
statusBarDarkFont(statusBarDarkFont())
init()
}
//子类复写
protected open fun statusBarColor(): Int {
return R.color.transparent
}
//这个方法为Java代码,其余为Kotlin代码——子类复写
protected @StatusBarUtils.FakeStatusBarCfg int fakeStatusBarCfg() {
return StatusBarUtils.FakeStatusBarCfg.NEED_WHEN_LOST;
}
//子类复写
protected open fun statusBarDarkFont(): Boolean {
return !NightModeUtils().isNight()
}










网友评论