Lollipop: draw behind statusBar com sua cor definida como transparente

142

Eu configurei minha cor statusBar como transparente para o Lollipop apenas com a seguinte linha no meu tema:

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

Agora preciso desenhar atrás dele, mas não consigo ver nenhuma imagem atrás dele. Sei como fazê-lo com a windowTranslucentStatuspropriedade, mas não quero usar essa propriedade, pois ela ignorará a cor do statusBar definido como transparente.

alxscms
fonte
2
Você também pode usarandroid:fitsSystemWindows="true"
Aznix

Respostas:

385

Método 1:

Para obter uma barra de status completamente transparente, você deve usar o statusBarColorque está disponível apenas na API 21 e acima. windowTranslucentStatusestá disponível na API 19 e acima, mas adiciona um fundo colorido à barra de status. No entanto, a configuração windowTranslucentStatusalcança algo que a alteração statusBarColorpara transparente não: define os sinalizadores SYSTEM_UI_FLAG_LAYOUT_STABLE e SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN. A maneira mais fácil de obter o mesmo efeito é definir manualmente esses sinalizadores, o que desativa efetivamente as inserções impostas pelo sistema de layout do Android e deixa você se defender.

Você chama esta linha no seu onCreatemétodo:

getWindow().getDecorView().setSystemUiVisibility(
    View.SYSTEM_UI_FLAG_LAYOUT_STABLE
    | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);

Defina também a transparência em /res/values-v21/styles.xml:

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

Ou defina a transparência programaticamente:

getWindow().setStatusBarColor(Color.TRANSPARENT);

O lado bom dessa abordagem é que os mesmos layouts e designs também podem ser usados ​​na API 19, negociando a barra de status transparente para a barra de status translúcida colorida.

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

Método 2:

Se você só precisar pintar uma imagem de plano de fundo sob a barra de status, em vez de posicionar uma vista por trás dela, isso pode ser feito simplesmente configurando o plano de fundo do tema da sua atividade para a imagem desejada e definindo a transparência da barra de status, conforme mostrado no método # 1 Este foi o método que eu usei para criar as capturas de tela do artigo Polícia Android de alguns meses atrás.

Método # 3:

Se você precisar ignorar as inserções padrão do sistema para alguns layouts, mantendo-os trabalhando em outros, a única maneira viável de fazer isso é trabalhar com a ScrimInsetsFrameLayoutclasse frequentemente vinculada . Obviamente, algumas das coisas feitas nessa classe não são necessárias para todos os cenários. Por exemplo, se você não planeja usar a sobreposição da barra de status sintético, simplesmente comente tudoinit() método e não se preocupe em adicionar nada ao arquivo attrs.xml. Eu já vi essa abordagem funcionar, mas acho que você descobrirá que ela traz outras implicações que podem dar muito trabalho para contornar.

Também vi que você se opõe a agrupar vários layouts. No caso de agrupar um layout dentro de outro, onde ambos têm match_parentaltura e largura, as implicações de desempenho são muito triviais para se preocupar. Independentemente disso, você pode evitar completamente essa situação alterando a classe da qual ela se estende FrameLayoutpara qualquer outro tipo de classe de Layout que desejar. Funcionará muito bem.

Cody Toombs
fonte
9
Muito obrigado, definir as bandeiras SYSTEM_UI_FLAG_LAYOUT_STABLEe SYSTEM_UI_FLAG_LAYOUT_FULLSCREENfoi a solução que eu estava procurando.
Alxscms
3
Procurei sua primeira solução por um mês. Obrigado!
NeoKree
1
Oi. Seu código funciona perfeitamente bem. Mas quando saio do fragmento, como devo reverter as alterações?
TheOnlyAnil
3
Isso não funciona com CollapsingToolbarLayoute Toolbar: a barra de status não é totalmente translúcida e android:statusBarColornão tem efeito #
Konstantin Konopko 29/03
Obrigado. Se você quiser voltar a uma atividade que não seja de tela cheia, leia developer.sonymobile.com/knowledge-base/tutorials/… .
CoolMind 16/09/16
43

Isso funcionou para o meu caso


// 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;
}

Para obter mais informações sobre como trabalhar com statusBars: youtube.com/watch?v=_mGDMVRO3iE


