Полностью прозрачная строка состояния и панель навигации на леденце

Я пытаюсь сделать андроид лаунчер. Я хочу добиться полностью прозрачной строки состояния и панели навигации, вот мой xml-файл темы.

<resources>
    <style name="Theme" parent="android:Theme.Material.Wallpaper.NoTitleBar">
        <item name="android:statusBarColor">@android:color/transparent</item>
        <item name="android:navigationBarColor">@android:color/transparent</item>
        <item name="android:windowTranslucentStatus">false</item>
        <item name="android:windowTranslucentNavigation">false</item>
    </style>
</resources>

последние два пункта не работают, на леденце все еще есть тень.

Вот как это выглядит (обратите внимание, что на панели состояния и на панели навигации есть тень):

чего я хочу достичь (nova launcher):

как сделать строку состояния и панель навигации "прозрачной" вместо "полупрозрачной"?

13 ответов

Обновить

Вы можете добиться того же эффекта программно на KitKat, а затем, установив FLAG_LAYOUT_NO_LIMITS флаг внутри Window,

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
            Window w = getWindow(); // in Activity's onCreate() for instance
            w.setFlags(WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS, WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS);
        }

Если вы установите фоновый ресурс (например, цвет или рисунок) для своего макета, вы увидите цвет или изображение "под" строкой состояния.

<item name="android:windowDrawsSystemBarBackgrounds">true</item>
<item name="android:statusBarColor">@color/primary_dark</item>

Оригинальный ответ

Это выглядит как android:windowTranslucentStatus а также android:windowTranslucentNavigation должно быть true вместо false

<resources>
    <style name="Theme" parent="android:Theme.Material.Wallpaper.NoTitleBar">
        <item name="android:statusBarColor">@android:color/transparent</item>
        <item name="android:navigationBarColor">@android:color/transparent</item>
        <item name="android:windowTranslucentStatus">true</item>
        <item name="android:windowTranslucentNavigation">true</item>
    </style>
</resources>

Кроме того, для вашего прозрачного макета деятельности / контейнера требуется этот набор свойств:

android:fitsSystemWindows="true"

Источник

Вы можете использовать эту функцию расширения kotlin, она установит полностью прозрачную строку состояния (в API 23+,View.SYSTEM_UI_FLAG_LIGHT_STATUS_BARфлаг доступен в API 23+) и панели навигации (в API 27+,View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BARдоступный в API 27+), в противном случае будет использоватьсяsystemUiScrimцвет по API 21+

fun Activity.transparentStatusAndNavigation(
    systemUiScrim: Int = Color.parseColor("#40000000") // 25% black
) {
    var systemUiVisibility = 0
    // Use a dark scrim by default since light status is API 23+
    var statusBarColor = systemUiScrim
    //  Use a dark scrim by default since light nav bar is API 27+
    var navigationBarColor = systemUiScrim
    val winParams = window.attributes


    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
        systemUiVisibility = systemUiVisibility or View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR
        statusBarColor = Color.TRANSPARENT
    }
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
        systemUiVisibility = systemUiVisibility or View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR
        navigationBarColor = Color.TRANSPARENT
    }
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
        systemUiVisibility = systemUiVisibility or
                View.SYSTEM_UI_FLAG_LAYOUT_STABLE or
                View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN or
                View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
        window.decorView.systemUiVisibility = systemUiVisibility
    }
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT && Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
        winParams.flags = winParams.flags or
                WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS or
                WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION
    }
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
        winParams.flags = winParams.flags and
                (WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS or
                        WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION).inv()
        window.statusBarColor = statusBarColor
        window.navigationBarColor = navigationBarColor
    }

    window.attributes = winParams
}

API 21+API 27+

Для API 29 и выше используйте

<style name="Your.Theme">
    <item name="android:navigationBarColor">@android:color/transparent</item>
    <item name="android:enforceNavigationBarContrast">false</item>
</style>

Я использую это, так как он сохраняет высоту строки состояния и панели навигации

