„Elewacja” Androida nie pokazuje cienia


273

Mam ListView i przy każdym elemencie listy chcę, aby wyświetlał cień pod nim. Korzystam z nowej funkcji elewacji Androida Lollipop, aby ustawić Z w widoku, który chcę rzucić cień, i już robię to skutecznie z ActionBar (technicznie pasek narzędzi w Lollipop). Korzystam z elewacji Lollipopa, ale z jakiegoś powodu nie pokazuje on cienia pod elementami listy. Oto jak układ każdego elementu listy jest skonfigurowany:

<?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"
    android:orientation="vertical"
    style="@style/block"
    android:gravity="center"
    android:layout_gravity="center"
    android:background="@color/lightgray"
    >

    <RelativeLayout
        android:layout_width="300dp"
        android:layout_height="300dp"
        android:layout_marginLeft="40dp"
        android:layout_marginRight="40dp"
        android:layout_marginTop="20dp"
        android:layout_marginBottom="20dp"
        android:elevation="30dp"
        >

        <ImageView
            android:id="@+id/documentImageView"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:scaleType="centerCrop" />

        <LinearLayout
            android:orientation="vertical"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background="@color/alphared"
            android:layout_alignParentBottom="true" >

            <appuccino.simplyscan.Extra.CustomTextView
                android:id="@+id/documentName"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:textColor="@color/white"
                app:typeface="light"
                android:paddingLeft="16dp"
                android:paddingTop="8dp"
                android:paddingBottom="4dp"
                android:singleLine="true"
                android:text="New Document"
                android:textSize="27sp"/>

            <appuccino.simplyscan.Extra.CustomTextView
                android:id="@+id/documentPageCount"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:textColor="@color/white"
                app:typeface="italic"
                android:paddingLeft="16dp"
                android:layout_marginBottom="16dp"
                android:text="1 page"
                android:textSize="20sp"/>

        </LinearLayout>

    </RelativeLayout>

</RelativeLayout>

Oto, jak pokazuje element listy bez cienia: wprowadź opis zdjęcia tutaj

Próbowałem również następujące bezskutecznie:

  1. Ustaw elewację do ImageView i TextViews zamiast układu macierzystego.
  2. Zastosował tło do ImageView.
  3. Używane TranslationZ zamiast elewacji.

Wypróbowałem Twój układ (bez niestandardowych widoków) i pokazałem cień w moim telefonie, czy możesz udostępnić minimalny projekt, który odtwarza problem?
rnrneverdies

1
możliwy duplikat przycisku Android L FAB Shadow
naveejr

Odpowiedzi:


383

Przez jakiś czas bawiłem się cieniami na Lollipop i oto, co znalazłem:

  1. Wygląda na to, że ViewGroupgranice rodzica z jakiegoś powodu odcinają cień jego dzieci; i
  2. ustawione cienie android:elevationsą odcięte przez Viewgranice, a nie granice rozciągnięte przez margines;
  3. właściwym sposobem na uzyskanie widoku dziecka pokazującego cień jest ustawienie paddingu na rodzicu i ustawienie android:clipToPadding="false"na tym rodzicu.

Oto moja propozycja dla ciebie na podstawie tego, co wiem:

  1. Ustaw najwyższy poziom, RelativeLayoutaby wypełnienie było równe marginesom ustawionym dla względnego układu, który chcesz wyświetlać w cieniu;
  2. ustawione android:clipToPadding="false"na to samo RelativeLayout;
  3. Usuń margines z tego, RelativeLayoutktóry ma również ustawiony poziom;
  4. [EDYCJA] może być konieczne ustawienie nieprzezroczystego koloru tła w układzie potomnym, który wymaga rzędnej.

Na koniec Twój względny układ najwyższego poziomu powinien wyglądać następująco:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    style="@style/block"
    android:gravity="center"
    android:layout_gravity="center"
    android:background="@color/lightgray"
    android:paddingLeft="40dp"
    android:paddingRight="40dp"
    android:paddingTop="20dp"
    android:paddingBottom="20dp"
    android:clipToPadding="false"
    >

