Леденец на палочке: рисовать за статусбаром с прозрачным цветом
Я установил мой статус statusBar прозрачным для Lollipop только со следующей строкой в моей теме:
<item name="android:statusBarColor">@android:color/transparent</item>
Теперь мне нужно отрисоваться за ним, но я не могу сделать вид за ним. Я знаю, как это сделать с windowTranslucentStatus
свойство, но не хочу использовать это свойство, так как оно тогда будет игнорировать цвет statusBar, установленный на прозрачный.
13 ответов
Способ № 1:
Для достижения полностью прозрачной строки состояния, вы должны использовать statusBarColor
, который доступен только для API 21 и выше. windowTranslucentStatus
доступно для API 19 и выше, но добавляет тонированный фон для строки состояния. Однако настройка windowTranslucentStatus
действительно достигает одной вещи, которая меняется statusBarColor
к прозрачному нет: он устанавливает SYSTEM_UI_FLAG_LAYOUT_STABLE
а также SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
флаги. Самый простой способ получить тот же эффект - вручную установить эти флаги, что эффективно отключает вставки, наложенные системой макетов Android, и оставляет вас наедине с собой.
Вы называете эту линию в вашем onCreate
метод:
getWindow().getDecorView().setSystemUiVisibility(
View.SYSTEM_UI_FLAG_LAYOUT_STABLE
| View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);
Не забудьте также установить прозрачность в /res/values-v21/styles.xml:
<item name="android:statusBarColor">@android:color/transparent</item>
Или установите прозрачность программно:
getWindow().setStatusBarColor(Color.TRANSPARENT);
Хорошая сторона этого подхода заключается в том, что те же макеты и дизайны также можно использовать в API 19 путем замены прозрачной строки состояния на тонированную полупрозрачную строку состояния.
<item name="android:windowTranslucentStatus">true</item>
Способ № 2:
Если вам нужно только нарисовать фоновое изображение под строкой состояния, а не размещать вид позади него, это можно сделать, просто установив фон темы вашей деятельности на желаемое изображение и установив прозрачность строки состояния, как показано в методе #1. Это был метод, который я использовал для создания скриншотов для статьи из Android Police несколько месяцев назад.
Способ № 3:
Если вам нужно игнорировать стандартные системные вставки для некоторых макетов, оставляя их работающими в других, единственный реальный способ сделать это - работать с часто связаннымиScrimInsetsFrameLayout
учебный класс. Конечно, некоторые вещи, выполненные в этом классе, не являются необходимыми для всех сценариев. Например, если вы не планируете использовать синтетическое наложение строки состояния, просто закомментируйте все в init()
метод и не надо ничего добавлять в файл attrs.xml. Я видел, как этот подход работает, но я думаю, вы обнаружите, что он имеет некоторые другие последствия, которые могут быть много работы, чтобы обойти.
Я также видел, что вы против упаковки нескольких макетов. В случае оборачивания одного макета внутри другого, где оба имеют match_parent
для высоты и ширины влияние на производительность слишком тривиально, чтобы о нем беспокоиться. Несмотря на это, вы можете полностью избежать этой ситуации, изменив класс, который она расширяет FrameLayout
к любому другому типу класса макета, который вам нравится. Это будет работать просто отлично.
Это сработало для моего случая
// Create/Set toolbar as actionbar
toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
// Check if the version of Android is Lollipop or higher
if (Build.VERSION.SDK_INT >= 21) {
// Set the status bar to dark-semi-transparentish
getWindow().setFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS,
WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
// Set paddingTop of toolbar to height of status bar.
// Fixes statusbar covers toolbar issue
toolbar.setPadding(0, getStatusBarHeight(), 0, 0);
}
// A method to find height of the status bar
public int getStatusBarHeight() {
int result = 0;
int resourceId = getResources().getIdentifier("status_bar_height", "dimen", "android");
if (resourceId > 0) {
result = getResources().getDimensionPixelSize(resourceId);
}
return result;
}
Для получения дополнительной информации о работе с statusBars: http://youtube.com/watch?v=_mGDMVRO3iE
Попробуйте эту тему
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
<!-- Customize your theme here. -->
<item name="windowActionBar">false</item>
<item name="windowNoTitle">true</item>
<item name="colorPrimaryDark">@android:color/transparent</item>
<item name="colorPrimary">@color/md_blue_200</item>
<item name="android:windowDrawsSystemBarBackgrounds">true</item>
<item name="android:statusBarColor">@android:color/transparent</item>
<item name="android:windowTranslucentStatus">true</item>
</style>
Убедитесь, что ваш макет установлен
android:fitsSystemWindows="false"
Вместо
<item name="android:statusBarColor">@android:color/transparent</item>
Используйте следующее:
<item name="android:windowTranslucentStatus">true</item>
И обязательно удалите верхний отступ (который добавлен по умолчанию) в макете "MainActivity".
Обратите внимание, что это не делает строку состояния полностью прозрачной, и над строкой состояния все равно будет наложение "блекло-черный".
Решение от Коди Тоомбса почти помогло мне. Я не уверен, связано ли это с Xamarin или нет, но теперь у меня есть приемлемое решение:
Это моя установка:
У меня есть проект Android, где я ссылался на пакеты Android.Support v4 и v7. У меня определены два стиля:
Значения /styles.xml:
<?xml version="1.0" encoding="UTF-8" ?>
<resources>
<style name="MyStyle" parent="@style/Theme.AppCompat.Light.NoActionBar">
<item name="android:windowTranslucentStatus">true</item>
</style>
</resources>
Значения-V21 /styles.xml:
<?xml version="1.0" encoding="UTF-8" ?>
<resources>
<style name="MyStyle" parent="@style/Theme.AppCompat.Light.NoActionBar">
<item name="android:statusBarColor">@android:color/transparent</item>
</style>
</resources>
AndroidManifest цели "MyStyle":
AndroidManifest.xml:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:versionCode="1" android:versionName="1.0" package="com.agn.test.test">
<uses-sdk android:minSdkVersion="10" />
<application android:allowBackup="true" android:icon="@mipmap/icon" android:label="@string/app_name" android:theme="@style/MyStyle">
</application>
</manifest>
И, наконец, код в основной деятельности:
[Activity (Label = "Test", MainLauncher = true, Icon = "@mipmap/icon")]
public class MainActivity : Activity
{
protected override void OnCreate (Bundle savedInstanceState)
{
base.OnCreate (savedInstanceState);
SetContentView (Resource.Layout.Main);
//Resource.Layout.Main is just a regular layout, no additional flags. Make sure there is something in there like an imageView, so that you can see the overlay.
var uiOptions = (int)Window.DecorView.SystemUiVisibility;
uiOptions ^= (int)SystemUiFlags.LayoutStable;
uiOptions ^= (int)SystemUiFlags.LayoutFullscreen;
Window.DecorView.SystemUiVisibility = (StatusBarVisibility)uiOptions;
Window.AddFlags (WindowManagerFlags.DrawsSystemBarBackgrounds);
}
}
Обратите внимание, что я установил флаг DrawsSystemBarBackgrounds, это имеет все значение
Window.AddFlags (WindowManagerFlags.DrawsSystemBarBackgrounds);
Я потратил много времени, чтобы понять это правильно, слишком много времени на самом деле. Надеюсь, этот ответ поможет любому, кто пытается достичь того же.
Ответ @Cody Toombs приводит к проблеме, которая приводит к расположению позади панели навигации. Итак, я обнаружил, что использую это решение, данное @Kriti
Вот фрагмент кода Kotlin для того же:
if (Build.VERSION.SDK_INT >= 19 && Build.VERSION.SDK_INT < 21) {
setWindowFlag(this, WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS, true)
}
if (Build.VERSION.SDK_INT >= 19) {
window.decorView.systemUiVisibility = View.SYSTEM_UI_FLAG_LAYOUT_STABLE or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
}
if (Build.VERSION.SDK_INT >= 21) {
setWindowFlag(this, WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS, false)
getWindow().setStatusBarColor(Color.TRANSPARENT)
}
private fun setWindowFlag(activity: Activity, bits: Int, on: Boolean) {
val win: Window = activity.getWindow()
val winParams: WindowManager.LayoutParams = win.getAttributes()
if (on) {
winParams.flags = winParams.flags or bits
} else {
winParams.flags = winParams.flags and bits.inv()
}
win.setAttributes(winParams)
}
Вы также должны добавить
android:fitsSystemWindows="false"
корневой вид вашего макета.
У меня была та же проблема, поэтому я создаю ImageView, который рисует за строкой API 19+
Установить собственное изображение позади строки состояния gist.github.com
public static void setTransparent(Activity activity, int imageRes) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) {
return;
}
// set flags
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
activity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION);
activity.getWindow().setStatusBarColor(Color.TRANSPARENT);
} else {
activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
}
// get root content of system window
//ViewGroup rootView = (ViewGroup) ((ViewGroup) activity.findViewById(android.R.id.content)).getChildAt(0);
// rootView.setFitsSystemWindows(true);
// rootView.setClipToPadding(true);
ViewGroup contentView = (ViewGroup) activity.findViewById(android.R.id.content);
if (contentView.getChildCount() > 1) {
contentView.removeViewAt(1);
}
// get status bar height
int res = activity.getResources().getIdentifier("status_bar_height", "dimen", "android");
int height = 0;
if (res != 0)
height = activity.getResources().getDimensionPixelSize(res);
// create new imageview and set resource id
ImageView image = new ImageView(activity);
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, height);
image.setLayoutParams(params);
image.setImageResource(imageRes);
image.setScaleType(ScaleType.MATRIX);
// add image view to content view
contentView.addView(image);
// rootView.setFitsSystemWindows(true);
}
Вы можете использовать ScrimInsetFrameLayout
android: fitsSystemWindows = "true" должен быть установлен на макете холста!
Аналогично некоторым опубликованным решениям, но в моем случае я сделал строку состояния прозрачной и зафиксировал положение панели действий с некоторым отрицательным полем.
if (Build.VERSION.SDK_INT >= 21) {
getWindow().setStatusBarColor(Color.TRANSPARENT);
FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) toolbar.getLayoutParams();
lp.setMargins(0, -getStatusBarHeight(), 0, 0);
}
И я использовал в панели инструментов и в корневом представлении
android:fitsSystemWindows="true"
Есть хорошая библиотека StatusBarUtil от @laobie, которая помогает легко рисовать изображения в StatusBar.
Просто добавьте в свой build.gradle
:
compile 'com.jaeger.statusbarutil:library:1.4.0'
Затем в наборе действий
StatusBarUtil.setTranslucentForImageView(Activity activity, int statusBarAlpha, View viewNeedOffset)
В макете
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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="@color/white"
android:orientation="vertical">
<ImageView
android:layout_alignParentTop="true"
android:layout_width="match_parent"
android:adjustViewBounds="true"
android:layout_height="wrap_content"
android:src="@drawable/toolbar_bg"/>
<android.support.design.widget.CoordinatorLayout
android:id="@+id/view_need_offset"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="@android:color/transparent"
app:popupTheme="@style/ThemeOverlay.AppCompat.Light"
app:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"/>
<!-- Your layout code -->
</android.support.design.widget.CoordinatorLayout>
</RelativeLayout>
Для получения дополнительной информации загрузите демо или клон со страницы github и поиграйте со всеми функциями.
Примечание: поддержка KitKat и выше.
Надеюсь, что это поможет кому-то еще!
Я добавлю сюда дополнительную информацию. Последние разработки для Android позволили довольно легко обрабатывать множество случаев в строке состояния. Ниже приведены мои наблюдения изstyles.xml
- Цвет фона: для SDK 21+, как упоминалось во многих ответах,
<item name="android:windowTranslucentStatus">true</item>
сделает строку состояния прозрачной и отобразится перед пользовательским интерфейсом. Ваша Activity займет все пространство вверху. Цвет фона: опять же, для SDK 21+,
<item name="android:statusBarColor">@color/your_color</item>
просто придаст цвет вашей строке состояния, не влияя ни на что другое.Однако на более поздних устройствах (Android M/+) значки стали иметь разные оттенки. ОС может придать значкам SDK 23/+ более темный оттенок серого, если вы переопределите
styles.xml
файл вvalues-23
папку и добавить<item name="android:windowLightStatusBar">true</item>
.
Таким образом, вы предоставите своему пользователю более заметную строку состояния, если ваша строка состояния имеет светлый цвет (подумайте о том, как многие приложения Google имеют светлый фон, а значки там отображаются сероватым цветом).
Я бы посоветовал вам использовать это, если вы придаете цвет своей строке состояния через пункт №2.В самых последних устройствах SDK 29/+ поставляется с общесистемной светлой и темной темой, управляемой пользователем. Как разработчики, мы также должны переопределить наш файл стиля в новом
values-night
папка, чтобы дать пользователю два разных опыта.
Здесь я снова обнаружил, что пункт №2 эффективен в обеспечении "цвета фона для строки состояния". Но система не меняла цвет значков строки состояния для моего приложения. поскольку моя дневная версия стиля состояла из более легкой темы, это означает, что пользователи будут страдать от плохой видимости (белые значки на более светлом фоне).
Эту проблему можно решить, используя подход пункта 3 или переопределив файл стиля вvalues-29
папка и используя более новый API<item name="android:enforceStatusBarContrast">true</item>
. Это автоматически добавит сероватый оттенок к значкам, если цвет вашего фона слишком светлый.
Принятый ответ сработал для меня, используя CollapsingToolbarLayout. Важно отметить, что setSytstemUiVisibility()
отменяет любые предыдущие вызовы этой функции. Поэтому, если вы используете эту функцию где-то еще для того же представления, вам необходимо включить View.SYSTEM_UI_FLAG_LAYOUT_STABLE
а также View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
флаги, или они будут переопределены новым вызовом.
Это было так для меня, и как только я добавил два флага в другое место, я звонил setSystemUiVisibility()
, принятый ответ сработал отлично.
С Android Studio 1.4, шаблон проекта с наборами кодов Overlay
тема на вашем AppbarLayout и / или панели инструментов. Они также должны отображаться за строкой состояния fitSystemWindow
атрибут = истина. Это приведет к тому, что только панель инструментов будет отображаться непосредственно под строкой состояния, а все остальное будет отображаться под панелью инструментов. Таким образом, решения, представленные выше, не будут работать сами по себе. Вам нужно будет внести следующие изменения.
- Удалите тему " Наложение" или измените ее на не перекрывающую тему для панели инструментов.
Поместите следующий код в ваш файл styles-21.xml.
@android: Цвет / прозрачный
Назначьте эту тему для действия, содержащего блок навигации в файле AndroidManifest.xml.
Это сделает окно навигации визуализированным за прозрачной строкой состояния.
Все, что вам нужно сделать, это установить эти свойства в вашей теме
<item name="android:windowTranslucentStatus">true</item>
<item name="android:windowTranslucentNavigation">true</item>
Вот тема, которую я использую для достижения этой цели:
<style name="AppTheme" parent="@android:style/Theme.NoTitleBar">
<!-- Default Background Screen -->
<item name="android:background">@color/default_blue</item>
<item name="android:windowTranslucentStatus">true</item>
</style>
Правильное решение состоит в том, чтобы изменить свойство в XML под вашим тегом Activity на стиль ниже. Это просто работает
android:theme="@style/Theme.AppCompat.Light.NoActionBar"