<!-- Base application theme. -->
<style name="theme" parent="android:Theme.Material.Wallpaper.NoTitleBar">
    <item name="android:navigationBarColor">#00000000</item>
    <item name="android:statusBarColor">#00000000</item>
</style>

Однако для этого требуется API 21+

100% рабочий код

Полностью прозрачная панель состояния и панель навигации

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    transparentStatusAndNavigation();
}


private void transparentStatusAndNavigation() {
    //make full transparent statusBar
    if (Build.VERSION.SDK_INT >= 19 && Build.VERSION.SDK_INT < 21) {
        setWindowFlag(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS
                | WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION, true);
    }
    if (Build.VERSION.SDK_INT >= 19) {
        getWindow().getDecorView().setSystemUiVisibility(
                View.SYSTEM_UI_FLAG_LAYOUT_STABLE
                        | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
                        | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
        );
    }
    if (Build.VERSION.SDK_INT >= 21) {
        setWindowFlag(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS
                | WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION, false);
        getWindow().setStatusBarColor(Color.TRANSPARENT);
        getWindow().setNavigationBarColor(Color.TRANSPARENT);
    }
}

private void setWindowFlag(final int bits, boolean on) {
    Window win = getWindow();
    WindowManager.LayoutParams winParams = win.getAttributes();
    if (on) {
        winParams.flags |= bits;
    } else {
        winParams.flags &= ~bits;
    }
    win.setAttributes(winParams);
}

Вам нужно добавить android:windowDrawsSystemBarBackgrounds пометить вам тему

<item name="android:windowDrawsSystemBarBackgrounds">true</item>

Или вызовите это в onCreate()

getWindow().addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);

Следующий код является примером того, что я использую в своем проекте:

styles.xml

<style name="FadingActionBarTheme" parent="@android:style/Theme.Holo.Light.DarkActionBar">
    <item name="android:actionBarStyle">@style/FadingActionBarWidget</item>
</style>

<style name="FadingActionBarWidget.Transparent">
    <item name="android:background">@android:color/transparent</item>
</style>

<style name="FadingActionBarTheme.TranslucentActionBar">
    <item name="android:icon">@drawable/ic_ab_icon</item>
    <item name="android:actionBarStyle">@style/FadingActionBarWidget.Transparent</item>
    <item name="android:windowActionBarOverlay">true</item>
    <item name="android:windowContentOverlay">@null</item>
</style>

AndroidManifest.xml

<activity
    android:name=".MyActivity"
    android:label="@string/app_name"
    android:theme="@style/FadingActionBarTheme.TranslucentActionBar">
</activity>

Чтобы нарисовать макет под строкой состояния:

Значения /styles.xml

<item name="android:windowTranslucentStatus">true</item>

Значения-V21/styles.xml

<item name="android:windowDrawsSystemBarBackgrounds">true</item>
<item name="android:statusBarColor">@color/colorPrimaryDark</item>

Используйте CoordinatorLayout/DrawerLayout, который уже позаботится о параметре fitsSystemWindows, или создайте свой собственный макет так:

public class FitsSystemWindowConstraintLayout extends ConstraintLayout {

    private Drawable mStatusBarBackground;
    private boolean mDrawStatusBarBackground;

    private WindowInsetsCompat mLastInsets;

    private Map<View, int[]> childsMargins = new HashMap<>();

    public FitsSystemWindowConstraintLayout(Context context) {
        this(context, null);
    }