Wewnętrzny układ względny powinien wyglądać następująco:

<RelativeLayout
    android:layout_width="300dp"
    android:layout_height="300dp"
    android:background="[some non-transparent color]"
    android:elevation="30dp"
    >

8
Dzięki za to! Uznałem również, że android: clipChildren = "false" jest przydatny, gdy zostanie zastosowany do nadrzędnego układu względnego.
blaffie,

1
Cieszę się, że mogę pomóc @blaffie!
Justin Pollard,

214
To tak denerwujące, że Google produkuje taki tandetny kod. Będziemy musieli rozliczać się z tych błędów ramowych przez lata.
Miguel

8
Google mówi tylko (niestety): „ Cienie są rysowane przez element nadrzędny widoku z podwyższonym poziomem, a zatem podlegają standardowemu przycinaniu widoku, domyślnie przycinanemu przez element nadrzędny. ”.
Jan

5
W moim przypadku był to kolor przezroczysty. Ok, przezroczyste rzeczy nie rzucają cieni ... haha
Ferran Maylinch,

285

Jeśli masz widok bez tła, ta linia ci pomoże

android:outlineProvider="bounds"

Domyślnie cień jest określany na podstawie tła widoku, więc jeśli nie ma tła, nie będzie również cienia.


11
Co dziwne, Preview pokazało wysokość, ale prawdziwe urządzenie tego nie zrobiło. Dzięki, ten naprawił problem.
Ioane Sharvadze

Działa na poziomie API 21 i wyższym
Pantelis Ieronimakis 12.04.16

10
Ten rodzaj zadziałał dla mnie, ale dał przekątną ramkę po bokach, gdy zastosowano go do widoku tekstu. Ustawienie tła na kolor (taki sam jak kolor tła rodziców) działało lepiej.
Gober

4
Dotyczy to również sytuacji, w której tło jest niestandardowe i nie ma go <solid>.
David Lord,

Można tego użyć odwrotnie. Gdy chcesz uzyskać nieprzezroczyste tło z elewacją i nie chcesz cienia. Po prostu ustaw na none. Dzięki!
Odys

101

Najwyraźniej nie można po prostu ustawić wysokości w Widoku i sprawić, by się pojawiła. Musisz także określić tło.

Następujące linie dodane do mojego LinearLayout w końcu pokazały cień:

android:background="@android:color/white"
android:elevation="10dp"

To było nieoczekiwane. Ustawiłem ImageView z src i szukałem rozwiązania. Dziękuję Ci.
Andrew Grow

47

jeszcze jedna rzecz, o której powinieneś wiedzieć, cienie nie pokażą się, jeśli w manifeście masz tę linię:

android: hardwareAccelerated = "false"

Próbowałem wszystkich sugerowanych rzeczy, ale działało to tylko dla mnie, gdy usunąłem linię. Powodem, dla którego ją miałem, było to, że moja aplikacja działa z wieloma obrazami bitmapowymi i powodowały awarię aplikacji.


1
Nie rozwiązuje to problemu, jeśli potrzebujesz tej flagi.
Clive Jefferies

Dziękuję Ci!! Spędziłem dzień próbując podnieść AppBar i znalazłem problem, gdy sprawdziłem manifest dla tej flagi aktywności
ir2pid

1
Próbowałem wszystkich możliwych rozwiązań, ale nic z tego nie działało. To rozwiązanie działało. Dzięki. Potrzebuję również android:clipToPadding="false"tego rozwiązania.
Chirag Savsani

29

Jeśli masz widok bez tła, ta linia ci pomoże

android:outlineProvider="bounds"

Jeśli masz widok z tłem, ta linia ci pomoże

android:outlineProvider="paddedBounds"