Michael
fonte
@TheOnlyAnil definir uma altura barra fixa :) "56dp" ou então deve ser bom
Michael
4
Obter a altura da barra de status como essa é totalmente sem suporte, sem documentos e certamente será interrompido em versões futuras. Use fitsSystemWindows = "true".
Greg Ennis
1
Bem, eu estou fazendo isso também porque às vezes você só precisa.
Greg Ennis
2
Esta é uma idéia muito ruim, de acordo com Chris Banes (Google Engineer) nesta conversa: youtube.com/watch?v=_mGDMVRO3iE
Martin Marconcini
1
@ Michael FWIW, eu fiz isso no passado e a API do WindowInsets (método) para fazer isso “deve ser simples e feita sem que tenhamos que pensar nisso”, mas não é, é uma API inútil que adiciona um muita sobrecarga desnecessária. O Google está sempre 80% completo e deixa os últimos 20% para os desenvolvedores ... que cortam todo o caminho até que isso aconteça. _ (ツ) _ / ¯
Martin Marconcini
21

Experimente este tema

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

Certifique-se de que seu layout definido

android:fitsSystemWindows="false"
Filho Nguyen Thanh
fonte
4
A configuração android:fitsSystemWindows="false"está cortando a barra de ferramentas ao meio.
Hammad Nasir
16

Ao invés de

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

Use o seguinte:

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

E certifique-se de remover o preenchimento superior (que é adicionado por padrão) no layout 'MainActivity'.

Observe que isso não torna a barra de status totalmente transparente e ainda haverá uma sobreposição "preto desbotado" sobre a barra de status.

Jeroen Mols
fonte
2
Ao usar <item name="android:windowTranslucentStatus">true</item>, ele faz com que o Android coloque um fundo preto desbotado sob a barra de status, que não é o que estou procurando. Existe alguma maneira de não ter esse fundo preto desbotado?
Alxscms
1
Eu tentei muitas coisas, mas não consigo encontrar uma maneira de remover o fundo preto desbotado. Portanto, estou concluindo minha pesquisa dizendo que não é possível no Android (nem mesmo com o ScrimLayout). Isso faz sentido, porque garante a legibilidade adequada da sua barra de status o tempo todo. Vou atualizar minha resposta acima.
Jeroen Mols
Eu acho que seria muito estranho poder colocar uma cor transparente na barra de status, sem ser capaz de desenhar atrás dela. Entendo por que você diz que faz sentido não poder remover esse fundo preto desbotado, mas definitivamente não é tão difícil ser cuidadoso o suficiente para manter o ícone da barra de status visível. Aqui está um artigo da polícia do Android que mostra o uso de uma barra de status transparente androidpolice.com/2014/07/04/… . Vou tentar entrar em contato com o autor.
Alxscms
1
Espero que você possa entrar em contato com ele. Estou ficando muito interessado em fazer isso também :)
Jeroen Mols
Ótimo! Atualizei minha resposta também.
Jeroen Mols
9

A solução de Cody Toombs quase fez o truque para mim. Não tenho certeza se isso está relacionado ao Xamarin ou não, mas agora tenho uma solução aceitável:

Exemplo

Esta é a minha configuração:

Eu tenho um projeto Android em que referenciei os pacotes Android.Support v4 e v7. Eu tenho dois estilos definidos:

values ​​/ 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>

O AndroidManifest tem como alvo "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>

E, finalmente, o código na atividade principal:

[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);
    }
}

Observe que eu defino o sinalizador DrawsSystemBarBackgrounds, isso faz toda a diferença

Window.AddFlags (WindowManagerFlags.DrawsSystemBarBackgrounds); 

Passei muito tempo acertando, na verdade, muito tempo. Espero que esta resposta ajude qualquer um que tente alcançar a mesma coisa.

Gerhard Schreurs
fonte
1
android:windowTranslucentStatusrequer o nível 19 ou superior da API, como é possível usá-la em seus values ​​/ styles.xml enquanto possui um valor android:minSdkVersionde 10?
precisa saber é o seguinte
7

A resposta de @Cody Toombs leva a um problema que coloca o layout atrás da barra de navegação. Então, o que eu achei foi usar esta solução dada por @Kriti