    public FitsSystemWindowConstraintLayout(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public FitsSystemWindowConstraintLayout(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);

        if (ViewCompat.getFitsSystemWindows(this)) {
            ViewCompat.setOnApplyWindowInsetsListener(this, new android.support.v4.view.OnApplyWindowInsetsListener() {
                @Override
                public WindowInsetsCompat onApplyWindowInsets(View view, WindowInsetsCompat insets) {
                    FitsSystemWindowConstraintLayout layout = (FitsSystemWindowConstraintLayout) view;
                    layout.setChildInsets(insets, insets.getSystemWindowInsetTop() > 0);
                    return insets.consumeSystemWindowInsets();
                }
            });
            setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE
                    | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);
            TypedArray typedArray = context.obtainStyledAttributes(new int[]{android.R.attr.colorPrimaryDark});
            try {
                mStatusBarBackground = typedArray.getDrawable(0);
            } finally {
                typedArray.recycle();
            }
        } else {
            mStatusBarBackground = null;
        }
    }

    public void setChildInsets(WindowInsetsCompat insets, boolean draw) {
        mLastInsets = insets;
        mDrawStatusBarBackground = draw;
        setWillNotDraw(!draw && getBackground() == null);

        for (int i = 0; i < getChildCount(); i++) {
            View child = getChildAt(i);
            if (child.getVisibility() != GONE) {
                if (ViewCompat.getFitsSystemWindows(this)) {
                    ConstraintLayout.LayoutParams layoutParams = (ConstraintLayout.LayoutParams) child.getLayoutParams();

                    if (ViewCompat.getFitsSystemWindows(child)) {
                        ViewCompat.dispatchApplyWindowInsets(child, insets);
                    } else {
                        int[] childMargins = childsMargins.get(child);
                        if (childMargins == null) {
                            childMargins = new int[]{layoutParams.leftMargin, layoutParams.topMargin, layoutParams.rightMargin, layoutParams.bottomMargin};
                            childsMargins.put(child, childMargins);
                        }
                        if (layoutParams.leftToLeft == LayoutParams.PARENT_ID) {
                            layoutParams.leftMargin = childMargins[0] + insets.getSystemWindowInsetLeft();
                        }
                        if (layoutParams.topToTop == LayoutParams.PARENT_ID) {
                            layoutParams.topMargin = childMargins[1] + insets.getSystemWindowInsetTop();
                        }
                        if (layoutParams.rightToRight == LayoutParams.PARENT_ID) {
                            layoutParams.rightMargin = childMargins[2] + insets.getSystemWindowInsetRight();
                        }
                        if (layoutParams.bottomToBottom == LayoutParams.PARENT_ID) {
                            layoutParams.bottomMargin = childMargins[3] + insets.getSystemWindowInsetBottom();
                        }
                    }
                }
            }
        }

        requestLayout();
    }

    public void setStatusBarBackground(Drawable bg) {
        mStatusBarBackground = bg;
        invalidate();
    }

    public Drawable getStatusBarBackgroundDrawable() {
        return mStatusBarBackground;
    }

    public void setStatusBarBackground(int resId) {
        mStatusBarBackground = resId != 0 ? ContextCompat.getDrawable(getContext(), resId) : null;
        invalidate();
    }

    public void setStatusBarBackgroundColor(@ColorInt int color) {
        mStatusBarBackground = new ColorDrawable(color);
        invalidate();
    }

    @Override
    public void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        if (mDrawStatusBarBackground && mStatusBarBackground != null) {
            int inset = mLastInsets != null ? mLastInsets.getSystemWindowInsetTop() : 0;
            if (inset > 0) {
                mStatusBarBackground.setBounds(0, 0, getWidth(), inset);
                mStatusBarBackground.draw(canvas);
            }
        }
    }
}

main_activity.xml

<FitsSystemWindowConstraintLayout 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:fitsSystemWindows="true">

    <ImageView
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:fitsSystemWindows="true"
        android:scaleType="centerCrop"
        android:src="@drawable/toolbar_background"
        app:layout_constraintBottom_toBottomOf="@id/toolbar"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <android.support.v7.widget.Toolbar
        android:id="@+id/toolbar"
        android:layout_width="0dp"
        android:layout_height="?attr/actionBarSize"
        android:background="@android:color/transparent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <LinearLayout
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:gravity="center"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toBottomOf="@id/toolbar">

        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:gravity="center"
            android:text="Content"
            android:textSize="48sp" />
    </LinearLayout>
</FitsSystemWindowConstraintLayout>