6
To jedyne rozwiązanie, które działa dla mnie. Dziękuję
Oleh Liskovych

4
Działa to, o ile nie masz promienia na tle widoków, w którym to przypadku cień będzie pokazywany jako prostokątny, ale paddedBounds działa dla widoku z tłem.
Trevor Hart

android:outlineProvider="paddedBounds"ta linia działała dla mnie. Ustawiam Selector Drawable.
Chirag Savsani,

1
Gdy tego użyłem, cień jest rysowany całkowicie wewnątrz widoku, a nie na zewnątrz, czego nie chcę.
androidguy


12

Ugh, spędziłem godzinę próbując to rozgryźć. W moim przypadku miałem zestaw tła, jednak był on ustawiony w kolorze. To nie wystarczy, musisz ustawić tło widoku na rysowalne.

np. To nie będzie miało cienia:

<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="165dp"
    android:background="@color/ight_grey"
    android:elevation="20dp"
    android:orientation="vertical"
    />

ale to będzie

<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="165dp"
    android:background="@drawable/selector_grey"
    android:elevation="20dp"
    android:orientation="vertical"
    />

EDYCJA: Odkryłem również, że jeśli używasz selektora jako tła, jeśli nie masz ustawionego rogu, cień nie pojawi się w oknie podglądu, ale pojawi się na urządzeniu

np. To nie ma cienia w podglądzie:

<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item>
        <shape android:shape="rectangle">
            <solid android:color="@color/white" />
            <stroke
                android:width="1dp"
                android:color="@color/grey"/>
        </shape>
    </item>
</selector>

ale to:

<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item>
        <shape android:shape="rectangle">
            <solid android:color="@color/white" />
            <corners android:radius="1dp" />
            <stroke
                android:width="1dp"
                android:color="@color/grey"/>
        </shape>
    </item>
</selector>