Aqui está o trecho de código Kotlin para o mesmo:

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

Você também precisa adicionar

android:fitsSystemWindows="false"

visualização raiz do seu layout.

Kishan Solanki
fonte
3

Eu tive o mesmo problema, então eu crio o ImageView que se destaca por trás da barra de status API 19+

Definir imagem personalizada atrás da barra de status 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);

}
Sumit
fonte
2

Você pode usar ScrimInsetFrameLayout

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

android: fitsSystemWindows = "true" deve ser definido no layout scrim!

Murtaza Khursheed Hussain
fonte
Eu vi essa aula, mas e se eu quiser usar um em RelativeLayoutvez de um FrameLayout?
Alxscms
3
use o layout relativo dentro de um layout de quadro.
Murtaza Khursheed Hussain
2
Layouts de nidificação em layouts definitivamente não é uma solução para mim em relação ao desempenho
alxscms
1
o desempenho do aplicativo depende de muitas coisas que podem variar. se você não tem saída, tente. Best of Luck
Murtaza Khursheed Hussain
Entendi o que você quer dizer, mas deve haver outra solução, se não houver, pode haver uma maneira de implementar em qualquer layout o que foi implementado nesse layout de quadro personalizado. Mas, graças qualquer maneira
alxscms
1

Semelhante a algumas das soluções postadas, mas no meu caso, fiz a barra de status transparente e corrigi a posição da barra de ação com uma margem negativa

if (Build.VERSION.SDK_INT >= 21) {
    getWindow().setStatusBarColor(Color.TRANSPARENT);
    FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) toolbar.getLayoutParams();
    lp.setMargins(0, -getStatusBarHeight(), 0, 0);
}

E eu usei na barra de ferramentas e na visualização raiz

android:fitsSystemWindows="true"
jegumi
fonte
1
getStatusBarHeight () não é padrão
Roel
Este método é implementado na solução de @ mike-milla ... public int getStatusBarHeight () {int result = 0; int resourceId = getResources (). getIdentifier ("status_bar_height", "dimen", "android"); if (resourceId> 0) {result = getResources (). getDimensionPixelSize (resourceId); } retornar resultado; }
jegumi
Obrigado. Eu fiz isso: AppBarLayout.LayoutParams lp = (AppBarLayout.LayoutParams) toolbar.getLayoutParams (); lp.topMargin + = getStatusBarHeight ();
CoolMind 24/09/16
1

Existe uma boa biblioteca StatusBarUtil da @laobie que ajuda a desenhar facilmente a imagem na StatusBar.

Basta adicionar o seu build.gradle:

compile 'com.jaeger.statusbarutil:library:1.4.0'

Em seguida, no conjunto de atividades

StatusBarUtil.setTranslucentForImageView(Activity activity, int statusBarAlpha, View viewNeedOffset)

No layout

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

Para mais informações, baixe a demonstração ou clone na página do github e brinque com todos os recursos.

Nota: Suporte KitKat e acima.

Espero que ajude outra pessoa!

Gueorgui Obregon
fonte
0

Com o Android Studio 1.4, o projeto de modelo com código da placa da caldeira define o Overlaytema no AppbarLayout e / ou na Barra de Ferramentas. Eles também são configurados para serem renderizados atrás da barra de status por fitSystemWindowattribute = true. Isso fará com que apenas a barra de ferramentas seja renderizada diretamente abaixo da barra de status e tudo o resto será renderizado abaixo da barra de ferramentas. Portanto, as soluções fornecidas acima não funcionarão sozinhas. Você precisará fazer as seguintes alterações.

  • Remova o tema Sobreposição ou altere para Tema sem sobreposição da barra de ferramentas.
  • Coloque o seguinte código no seu arquivo styles-21.xml .

    @android: cor / transparente

  • Atribua esse tema à atividade que contém a gaveta de navegação no arquivo AndroidManifest.xml .

Isso fará com que a gaveta de navegação seja renderizada atrás da barra de status transparente.

Umer Farooq
fonte
0

Tudo que você precisa fazer é definir essas propriedades no seu tema

