Льодяник: намалюйте статусBar з кольором, встановленим прозорим


142

Я встановив свій статусBar колір прозорим для Lollipop, лише наступним рядком у моїй темі:

<item name="android:statusBarColor">@android:color/transparent</item>

Тепер мені потрібно намалювати за нею, але я не можу отримати жодного виду малюнку позаду нього. Я знаю, як це зробити з windowTranslucentStatusвластивістю, але не хочу використовувати це властивість, оскільки тоді він буде ігнорувати колір статусу Bar, встановлений на прозорий.


2
Ви також можете скористатисяandroid:fitsSystemWindows="true"
Aznix

Відповіді:


385

Спосіб №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 від декількох місяців тому.

Спосіб №3:

Якщо вам доведеться ігнорувати стандартні системні вставки для деяких макетів, залишаючи їх працювати в інших, єдиний життєздатний спосіб зробити це - це робота з часто пов'язаним ScrimInsetsFrameLayoutкласом. Звичайно, деякі речі, зроблені в цьому класі, потрібні не для всіх сценаріїв. Наприклад, якщо ви не плануєте використовувати накладку синтетичної панелі стану, просто прокоментуйте все в init()методі і не переймайтеся додаванням нічого у файл attrs.xml. Я бачив, як цей підхід працює, але я думаю, що ви побачите, що він приносить деякі інші наслідки, які, можливо, потребують багато роботи.

Я також бачив, що ви проти переплетення кількох макетів. У разі обгортання одного макета всередині іншого, де обидва мають match_parentвисоту та ширину, наслідки для продуктивності надто тривіальні, щоб турбуватися. Незалежно від цього ви можете повністю уникнути цієї ситуації, змінивши клас, з якого він поширюється, FrameLayoutна будь-який інший тип класу Макет, який вам подобається. Це буде працювати чудово.


9
Велике спасибі, налаштування SYSTEM_UI_FLAG_LAYOUT_STABLEта SYSTEM_UI_FLAG_LAYOUT_FULLSCREENпрапори було рішенням, яке я шукав.
alxscms

3
Я шукав ваше перше рішення протягом місяця. Дякую!
NeoKree

1
Привіт. Ваш код працює чудово. Але коли я виходжу з фрагмента, як слід відкидати зміни?
TheOnlyAnil

3
Це не спрацьовує CollapsingToolbarLayoutі Toolbar: рядок стану залишається непрозорим і android:statusBarColorне дає ефекту
Костянтин Конопко

Дякую. Якщо ви хочете повернутися до неекранного екрану, прочитайте сторінку developer.sonymobile.com/knowledge-base/tutorials/… .
CoolMind

43

Це працювало для моєї справи


// 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: youtube.com/watch?v=_mGDMVRO3iE



@TheOnlyAnil визначте фіксовану висоту панелі інструментів :) "56dp" або близько того має виглядати добре
Майкл

4
Отримання такої висоти рядка стану є абсолютно непідтримуваним, недокументованим, і, безумовно, буде порушено в наступних версіях. Використовуйте замість fitsSystemWindows = "true".
Грег Енніс

1
Ну, я це роблю, тому що іноді просто потрібно.
Грег Енніс

2
Це дуже погана ідея, на думку Кріса Бейнса (інженера Google) у цій розмові: youtube.com/watch?v=_mGDMVRO3iE
Мартін Марконніні

1
@Michael FWIW, я це робив у минулому, і WindowInsets api (метод) зробити це "має бути простим і робити, без того, щоб ми про це думали", але це не так, це кульгавий марний API, який додає багато зайвих накладних витрат. Google завжди на 80% завершений, а останні 20% залишають розробникам ... які хакують весь шлях, поки вони не зроблять це. ¯_ (ツ) _ / ¯
Мартін Маркончіні

21

Спробуйте цю тему

<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"

4
налаштування android:fitsSystemWindows="false"- розрізання панелі інструментів навпіл.
Хаммад Насір

16

Замість

<item name="android:statusBarColor">@android:color/transparent</item>

Використовуйте наступне:

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

І обов’язково видаліть верхню підкладку (яка додана за замовчуванням) на макеті "MainActivity".

Зауважте, що це не робить панель стану повністю прозорою, і на вашій панелі стану все одно буде накладене "зів'яле чорне".