1
Dokładnie przeciwnie do twojego pierwszego punktu było dla mnie prawdziwe w przypadku RecyclerView ... To niesamowite, że wciąż znajduję przypadki, w których muszę walczyć z tymi interfejsami API po 5 latach profesjonalnego rozwoju Androida :(
aProperFox

7

Dodanie koloru tła pomogło mi.

<CalendarView
    android:layout_width="match_parent"
    android:id="@+id/calendarView"
    android:layout_alignParentTop="true"
    android:layout_alignParentStart="true"
    android:layout_height="wrap_content"
    android:elevation="5dp"

    android:background="@color/windowBackground"

    />

4

Czasami jak background="@color/***"lub background="#ff33**"nie działa, zamieniam na background_colordrawable, a potem działa


4

Jeśli nadal nie pokazuje wysokości, spróbuj

    android:hardwareAccelerated="true" 

to na pewno ci pomoże.


Naprawiłem to dla mnie. Zakładałem, że PRAWDA jest ustawieniem domyślnym, ale najwyraźniej nie, przynajmniej w moim przypadku.
Matt Robertson

3

Jeśli chcesz mieć przezroczyste tło i android:outlineProvider="bounds"nie działa dla Ciebie, możesz utworzyć niestandardowy ViewOutlineProvider:

class TransparentOutlineProvider extends ViewOutlineProvider {

    @Override
    public void getOutline(View view, Outline outline) {
        ViewOutlineProvider.BACKGROUND.getOutline(view, outline);
        Drawable background = view.getBackground();
        float outlineAlpha = background == null ? 0f : background.getAlpha()/255f;
        outline.setAlpha(outlineAlpha);
    }
}

I ustaw tego dostawcę na przejrzysty widok:

transparentView.setOutlineProvider(new TransparentOutlineProvider());

Źródła: https://code.google.com/p/android/issues/detail?id=78248#c13

[EDYCJA] Dokumentacja Drawable.getAlpha () mówi, że jest specyficzna dla tego, w jaki sposób Drawable zagraża alfa. Możliwe, że zawsze zwróci 255. W takim przypadku możesz podać alfabet ręcznie:

class TransparentOutlineProvider extends ViewOutlineProvider {

    private float mAlpha;

    public TransparentOutlineProvider(float alpha) {
        mAlpha = alpha;
    }

    @Override
    public void getOutline(View view, Outline outline) {
        ViewOutlineProvider.BACKGROUND.getOutline(view, outline);
        outline.setAlpha(mAlpha);
    }
}

Jeśli tło widoku to StateListDrawable z domyślnym kolorem # DDFF0000, który ma alfa DDx0 / FFx0 == 0,86

transparentView.setOutlineProvider(new TransparentOutlineProvider(0.86f));

2

dodaj kolor tła układowi, który dla mnie działał:

    android:background="@color/catskill_white"
    android:layout_height="?attr/actionBarSize"
    android:elevation="@dimen/dimen_5dp"

1

Miałem trochę szczęścia z ustawieniem clipChildren="false"układu rodzica.


1

Spędziłem trochę czasu nad tym pracując i w końcu zdałem sobie sprawę, że gdy tło jest ciemne, cień nie jest widoczny


1

Dodając do zaakceptowanej odpowiedzi, istnieje jeszcze jeden powód, dla którego podniesienie może nie działać zgodnie z oczekiwaniami, jeśli funkcja filtru Bluelight w telefonie jest WŁĄCZONA.

Napotkałem ten problem, gdy w moim urządzeniu elewacja wydawała się całkowicie zniekształcona i nie do zniesienia. Ale w podglądzie wysokość była w porządku. Wyłączenie filtra Bluelight na telefonie rozwiązało problem.

Więc nawet po ustawieniu

android:outlineProvider="bounds"

Wysokość nie działa poprawnie, możesz więc majstrować przy ustawieniach kolorów telefonu.


0

Uważam, że twój problem wynika z faktu, że zastosowałeś element elewacji do układu względnego, który wypełnia jego element nadrzędny. Jego rodzic przycina wszystkie widoki potomne we własnym obszarze roboczym rysunku (i jest widokiem, który obsługuje cień dziecka). Możesz to naprawić, stosując właściwość elewacji do najwyższego RelativeLayoutw swoim widoku xml (znacznik root).


0

W moim przypadku problemem były czcionki.

1) Bez fontFamilymusiałem ustawić android:backgroundjakąś wartość.

<TextView
    android:layout_width="match_parent"
    android:layout_height="44dp"
    android:background="@android:color/white"
    android:elevation="3dp"
    android:gravity="center"
    android:text="@string/fr_etalons_your_tickets"
    android:textAllCaps="true"
    android:textColor="@color/blue_4" />

2) z fontFamilymusiałem dodać android:outlineProvider="bounds"ustawienie:

<TextView
    android:fontFamily="@font/gilroy_bold"
    android:layout_width="match_parent"
    android:layout_height="44dp"
    android:background="@android:color/white"
    android:elevation="3dp"
    android:gravity="center"
    android:outlineProvider="bounds"
    android:text="@string/fr_etalons_your_tickets"
    android:textAllCaps="true"
    android:textColor="@color/blue_4" />

0

W moim przypadku było to spowodowane niestandardowym komponentem nadrzędnym ustawiającym typ warstwy renderującej na „Oprogramowanie”:

setLayerType(View.LAYER_TYPE_SOFTWARE, null);

Usunięcie tej linii zrobiło lewę. Lub oczywiście musisz ocenić, dlaczego tak się dzieje. W moim przypadku chodziło o obsługę programu Honeycomb, który jest znacznie poniżej obecnego minimalnego zestawu SDK dla mojego projektu.


0

Sprawdź także, czy nie zmieniasz alfa w tym widoku. Badam problem, gdy zmieniam alfa w niektórych widokach z elewacją. Po prostu tracą wysokość, gdy zmienia się alfa i wraca do 1f.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.