Результат:

результат

Основываясь на ответе Арпана Саркара, только что использован WindowCompat, чтобы уменьшить объем кода и избежать использования устаревших определений,

      fun Activity.transparentSystemBars(
    behindStatusBarIsLight: Boolean,
    behindNavigationBarIsLight: Boolean,
) {
    // Android 4 is hard to debug and apparently ViewCompat.setOnApplyWindowInsetsListener isn't
    // reporting any value there so let's skip and simplify
    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) return

    WindowCompat.setDecorFitsSystemWindows(window, false)

    if (behindStatusBarIsLight || behindNavigationBarIsLight) {
        val insetsController: WindowInsetsControllerCompat =
            WindowCompat.getInsetsController(window, window.decorView)
        if (behindStatusBarIsLight)
            insetsController.isAppearanceLightStatusBars = true
        if (behindNavigationBarIsLight)
            insetsController.isAppearanceLightNavigationBars = true
    }
    
    val isLightStatusBarAvailable = Build.VERSION.SDK_INT >= Build.VERSION_CODES.M
    val isLightNavigationBarAvailable = Build.VERSION.SDK_INT >= Build.VERSION_CODES.O
    val shouldStatusBarBeTransparent = !behindStatusBarIsLight || isLightStatusBarAvailable
    val shouldNavigationBarBeTransparent = !behindNavigationBarIsLight || isLightNavigationBarAvailable

    val systemUiScrim = ColorUtils.setAlphaComponent(Color.BLACK, 0x40) // 25% black
    window.statusBarColor = if (shouldStatusBarBeTransparent) Color.TRANSPARENT else systemUiScrim
    window.navigationBarColor = if (shouldNavigationBarBeTransparent) Color.TRANSPARENT else systemUiScrim

    // You may set android:enforceNavigationBarContrast to false in style.xml as doing it in code isn't as effective apparently.
}

В библиотеке материалов также есть EdgeToEdgeUtils.applyEdgeToEdge , который работает, но не предназначен для использования обычными разработчиками, думаю, когда-нибудь он будет предоставлен публике.

Это для новичков, таких как я, на Nativescript + Angular. Я начал с одного из пустых шаблонов на торговой площадке NTS . Затем для моего конкретного использования мне нужно, чтобы строка состояния вверху всегда была прозрачной (аналогично стилю iOS), а панель навигации (внизу) была полностью прозрачной (не полупрозрачной!) Для некоторых компонентов / модулей и непрозрачной для других. Если все сделано в соответствии с протоколом, установленным NTS, у вас должен быть файл main.ts (предварительное условие для моего решения), подобный этому

Я разделил свою работу на две части, сначала верх, затем низ. Для вершины я нашел, что этот ответ сработал. Итак, у вас должен быть файл main.ts, который выглядит так.

      import { platformNativeScriptDynamic } from "@nativescript/angular";

import { AppModule } from "./app/app.module";

import * as application from "tns-core-modules/application";
import { Color } from "@nativescript/core";

platformNativeScriptDynamic().bootstrapModule(AppModule);

declare var android;

