Android - 让视图文件显示到状态栏下,且不受底部导航虚拟按键影响
最新需要实现这个功能,琢磨了半天,网上也查找了一些资料,不过都是零零散散的,而且大部分是xml实现的,现在我用代码大致来实现一下这个功能。
第一步,获取状态栏高度,底部虚拟导航按键高度
/**
* 获取状态栏高度
*
* @param context 上下文对象
*/
@SuppressLint("PrivateApi")
@JvmStatic
fun getStatusBarHeight(context: Context): Int = try {
val c: Class<*>? = Class.forName("com.android.internal.R\$dimen")
val obj: Any? = c?.newInstance()
val field: Field? = c?.getField("status_bar_height")
if (obj != null && field != null) {
field.isAccessible = true
val x = Integer.parseInt(field.get(obj).toString())
context.resources.getDimensionPixelSize(x)
} else {
75
}
} catch (e1: Exception) {
Log.d("ApkUtil", "get status bar height fail")
e1.printStackTrace()
75
}
/**
* 获取底部导航栏高度
*
* @param context
* @return
*/
@JvmStatic
fun getNavigationBarHeight(context: Context): Int {
if (!isHasNavBar(context)) return 0
val resourceId: Int
val rid = context.resources.getIdentifier("config_showNavigationBar", "bool", "android")
return if (rid != 0) {
resourceId = context.resources.getIdentifier("navigation_bar_height", "dimen", "android")
context.resources.getDimensionPixelSize(resourceId)
} else {
0
}
}
/**
* 判断虚拟按键栏是否重写
*
* @return
*/
private val navBarOverride: String?
@SuppressLint("PrivateApi")
get() {
var sNavBarOverride: String? = null
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
try {
val c = Class.forName("android.os.SystemProperties")
val m = c.getDeclaredMethod("get", String::class.java)
m.isAccessible = true
sNavBarOverride = m.invoke(null, "qemu.hw.mainkeys") as String
} catch (e: Throwable) {
}
}
return sNavBarOverride
}
/**
* 检查是否存在虚拟按键栏
*
* @param context
* @return
*/
@JvmStatic
@TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)
fun isHasNavBar(context: Context): Boolean {
val res = context.resources
val resourceId = res.getIdentifier("config_showNavigationBar", "bool", "android")
return when {
resourceId != 0 -> {
var hasNav = res.getBoolean(resourceId)
// check override flag
val sNavBarOverride = navBarOverride
if ("1" == sNavBarOverride) {
hasNav = false
} else if ("0" == sNavBarOverride) {
hasNav = true
}
hasNav
}
else -> // fallback
!ViewConfiguration.get(context).hasPermanentMenuKey()
}
}
第二步,处理Activity的Window的Flag属性
override fun onCreate(...){
window.requestFeature(Window.FEATURE_NO_TITLE)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
window.addFlags(WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS)
window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS)
window.statusBarColor = Color.TRANSPARENT
window.navigationBarColor = Color.BLACK
}
}
第三步,添加视图到Activity的RootView(DecorView)中
setContentView(
contentView,
WindowManager.LayoutParams(
WindowManager.LayoutParams.MATCH_PARENT,
WindowManager.LayoutParams.MATCH_PARENT
)
)
第四步,动态监听布局变化,动态设置导航栏高度
/** 根据导航栏高度判断页面布局 **/
private fun setContentViewLayoutParamsByNavigationBarHeight() {
val navigationBarHeight by lazy { ApkUtil.getNavigationBarHeight(this@PActivity) }
val lp: FrameLayout.LayoutParams?
if (navigationBarHolderView == null) {
navigationBarHolderView = View(this)
navigationBarHolderView?.setBackgroundColor(Color.BLACK)
lp = FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, navigationBarHeight)
lp.gravity = Gravity.BOTTOM
this@PActivity.rootView.addView(navigationBarHolderView, lp)
} else {
lp = navigationBarHolderView?.layoutParams as? FrameLayout.LayoutParams
lp?.height = navigationBarHeight
navigationBarHolderView?.layoutParams = lp
}
binder.root.setPadding(0, 0, 0, navigationBarHeight)
}
override fun onGlobalLayout() {
if (isContentViewAttachScreenTop)
setContentViewLayoutParamsByNavigationBarHeight()
}
override fun onResume() {
if (isContentViewAttachScreenTop)
rootView.viewTreeObserver.addOnGlobalLayoutListener(this)
super.onResume()
}
override fun onStop() {
super.onStop()
if (isContentViewAttachScreenTop) {
@Suppress("DEPRECATION")
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M)
rootView.viewTreeObserver.removeOnGlobalLayoutListener(this)
else
rootView.viewTreeObserver.removeGlobalOnLayoutListener(this)
}
}
先写成这个样子,后面我有时间会再来修改的!
网友评论