Aggiungi ombra alla forma personalizzata su Android


130

È possibile aggiungere un'ombra esterna a una forma personalizzata in Android? Dopo aver consultato la documentazione, vedo solo un modo per applicare un'ombra di testo.

Ci ho provato senza fortuna:

<?xml version="1.0" encoding="UTF-8"?> 
   <shape xmlns:android="http://schemas.android.com/apk/res/android" 
   android:shape="rectangle"> 
     <solid android:color="#90ffffff"/>
       <corners android:radius="12dp" />
     <item name="android:shadowColor">#000000</item> 
     <item name="android:shadowRadius">5</item> 
     <item name="android:shadowDy">3</item> 
   </shape>

Risposte:


165

Dopo molte ricerche finalmente ho capito

inserisci qui la descrizione dell'immagine

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">

<!-- Bottom 2dp Shadow -->
<item>
    <shape  android:shape="rectangle">

        <solid android:color="#d8d8d8" />
        <corners android:radius="7dp" />

    </shape>
</item>

<!-- White Top color -->
<item android:bottom="3px">

    <shape  android:shape="rectangle">

    <solid android:color="#FFFFFF" />
    <corners android:radius="7dp" />


    </shape>

</item>


</layer-list>

5
dove hai configurato <!-- Bottom 2dp Shadow -->non ne vedo nessuno 2nel tuo codice ... ???
Choletski,

74

Ecco come lo faccio:

Pulsante nativo Android con ombre

Codice sotto per un pulsante STATO:

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
    <!-- "background shadow" -->
    <item>
        <shape android:shape="rectangle" >
            <solid android:color="#000000" />

            <corners android:radius="15dp" />
        </shape>
    </item>
    <!-- background color -->
    <item
        android:bottom="3px"
        android:left="3px"
        android:right="3px"
        android:top="3px">
        <shape android:shape="rectangle" >
            <solid android:color="#cc2b2b" />


            <corners android:radius="8dp" />
        </shape>
    </item>
    <!-- over left shadow -->
    <item>
        <shape android:shape="rectangle" >
            <gradient
                android:angle="180"
                android:centerColor="#00FF0000"
                android:centerX="0.9"
                android:endColor="#99000000"
                android:startColor="#00FF0000" />

            <corners android:radius="8dp" />
        </shape>
    </item>
    <!-- over right shadow -->
    <item>
        <shape android:shape="rectangle" >
            <gradient
                android:angle="360"
                android:centerColor="#00FF0000"
                android:centerX="0.9"
                android:endColor="#99000000"
                android:startColor="#00FF0000" />

            <corners android:radius="8dp" />
        </shape>
    </item>
    <!-- over top shadow -->
    <item>
        <shape android:shape="rectangle" >
            <gradient
                android:angle="-90"
                android:centerColor="#00FF0000"
                android:centerY="0.9"
                android:endColor="#00FF0000"
                android:startColor="#99000000"
                android:type="linear" />

            <corners android:radius="8dp" />
        </shape>
    </item>
    <!-- over bottom shadow -->
    <item>
        <shape android:shape="rectangle" >
            <gradient
                android:angle="90"
                android:centerColor="#00FF0000"
                android:centerY="0.9"
                android:endColor="#00FF0000"
                android:startColor="#99000000"
                android:type="linear" />

            <corners android:radius="8dp" />
        </shape>
    </item>
</layer-list>

Quindi dovresti avere un selettore con diverse versioni del pulsante, qualcosa del tipo:

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">

    <item android:drawable="@drawable/ic_button_red_pressed" android:state_pressed="true"/> <!-- pressed -->
    <item android:drawable="@drawable/ic_button_red_selected" android:state_focused="true"/> <!-- focused -->
    <item android:drawable="@drawable/ic_button_red_selected" android:state_selected="true"/> <!-- selected -->
    <item android:drawable="@drawable/ic_button_red_default"/> <!-- default -->

</selector>

spero che questo ti possa aiutare ... buona fortuna


47