application.android.on(application.AndroidApplication.activityCreatedEvent, (event) => {

    const activity = event.activity;
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) {
    activity.getWindow().addFlags(android.view.WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
    activity.getWindow().clearFlags(android.view.WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
    activity.getWindow().addFlags(android.view.WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION);
    activity.getWindow().setStatusBarColor(android.graphics.Color.TRANSPARENT);
    activity.getWindow().setNavigationBarColor(android.graphics.Color.TRANSPARENT);

} else {
    activity.getWindow().addFlags(android.view.WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
    activity.getWindow().setNavigationBarColor(android.graphics.Color.TRANSPARENT);
}

const parent = activity.findViewById(android.R.id.content);
for (let i = 0; i < parent.getChildCount(); i++) {
    const childView = parent.getChildAt(i);
    if (childView instanceof android.view.ViewGroup) {
        childView.setFitsSystemWindows(true);
        childView.setClipToPadding(true);
    }
}

});

Затем, чтобы добавить прозрачности навигационной панели, я выполнил это и добавил это в строку 24 файла main.ts выше. activity.getWindow().addFlags(android.view.WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS);

Учтите, что есть также файлы styles.xml, которые мы должны уважать, поэтому мой файл styles.xml (App_Resources\Android\ src \ main \ res \values ​​\styles.xml) выглядит так:

          <?xml version="1.0" encoding="utf-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android">

<!-- theme to use FOR launch screen-->
<style name="LaunchScreenThemeBase" parent="Theme.AppCompat.Light.NoActionBar">
    <item name="toolbarStyle">@style/NativeScriptToolbarStyle</item>
    <item name="colorPrimary">@color/ns_primary</item>
    <item name="colorPrimaryDark">@color/ns_primaryDark</item>
    <item name="colorAccent">@color/ns_accent</item>
    <item name="android:windowBackground">@drawable/splash_screen</item>
    <item name="android:statusBarColor">@color/transparent</item>
</style>

<style name="LaunchScreenTheme" parent="LaunchScreenThemeBase"></style>

<!-- theme to use AFTER launch screen is loaded-->
<style name="AppThemeBase" parent="Theme.AppCompat.Light.NoActionBar">
    <item name="toolbarStyle">@style/NativeScriptToolbarStyle</item>
    <item name="colorPrimary">@color/ns_primary</item>
    <item name="colorPrimaryDark">@color/ns_primaryDark</item>
    <item name="colorAccent">@color/ns_accent</item>
    <item name="android:statusBarColor">@color/transparent</item>
    <item name="android:navigationBarColor">@color/transparent</item>

    <item name="android:windowDrawsSystemBarBackgrounds">true</item>
    <item name="android:windowTranslucentNavigation">false</item>
</style>

<style name="AppTheme" parent="AppThemeBase"></style>

<!-- theme for action-bar -->
<style name="NativeScriptToolbarStyleBase" parent="Widget.AppCompat.Toolbar">
    <item name="android:background">@color/transparent</item>
    <item name="theme">@color/transparent</item>
    <item name="popupTheme">@color/transparent</item>
</style>

<style name="NativeScriptToolbarStyle" parent="NativeScriptToolbarStyleBase"></style>

Мне потребовалось 2-3 дня, чтобы разобраться, надеюсь, это поможет

Для тех, кому нужна полностью прозрачная строка состояния и панель навигации на KitKat и выше, существует небольшой конфликт с использованием windowTranslucentNavigation с ответом @Machado для Lollipop и для предотвращения этого конфликта разделите стили

styles.xml

<style name="LockScreenStyle" parent="@android:style/Theme.Wallpaper.NoTitleBar">
    <item name="android:windowTranslucentStatus" tools:targetApi="kitkat">true</item>
    <item name="android:windowTranslucentNavigation" tools:targetApi="kitkat">true</item>
</style>

styles.xml (v21)

<style name="LockScreenStyle" parent="@android:style/Theme.Wallpaper.NoTitleBar">
    <item name="android:windowDrawsSystemBarBackgrounds">true</item>
</style>

MyClass.java

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
        Window w = getWindow(); // in Activity's onCreate() for instance
        w.setFlags(WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS,
                WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS);

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            w.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
        }
    }

Вы также можете изменить альфа-канал для цветов colorPrimary и colorPrimaryDark на 00, а затем добавить это в свой onCreateMethod:

    window.decorView.systemUiVisibility = View.SYSTEM_UI_FLAG_LAYOUT_STABLE or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN

а также добавьте это в свою деятельность:

android:fitsSystemWindows="true"

Из Android R

      fun Activity.setTransparentStatusBar() {
    WindowCompat.setDecorFitsSystemWindows(window, false)
    window.statusBarColor = Color.TRANSPARENT
    window.navigationBarColor = Color.TRANSPARENT
}

Вот и все

Другие вопросы по тегам