獲取狀態欄高度
/**
* 方式一: 通過反射獲取狀態欄高度
*/
@SuppressLint("PrivateApi")
private fun getStatusBarHeight(context: Context): Int {
var statusbarheight = 0
try {
val c = Class.forName("com.android.internal.R\$dimen")
val o = c.newInstance()
val field: Field = c.getField("status_bar_height")
val x = field.get(o) as Int
statusbarheight = context.getResources().getDimensionPixelSize(x)
} catch (e: Exception) {
e.printStackTrace()
}
return statusbarheight
}
/**
* 方式二:通過getWindowVisibleDisplayFrame方法獲取狀態欄高度
*/
private fun getStatusBarHeight(view: View): Int {
val outRect = Rect()
view.getWindowVisibleDisplayFrame(outRect)
return outRect.top
}
測試:
et_receive_comment.viewTreeObserver.addOnGlobalLayoutListener {
//獲取狀態欄高度
val statusBarHeight1 = getStatusBarHeight(et_receive_comment)
println("statusBarHeight1=================================$statusBarHeight1")
val statusBarHeight2 = getStatusBarHeight(et_receive_comment.context)
println("statusBarHeight2=================================$statusBarHeight2")
}
view.parent 與 view.rootView
et_receive_comment.viewTreeObserver.addOnGlobalLayoutListener {
//父view
val parent = et_receive_comment.parent
//根view : DecorView
val rootView = et_receive_comment.rootView
println("parent======================$parent")
println("rootView======================$rootView")
//DecorView 高度不會變
val rootViewHeight = et_receive_comment.rootView.height
println("DecorView 高度======================$rootViewHeight")//1520
}
一、使用工具類獲取狀態欄,導航欄,標題欄高度:
https://github.com/Blankj/AndroidUtilCode
implementation 'com.blankj:utilcodex:1.28.3'
Log.e(TAG, "getScreenHeight========" + ScreenUtils.getScreenHeight())//1520
Log.e(TAG, "getActionBarHeight========" + BarUtils.getActionBarHeight())//112
Log.e(TAG, "getNavBarHeight===========" + BarUtils.getNavBarHeight())//80
Log.e(TAG, "getStatusBarHeight========" + BarUtils.getStatusBarHeight())//55
二、decorView.getWindowVisibleDisplayFrame獲取狀態欄高度
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
gallery.viewTreeObserver
.addOnGlobalLayoutListener {
Log.e(TAG, "=============================================================")
val decorView = window.decorView
Log.e(TAG, "decorView ===================== $decorView")
Log.e(TAG, "decorView.height ===================== ${decorView.height}")//1520
//decorView.getWindowVisibleDisplayFrame
//注意:
//1、rect.top/bottom/height的值不會隨着主題NoActionBar變化
//2、rect.bottom/height 的值會隨着軟鍵盤的打開而變小
val rect = Rect()
decorView.getWindowVisibleDisplayFrame(rect)
Log.e(TAG, "rect.top ===================== ${rect.top}")//55
Log.e(TAG, "rect.bottom ================== ${rect.bottom}")//1440
Log.e(TAG, "rect height ================== ${rect.bottom - rect.top}")//1385
//decorView.findViewById<View>(Window.ID_ANDROID_CONTENT)
//view.top/bottom : 相對父容器
val contentTop = decorView.findViewById<View>(Window.ID_ANDROID_CONTENT).top
val contentBottom = decorView.findViewById<View>(Window.ID_ANDROID_CONTENT).bottom
val contentHeight = contentBottom - contentTop
//注意:
//1、如果設置NoActionBar的主題contentTop爲0, contentBottom = contentHeight = 1385
//2、contentBottom/height 的值會隨着軟鍵盤的打開而變小
Log.e(TAG, "content top ================== $contentTop")//112 / 0
Log.e(TAG, "content bottom ================== $contentBottom")//1385
Log.e(TAG, "content height ================== $contentHeight")//1273 / 1385
Log.e(TAG, "狀態欄高度 ================== ${rect.top}")//55
Log.e(TAG, "標題欄高度 ================== $contentTop")//112 / 0
Log.e(TAG, "內容高度 ================== $contentHeight")//1273
//獲取content的方式有以下兩種方式
// 打印結果一致:
iteratorContentView1()
iteratorContentView2()
}
}
private fun iteratorContentView1() {
val contentView1 = window.decorView.findViewById<View>(Window.ID_ANDROID_CONTENT)
Log.e(TAG, "contentView1=================$contentView1")
//androidx.appcompat.widget.ContentFrameLayout
// {8b0458c V.E...... .......D 0,112-720,1385 #1020002 android:id/content}
if (contentView1 is FrameLayout) {
val childCount = contentView1.childCount
for (i in 0 until childCount) {
val childView = contentView1.getChildAt(i)
Log.e(TAG, "$i=================$childView")
//我們自己的佈局
//0 === androidx.constraintlayout.widget.ConstraintLayout
// {e8674d5 V.E...... .......D 0,0-720,1273 #7f080058 app:id/container}
}
}
}
private fun iteratorContentView2() {
val contentView2 = this.findViewById<View>(android.R.id.content)
Log.e(TAG, "contentView2=================$contentView2")
if (contentView2 is FrameLayout) {
val childCount = contentView2.childCount
for (i in 0 until childCount) {
val childView = contentView2.getChildAt(i)
Log.e(TAG, "$i=================$childView")
}
}
}
view樹結構
帶標題的界面佈局
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
</androidx.constraintlayout.widget.ConstraintLayout>
查看view樹結構 :
- class com.android.internal.policy.DecorView
- android.widget.LinearLayout{}
- android.view.ViewStub{android:id/action_mode_bar_stub}
- android.widget.FrameLayout{}
- androidx.appcompat.widget.ActionBarOverlayLayout{app:id/decor_content_parent}
- androidx.appcompat.widget.ContentFrameLayout{android:id/content}
- androidx.constraintlayout.widget.ConstraintLayout{app:id/container}
- 自己的佈局…
- androidx.constraintlayout.widget.ConstraintLayout{app:id/container}
- androidx.appcompat.widget.ActionBarContainer{app:id/action_bar_container}
- androidx.appcompat.widget.Toolbar{app:id/action_bar}
- androidx.appcompat.widget.AppCompatTextView{}
- androidx.appcompat.widget.ActionBarContextView{app:id/action_context_bar}
- androidx.appcompat.widget.Toolbar{app:id/action_bar}
- androidx.appcompat.widget.ContentFrameLayout{android:id/content}
- androidx.appcompat.widget.ActionBarOverlayLayout{app:id/decor_content_parent}
- android.widget.LinearLayout{}