解决Activity布局与透明状态栏重叠的问题

358 阅读2分钟

Bug

最近开发项目中,遇到一个问题:状态栏是透明的,但Activity顶部部分的布局在状态栏中显示了。如下图: e46358eba2aacbcea562e4c3953b16d.jpg

正常情况下,我们的布局是在状态栏底下展示,如下图: 4315762dbd3eb0c0ad7930ce8555c6d.jpg

上图的布局文件,如下:

<?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 的外边距

  1. 通过 ViewGroup.MarginLayoutParams # getXXXMargin 来获取外边距
  2. 通过 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 的内边距

  1. 通过 View # getXXXPadding 获取对应的内边距
  2. 通过 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

如何设置状态栏透明

  1. 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>
  1. AndroidManifest.xml 文件中,给标签 <applcation> 中指定主题
<?xml version="1.0" encoding="utf-8"?>  
<manifest ...>  
    ...
    <application  
        ...
        android:theme="@style/Theme.MyDemoApplication">  
       ...
    </application>  
    ...
</manifest>