Questa è la mia versione di un'ombra discendente. Stavo cercando un'ombra nebulosa intorno alla forma e ho usato questa risposta di Joakim Lundborg come punto di partenza. Ciò che ho modificato è quello di aggiungere angoli a tutti gli oggetti ombra e di aumentare il raggio dell'angolo per ciascun oggetto ombra successivo. Quindi ecco il xml:

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
    <!-- Drop Shadow Stack -->
    <item>
        <shape>
            <padding android:top="1dp" android:right="1dp" android:bottom="1dp" android:left="1dp" />
            <solid android:color="#02000000" />
            <corners android:radius="8dp" />
        </shape>
    </item>
    <item>
        <shape>
            <padding android:top="1dp" android:right="1dp" android:bottom="1dp" android:left="1dp" />
            <solid android:color="#05000000" />
            <corners android:radius="7dp" />
        </shape>
    </item>
    <item>
        <shape>
            <padding android:top="1dp" android:right="1dp" android:bottom="1dp" android:left="1dp" />
            <solid android:color="#10000000" />
            <corners android:radius="6dp" />
        </shape>
    </item>
    <item>
        <shape>
            <padding android:top="1dp" android:right="1dp" android:bottom="1dp" android:left="1dp" />
            <solid android:color="#15000000" />
            <corners android:radius="5dp" />
        </shape>
    </item>
    <item>
        <shape>
            <padding android:top="1dp" android:right="1dp" android:bottom="1dp" android:left="1dp" />
            <solid android:color="#20000000" />
            <corners android:radius="4dp" />
        </shape>
    </item>
    <item>
        <shape>
            <padding android:top="1dp" android:right="1dp" android:bottom="1dp" android:left="1dp" />
            <solid android:color="#25000000" />
            <corners android:radius="3dp" />
        </shape>
    </item>
    <item>
        <shape>
            <padding android:top="1dp" android:right="1dp" android:bottom="1dp" android:left="1dp" />
            <solid android:color="#30000000" />
            <corners android:radius="3dp" />
        </shape>
    </item>

    <!-- Background -->
    <item>
    <shape>
            <solid android:color="#0099CC" />
        <corners android:radius="3dp" />
    </shape>
   </item>
</layer-list>

Funziona bene .. Grazie (y)
Faldu Jaldeep il

31

Per me ha funzionato: basta salvare come custom_shape.xml.

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >

    <!-- "shadow" -->
    <item>
        <shape android:shape="rectangle" >
           <solid android:color="#000000"/>
           <corners android:radius="12dp" />
        </shape>
    </item>


    <item android:bottom="3px">
        <shape android:shape="rectangle"> 
            <solid android:color="#90ffffff"/>
            <corners android:radius="12dp" />
         </shape>
    </item>

</layer-list>

28

Penso che questo metodo produca risultati molto buoni:

<!-- Drop Shadow Stack -->
<item>
    <shape>
        <padding
                android:top="1dp"
                android:right="1dp"
                android:bottom="1dp"
                android:left="1dp"/>
        <solid android:color="#00CCCCCC"/>
    </shape>
</item>
<item>
    <shape>
        <padding
                android:top="1dp"
                android:right="1dp"
                android:bottom="1dp"
                android:left="1dp"/>
        <solid android:color="#10CCCCCC"/>
    </shape>
</item>
<item>
    <shape>
        <padding
                android:top="1dp"
                android:right="1dp"
                android:bottom="1dp"
                android:left="1dp"/>
        <solid android:color="#20CCCCCC"/>
    </shape>
</item>
<item>
    <shape>
        <padding
                android:top="1dp"
                android:right="1dp"
                android:bottom="1dp"
                android:left="1dp"/>
        <solid android:color="#30CCCCCC"/>
    </shape>
</item>
<item>
    <shape>
        <padding
                android:top="1dp"
                android:right="1dp"
                android:bottom="1dp"
                android:left="1dp"/>
        <solid android:color="#50CCCCCC"/>
    </shape>
</item>

<item>

    <shape android:shape="rectangle">
        <stroke android:color="#CCC" android:width="1dp"/>
        <solid android:color="#FFF" />
        <corners android:radius="2dp" />

    </shape>

</item>

8

Vecchia domanda, ma Elevation, disponibile con Material Design ora fornisce un'ombra a qualsiasi vista.

<TextView
android:id="@+id/myview"
...
android:elevation="2dp"
android:background="@drawable/myrect" />

Consulta i documenti su https://developer.android.com/training/material/shadows-clipping.html


Che cosa succede se hai diversi widget dell'interfaccia utente che dovrebbero apparire fusi con un'ombra attorno alla forma più esterna? Ho provato ad aggiungere l'elevazione a quello esterno, ma quello interno è stato nascosto dietro quello esterno. Quindi ho provato ad aggiungere l'elevazione ad entrambi ma poi sembrava che quello interno avesse un'ombra sopra quello esterno come una piramide Inca.
Michael Osofsky,

Ho finito per occuparmi della fusione usando un singolo ImageButtoninvece di un ImageViewpiù Button' because it allows a ImageButton` sia per un android:backgroundche per un android:src. Pertanto sono stato in grado di specificare android:elevationsolo una volta ed evitando "l'effetto piramide inca" che ho descritto nel mio ultimo commento.
Michael Osofsky,

8

