Полностью прозрачная строка состояния и панель навигации на леденце
Я пытаюсь сделать андроид лаунчер. Я хочу добиться полностью прозрачной строки состояния и панели навигации, вот мой 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 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
}
Вот и все