Bug
最近开发项目中,遇到一个问题:状态栏是透明的,但Activity顶部部分的布局在状态栏中显示了。如下图:
正常情况下,我们的布局是在状态栏底下展示,如下图:
上图的布局文件,如下:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#FFFFFFFF"
tools:context=".DemoActivity">
<ImageView
android:id="@+id/iv_back"
android:layout_width="25dp"
android:layout_height="25dp"
android:layout_marginStart="25dp"
android:layout_marginTop="35dp"
android:src="@mipmap/ic_arrow_left"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:ignore="MissingConstraints" />
<FrameLayout
android:id="@+id/container"
android:layout_width="390dp"
android:layout_height="match_parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:background="#66000000">
<View
android:id="@+id/view"
android:layout_width="320dp"
android:layout_height="250dp"
android:layout_marginStart="40dp"
android:layout_marginTop="20dp"
android:background="#FF000000"/>
</FrameLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
Solution
基于多个因素的考虑,我的想法是:
- id 为 iv_back 的 ImageView 的顶部外边距添加额外的状态栏高度
- id 为 container 的 FrameLayout 的顶部内边距添加额外的状态啦高度
设置 ImageView 的外边距
- 通过
ViewGroup.MarginLayoutParams # getXXXMargin来获取外边距 - 通过
ViewGroup.MarginLayoutParams # setMargins方法来设置外边距
val statusBarHeight = getStatusBarHeight()
val ivBack: ImageView = findViewById(R.id.iv_back)
// 设置外边距
val marginParams = ivBack.layoutParams as ViewGroup.MarginLayoutParams
marginParams.setMargins(
marginParams.leftMargin,
marginParams.topMargin + statusBarHeight,
marginParams.rightMargin,
marginParams.bottomMargin)
设置 FrameLayout 的内边距
- 通过
View # getXXXPadding获取对应的内边距 - 通过
View # setPadding方法来设置内边距
val container: FrameLayout = findViewById(R.id.container)
// 设置内边距
container.setPadding(
container.paddingLeft,
container.paddingTop + statusBarHeight,
container.paddingRight,
container.paddingBottom)
完整代码
package com.example.mydemoapplication
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.view.ViewGroup
import android.view.WindowManager
import android.widget.FrameLayout
import android.widget.ImageView
class DemoActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_demo)
val statusBarHeight = getStatusBarHeight()
val ivBack: ImageView = findViewById(R.id.iv_back)
// 设置外边距
val marginParams = ivBack.layoutParams as ViewGroup.MarginLayoutParams
marginParams.setMargins(
marginParams.leftMargin,
marginParams.topMargin + statusBarHeight,
marginParams.rightMargin,
marginParams.bottomMargin)
val container: FrameLayout = findViewById(R.id.container)
// 设置内边距
container.setPadding(
container.paddingLeft,
container.paddingTop + statusBarHeight,
container.paddingRight,
container.paddingBottom)
}
private fun getStatusBarHeight(): Int {
var result = 0
val resourceId = resources.getIdentifier("status_bar_height", "dimen", "android")
if (resourceId > 0) {
result = resources.getDimensionPixelSize(resourceId)
}
return result
}
}
Extension
如何设置状态栏透明
- 在
theme.xml文件中,设置主题为NoActionBar,再设定状态栏透明的相关属性,如下:
<style name="Theme.MyDemoApplication" parent="Theme.MaterialComponents.NoActionBar">
...
<!-- 状态栏透明 -->
<item name="android:windowTranslucentStatus">true</item>
<item name="android:statusBarColor">@android:color/transparent</item>
</style>
- 在
AndroidManifest.xml文件中,给标签<applcation>中指定主题
<?xml version="1.0" encoding="utf-8"?>
<manifest ...>
...
<application
...
android:theme="@style/Theme.MyDemoApplication">
...
</application>
...
</manifest>