Vorrei suggerire un piccolo miglioramento alla soluzione di Bruce che è quella di evitare di sovrapporre la stessa forma l'una sopra l'altra e di usare semplicemente il tratto anziché il solido. Sarebbe così:

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
    <!-- Drop Shadow Stack -->
    <item>
        <shape>
            <padding android:top="1dp" android:right="1dp" android:bottom="1dp" android:left="1dp" />
            <stroke android:color="#02000000" android:width="1dp"  />
            <corners android:radius="8dp" />
        </shape>
    </item>
    <item>
        <shape>
            <padding android:top="1dp" android:right="1dp" android:bottom="1dp" android:left="1dp" />
            <stroke android:color="#05000000" android:width="1dp" />
            <corners android:radius="7dp" />
        </shape>
    </item>
    <item>
        <shape>
            <padding android:top="1dp" android:right="1dp" android:bottom="1dp" android:left="1dp" />
            <stroke android:color="#10000000" android:width="1dp" />
            <corners android:radius="6dp" />
        </shape>
    </item>
    <item>
        <shape>
            <padding android:top="1dp" android:right="1dp" android:bottom="1dp" android:left="1dp" />
            <stroke android:color="#15000000" android:width="1dp" />
            <corners android:radius="5dp" />
        </shape>
    </item>
    <item>
        <shape>
            <padding android:top="1dp" android:right="1dp" android:bottom="1dp" android:left="1dp" />
            <stroke android:color="#20000000" android:width="1dp" />
            <corners android:radius="4dp" />
        </shape>
    </item>
    <item>
        <shape>
            <padding android:top="1dp" android:right="1dp" android:bottom="1dp" android:left="1dp" />
            <stroke android:color="#25000000" android:width="1dp" />
            <corners android:radius="3dp" />
        </shape>
    </item>
    <item>
        <shape>
            <padding android:top="1dp" android:right="1dp" android:bottom="1dp" android:left="1dp" />
            <stroke android:color="#30000000" android:width="1dp" />
            <corners android:radius="3dp" />
        </shape>
    </item>

    <!-- Background -->
    <item>
        <shape>
            <solid android:color="#FFF" />
            <corners android:radius="3dp" />
        </shape>
    </item>
</layer-list>

screenshot del rendering dell'ombra Infine, ho voluto sottolineare per le persone che vorrebbero un'ombra in una direzione specifica che tutto ciò che devi fare è impostare la parte superiore, inferiore, sinistra o destra su 0 dpi (per una linea continua) o -1 dpi (per nulla)


7

Se non ti dispiace fare un disegno personalizzato con l'API Canvas, dai un'occhiata a questa risposta sulle ombre discendenti . Ecco una domanda di follow-up a quella che risolve un problema nell'originale.


2

inserisci qui la descrizione dell'immagine

  <?xml version="1.0" encoding="utf-8"?>
    <shape xmlns:android="http://schemas.android.com/apk/res/android" >

        <solid android:color="@android:color/white" >
        </solid>

        <stroke
            android:width="1dp"
            android:color="@color/LightGrey" >
        </stroke>

        <padding
            android:bottom="5dp"
            android:left="2dp"
            android:right="2dp"
            android:top="5dp" >
        </padding>

        <corners
            android:bottomLeftRadius="20dp"
            android:bottomRightRadius="20dp"
            android:radius="12dp"
            android:topLeftRadius="20dp"
            android:topRightRadius="20dp" />

        <gradient
            android:angle="90"
            android:centerColor="@android:color/white"
            android:centerY="0.2"
            android:endColor="#99e0e0e0"
            android:startColor="@android:color/white"
            android:type="linear" />

    </shape>

1

Penso che questo valore dell'ombra esterna sia buono per la maggior parte dei casi:

<solid android:color="#20000000" />

1

Questa domanda potrebbe essere vecchia, ma per chiunque in futuro voglia un modo semplice per ottenere complessi effetti d'ombra controlla la mia biblioteca qui https://github.com/BluRe-CN/ComplexView

Usando la libreria, puoi cambiare i colori delle ombre, modificare i bordi e molto altro. Ecco un esempio per ottenere ciò che cerchi.

<com.blure.complexview.ComplexView
        android:layout_width="400dp"
        android:layout_height="600dp"
        app:radius="10dp"
        app:shadow="true"
        app:shadowSpread="2">

        <com.blure.complexview.ComplexView
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            app:color="#fdfcfc"
            app:radius="10dp" />
    </com.blure.complexview.ComplexView>

Per cambiare il colore dell'ombra, usa l'app: shadowColor = "il tuo codice colore".


1

9 patch per il salvataggio, una bella ombra potrebbe essere raggiunta facilmente soprattutto con questo fantastico strumento -

Generatore di ombre Android a 9 patch

PS: se il progetto non sarà in grado di compilare, dovrai spostare leggermente le linee nere nell'editor di studio Android


0

se hai bisogno di un'ombra a linea retta (come nella parte inferiore della barra degli strumenti) puoi anche usare il gradiente xml:

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
    <gradient
        android:type="linear"
        android:angle="-90"
        android:startColor="#19000000" <!-- black transparent -->
        android:endColor="#00000000" /> <!-- full transparent -->
</shape>

spero che questo aiuti qualcuno

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.