2
Під час використання <item name="android:windowTranslucentStatus">true</item>він робить андроїд покласти вицвілий чорний фон під рядок стану, який я не шукаю. Будь-який спосіб хоч не мати цього чорного зів’ялого фону?
alxscms

1
Я спробував багато речей, але не можу знайти спосіб видалити зів’ялий чорний фон. Тому я закінчую своє дослідження, кажучи, що це не можливо для Android (навіть не для ScrimLayout). Цей вид має сенс, оскільки він забезпечує правильну читабельність вашого рядка стану у будь-який час. Я оновлю свою відповідь вище.
Jeroen Mols

Я думаю, було б дуже дивно, коли б можна було ввести прозорий колір у рядок статусу, не маючи змоги намалювати його. Я розумію, чому ви кажете, що має сенс, що ви не можете видалити цей чорний зів’ялий фон, але, безумовно, не так вже й важко бути обережним, щоб вигляд піктограми рядка стану був видимим. Ось стаття андроїда поліції , що показує використання прозорої панелі стану androidpolice.com/2014/07/04 / ... . Я спробую зв’язатися з автором.
alxscms

1
Сподіваюся, ви зможете зв’язатися з ним. Мені теж дуже цікаво це зробити :)
Jeroen Mols

Чудово! Оновлено і мою відповідь.
Jeroen Mols

9

Рішення від Cody Toombs майже зробило для мене трюк. Я не впевнений, це стосується 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>

values-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); 

Я витратив багато часу на те, щоб це правильно, занадто багато часу насправді. Сподіваємось, ця відповідь допомагає кожному, хто намагається досягти того самого.


1
android:windowTranslucentStatusпотрібен API рівня 19 або вище, як можливо, ви використовуєте його у ваших значеннях / styles.xml , маючи android:minSdkVersion10?
mradzinski

7

@Cody Toombs відповідь призводить до проблеми, яка приводить макет за навігаційною панеллю. Тож, що я знайшов - це використання цього рішення, поданого @Kriti

ось фрагмент коду Котліна для того ж:

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"

вигляд кореня вашого макета.


3

У мене була така ж проблема, тому я створив 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);

}

2

Ви можете використовувати ScrimInsetFrameLayout

https://github.com/google/iosched/blob/master/android/src/main/java/com/google/samples/apps/iosched/ui/widget/ScrimInsetsFrameLayout.java

android: fitsSystemWindows = "true" слід встановити на макет scrim!


Я бачив цей клас, але що робити, якщо я хочу використовувати RelativeLayoutзамість FrameLayout?
alxscms

3
використовувати відносне розташування всередині кадру.
Муртаза Хуршид Хуссей

2
Вкладення макетів у макети, безумовно, не для мене рішення щодо продуктивності
alxscms

1
Ефективність програми залежить від багатьох речей, які можуть відрізнятися. якщо у вас немає виходу, спробуйте. Best of Luck
Муртаза Хуршід Хуссей

Я розумію, що ви маєте на увазі, але повинно бути інше рішення, якщо ні, може бути спосіб реалізувати на будь-якому макеті те, що було реалізовано в цій спеціальній макеті кадру. Але дякую будь-яким чином
alxscms

1

Подібно до деяких розміщених рішень, але в моєму випадку я зробив рядок стану прозорим і виправляв положення панелі дій з деяким негативним запасом

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"

1
getStatusBarHeight () не стандартний
Roel

Цей метод реалізований на рішенні від @ mike-milla ... public int getStatusBarHeight () {int результат = 0; int resourceId = getResources (). getIdentifier ("status_bar_height", "dimen", "android"); if (resourceId> 0) {result = getResources (). getDimensionPixelSize (resourceId); } повернути результат; }
jegumi

Дякую. Я зробив так: AppBarLayout.LayoutParams lp = (AppBarLayout.LayoutParams) панель інструментів.getLayoutParams (); lp.topMargin + = getStatusBarHeight ();
CoolMind

1

Є хороша бібліотека 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 та вище.

Сподіваюся, що хтось ще допомагає!


0