<item name="android:windowTranslucentStatus">true</item>
<item name="android:windowTranslucentNavigation">true</item>
Sudhir singh
fonte
1
Tenho certeza de que isso fará com que seu layout caia sob os botões de navegação da interface do usuário (dispositivos com navegação na tela). Isso fez vista inacessível navegação inferior em nosso aplicativo, de modo que abandonou esses sinalizadores depois de testar em um Nexus
EpicPandaForce
0

A resposta aceita funcionou para mim usando um CollapsingToolbarLayout. É importante observar, porém, que setSytstemUiVisibility()substitui todas as chamadas anteriores para essa função. Portanto, se você estiver usando essa função em outro lugar para a mesma exibição, precisará incluir os sinalizadores View.SYSTEM_UI_FLAG_LAYOUT_STABLEe View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN, ou eles serão substituídos pela nova chamada.

Esse foi o meu caso e, depois de adicionar as duas bandeiras ao outro lugar para o qual estava ligando setSystemUiVisibility(), a resposta aceita funcionou perfeitamente.

cpgreen2
fonte
0

Vou adicionar mais algumas informações aqui. Os desenvolvimentos mais recentes do Android tornaram muito fácil lidar com muitos casos na barra de status. A seguir, minhas observações dostyles.xml

  1. Cor do plano de fundo : para o SDK 21+, como muitas respostas mencionadas, <item name="android:windowTranslucentStatus">true</item> a barra de status ficará transparente e será exibida na frente da interface do usuário. Sua atividade ocupará todo o espaço da parte superior.
  2. Cor do plano de fundo : novamente, para o SDK 21+, <item name="android:statusBarColor">@color/your_color</item>basta dar uma cor à sua barra de status, sem afetar mais nada.

  3. No entanto, em dispositivos posteriores (Android M / +), os ícones começaram a aparecer em diferentes tons. O sistema operacional pode dar um tom de cinza mais escuro aos ícones do SDK 23 / +, se você substituir o styles.xmlarquivo na values-23pasta e adicioná-lo <item name="android:windowLightStatusBar">true</item>.
    Dessa forma, você fornecerá ao usuário uma barra de status mais visível, se a barra de status tiver uma cor clara (pense em como muitos aplicativos do Google têm fundo claro e os ícones ficam visíveis em uma cor acinzentada).
    Eu sugiro que você use isso, se você estiver dando cor à sua barra de status pelo ponto # 2

  4. Nos dispositivos mais recentes, o SDK 29 / + vem com um tema claro e escuro amplo do sistema, controlável pelo usuário. Como desenvolvedores, também devemos substituir nosso arquivo de estilo em uma nova values-nightpasta, para fornecer ao usuário 2 experiências diferentes.
    Aqui, novamente, eu achei o ponto 2 eficaz para fornecer a "cor de fundo à barra de status". Mas o sistema não estava alterando a cor dos ícones da barra de status para o meu aplicativo. desde que minha versão do dia do estilo consistia em um tema mais claro, isso significa que os usuários sofrerão com baixa visibilidade (ícones brancos sobre fundo mais claro)
    Esse problema pode ser resolvido usando a abordagem do ponto 3 ou substituindo o arquivo de estilo na values-29pasta e usando um novo api <item name="android:enforceStatusBarContrast">true</item>. Isso aplicará automaticamente a tonalidade acinzentada aos ícones, se a cor do fundo for muito clara.

ansh sachdeva
fonte
-1

Aqui está o tema que eu uso para fazer isso:

<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>
Droid Chris
fonte
1
Existem alguns downvoters estranhos. Mesmo que uma solução seja certa para você e para outras pessoas, eles votam negativamente em vez de passar para outra resposta.
CoolMind
Tudo o que estou pedindo é uma explicação. Eu não acho que as pessoas devam votar sem uma explicação.
Droid Chris
Eu também acho.
CoolMind
Vou explicar que a opção em segundo plano não funciona corretamente neste pacote. Corrija sua resposta, por favor.
Morozov
Hmmm ... em qual versão do Android você está fazendo isso? Eu estou usando esta configuração no M. Android
Droid Chris
-3

A solução correta é alterar uma propriedade em XML na sua tag Activity para o estilo abaixo. Simplesmente funciona

  android:theme="@style/Theme.AppCompat.Light.NoActionBar"
satya phani
fonte