У Android Studio 1.4 проект шаблону з кодом пластини котла задає Overlayтему на AppbarLayout та / або Панелі інструментів. Вони також встановлюються для відображення за рядком стану за fitSystemWindowатрибутом = true. Це призведе до відображення лише панелі інструментів безпосередньо під рядком стану, а все інше відобразиться під панеллю інструментів. Таким чином, запропоновані вище рішення не працюватимуть самостійно. Вам доведеться внести такі зміни.

  • Видаліть тему накладання або змініть її на тему, що не накладається, на панелі інструментів.
  • Введіть у свій стиль наступний код -21.xml .

    @android: колір / прозорий

  • Призначте цю тему діяльності, що містить ящик навігації у файлі AndroidManifest.xml .

Це зробить ящик навігації для відображення за прозорим рядком стану.


0

Все, що вам потрібно зробити, це встановити ці властивості у вашій темі

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

1
Я впевнений, що це зробить ваш макет під кнопками навігаційного інтерфейсу (пристрої з екранною навігацією). Це зробило подання навігації знизу недоступним у нашому додатку, тому ми вилучили ці прапори після тестування на Nexus
EpicPandaForce

0

Прийнята відповідь працювала для мене за допомогою CollapsingToolbarLayout. Важливо зазначити, що це setSytstemUiVisibility()перекриває будь-які попередні дзвінки до цієї функції. Тож якщо ви використовуєте цю функцію десь ще для того ж виду, вам потрібно включити View.SYSTEM_UI_FLAG_LAYOUT_STABLEіView.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN прапори, інакше вони будуть переохоплені новим викликом.

Так було і для мене, і як тільки я додав два прапори до іншого місця, до якого я дзвонив setSystemUiVisibility(), прийнята відповідь спрацювала чудово.


0

Я додам тут ще трохи інформації. Останні розробки Android зробили досить простим обробку багатьох випадків у рядку стану. Далі мої спостереження зstyles.xml

  1. Колір фону : для SDK 21+, як згадується багато відповідей, <item name="android:windowTranslucentStatus">true</item> зробить рядок стану прозорим і відображатиметься перед інтерфейсом користувача. Ваша активність займе весь простір верху.
  2. Колір фону : знову ж таки для SDK 21+, <item name="android:statusBarColor">@color/your_color</item>він просто додасть колір вашій смузі стану, не впливаючи ні на що інше.

  3. Однак на пізніших пристроях (Android M / +) піктограми почали надходити в різних відтінках. ОС може надати піктограму для SDK 23 / + темніший відтінок сірого, якщо ви перезаписуєте styles.xmlфайл у values-23папці та додаєте <item name="android:windowLightStatusBar">true</item>.
    Таким чином, ви надасте користувачеві більш видимий рядок стану, якщо ваш рядок стану має світлий колір (подумайте, як багато програм Google мають світлий фон, але піктограми видно там сіруватим кольором).
    Я б запропонував вам скористатись цим, якщо ви додасте колір до рядка статусу через пункт №2

  4. На останніх пристроях SDK 29 / + поставляється із системною широкою світлою та темною темою, керованою користувачем. Як розробники, ми також повинні замінити наш стиль стилю в новій values-nightпапці, щоб дати користувачеві 2 різні враження.
    І тут я знову виявив, що пункт №2 є ефективним у наданні "кольору тла в рядку стану". Але система не змінювала колір значків рядка стану для мого додатка. оскільки моя денна версія стилю складалася з більш легкої теми, це означає, що користувачі будуть страждати від низької видимості (білі піктограми на світлому фоні).
    Цю проблему можна вирішити, використовуючи підхід точки №3 або пересунувши файл стилю в values-29папці та використовуючи новіший апі <item name="android:enforceStatusBarContrast">true</item>. Це автоматично набере сіруватий відтінок піктограм, якщо колір тла занадто світлий.


-1

Ось тема, яку я використовую для цього:

<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>

1
Є деякі дивні потоки. Навіть якщо рішення було правильним для вас та когось іншого, вони будуть звучати, замість переходу до іншої відповіді.
CoolMind

Все, що я прошу, - це пояснення. Я не думаю, що люди не мають змоги звертатись без пояснень.
Дроїд Кріс

Я теж так думаю.
CoolMind

Я поясню, що фоновий варіант не працює належним чином у цьому пакеті. Виправте, будь ласка, свою відповідь.
Морозов

Гммм ... у якій версії Android ви це робите? Я використовую цю конфігурацію в Android M.
Droid Chris

-3

Правильне рішення - змінити властивість у XML під тегом Activity на стиль нижче. Це просто працює

  android:theme="@style/Theme.AppCompat.Light.NoActionBar"
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.