Come faccio a creare un ListView con angoli arrotondati in Android?


Risposte:


371

Ecco un modo per farlo (grazie alla documentazione Android!):

Aggiungi quanto segue in un file (ad esempio customshape.xml) e poi inseriscilo in (res / drawable / customshape.xml)

<?xml version="1.0" encoding="UTF-8"?> 
<shape xmlns:android="http://schemas.android.com/apk/res/android" 
     android:shape="rectangle"> 
     <gradient 
         android:startColor="#SomeGradientBeginColor"
         android:endColor="#SomeGradientEndColor" 
         android:angle="270"/> 

    <corners 
         android:bottomRightRadius="7dp" 
         android:bottomLeftRadius="7dp" 
         android:topLeftRadius="7dp" 
         android:topRightRadius="7dp"/> 
</shape> 

Una volta terminata la creazione di questo file, basta impostare lo sfondo in uno dei seguenti modi:

Tramite codice: listView.setBackgroundResource(R.drawable.customshape);

Tramite XML , basta aggiungere il seguente attributo al contenitore (es: LinearLayout o in tutti i campi):

android:background="@drawable/customshape"

Spero che qualcuno lo trovi utile ...


2
Grazie per l'ottimo consiglio. Cordiali saluti, il copia-incolla mi ha dato un'eccezione di runtime che diceva "XmlPullParserException: tag <gradient> della riga # 4 del file XML binario richiede che l'attributo 'angolo' sia un multiplo di 45" .. Facilmente risolto modificando l'angolo in 270.
allclaws

Grazie per la correzione ... Ma non so perché ciò potrebbe accadere .. Hai trovato qualche motivo specifico?
Legenda,

@teedyay: Anytime pal :)
Legenda

1
come tutti gli angeli, l'angolo dovrebbe essere multiplo di 45: "XmlPullParserException: il tag <gradient> della riga # 4 del file XML binario richiede che l'attributo 'angolo' sia multiplo di 45"
Youssef

29
Tuttavia, non funziona bene con l'evidenziazione della selezione: quando si seleziona l'elemento superiore o inferiore, lo sfondo colorato è rettangolare e disegnato sopra lo sfondo con angoli arrotondati.
Kris Van Bael,

56

Anche se ha funzionato, ha eliminato anche l'intero colore di sfondo. Stavo cercando un modo per fare solo il bordo e sostituire semplicemente quel codice di layout XML con questo ed ero a posto!

<shape xmlns:android="http://schemas.android.com/apk/res/android">
    <stroke android:width="4dp" android:color="#FF00FF00" />
    <padding android:left="7dp" android:top="7dp"
            android:right="7dp" android:bottom="7dp" />
    <corners android:radius="4dp" />
</shape> 

Dai

12

@ Kris-van-Bael

Per coloro che hanno problemi con l'evidenziazione della selezione per la riga superiore e inferiore in cui viene visualizzato il rettangolo di sfondo durante la selezione, è necessario impostare il selettore per la visualizzazione elenco su un colore trasparente.

listView.setSelector(R.color.transparent);

In color.xml basta aggiungere quanto segue -

<color name="transparent">#00000000</color>

5
non ha funzionato per me. Ho aggiunto la seguente riga, tuttavia, e me ne sono liberato:android:cacheColorHint="@android:color/transparent"
Cesare

1
Ciò ha sicuramente risolto il problema della selezione per me - grazie! Puoi anche usare android.R.color.transparent per il colore Selector invece di crearne uno tuo.
greg7gkb,

3
Invece di farlo a livello di codice, aggiungilo al tuo ListView nel layout XML per nascondere il colore della selezione: android: listSelector = "# 00000000"
Elad Nava

@alvins Esiste un modo per rendere selezionabile il layout per evidenziare come elemento della visualizzazione elenco?
Bharat Dodeja il

cosa devo fare se voglio usare un colore opaco per listSelector?
suitianshi,

3

Le altre risposte sono molto utili, grazie agli autori!

Ma non sono riuscito a vedere come personalizzare il rettangolo quando si evidenzia un elemento al momento della selezione piuttosto che disabilitare l'evidenziazione @alvins @bharat dojeha.

Quanto segue funziona per me creare un contenitore di elementi di visualizzazione elenco arrotondato senza contorno e un grigio più chiaro quando selezionato della stessa forma:

Il tuo xml deve contenere un selettore come ad es. (In res / drawable / customshape.xml):

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android" >
<item android:state_pressed="true" >
    <shape xmlns:android="http://schemas.android.com/apk/res/android" >
        <stroke android:width="8dp" android:color="@android:color/transparent" />
        <padding android:left="14dp" android:top="14dp"
                android:right="14dp" android:bottom="14dp" />
        <corners android:radius="10dp" />
        <gradient 
             android:startColor="@android:color/background_light"
             android:endColor="@android:color/transparent" 
             android:angle="225"/> 
    </shape>
</item>
<item android:state_pressed="false">
    <shape xmlns:android="http://schemas.android.com/apk/res/android" >
        <stroke android:width="8dp" android:color="@android:color/transparent" />
        <padding android:left="14dp" android:top="14dp"
                android:right="14dp" android:bottom="14dp" />
        <corners android:radius="10dp" />
        <gradient 
             android:startColor="@android:color/darker_gray"
             android:endColor="@android:color/transparent" 
             android:angle="225"/> 
    </shape>        
</item>

Quindi è necessario implementare un adattatore elenco e sovrascrivere il metodo getView per impostare il selettore personalizzato come sfondo

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        //snip
        convertView.setBackgroundResource(R.drawable.customshape);
        //snip
    }

e ho anche bisogno di 'nascondere' il rettangolo di selezione predefinito, ad esempio in onCreate (nascondo anche la mia sottile linea di divisione grigia tra gli elementi):

listView.setSelector(android.R.color.transparent);
listview.setDivider(null);

Questo approccio risolve una soluzione generale per i disegni, non solo ListViewItem con vari stati di selezione.



2

Un'altra soluzione alla selezione evidenzia problemi con il primo e l'ultimo elemento dell'elenco:

Aggiungi un'imbottitura all'inizio e alla fine dello sfondo dell'elenco uguale o maggiore del raggio. Ciò garantisce che l'evidenziazione della selezione non si sovrapponga alle curve degli angoli.

Questa è la soluzione più semplice quando è necessario evidenziare una selezione non trasparente.

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" >
    <solid android:color="@color/listbg" />
    <stroke
        android:width="2dip"
        android:color="#D5D5D5" />
    <corners android:radius="10dip" />

    <!-- Make sure bottom and top padding match corner radius -->
    <padding
        android:bottom="10dip"
        android:left="2dip"
        android:right="2dip"
        android:top="10dip" />
</shape>


1

Questo è stato incredibilmente utile per me. Vorrei suggerire un'altra soluzione alternativa per evidenziare perfettamente gli angoli arrotondati se si utilizza il proprio CustomAdapter.

Definizione di file XML

Prima di tutto, vai nella tua cartella disegnabile e crea 4 forme diverse:

  • shape_top

    <gradient
        android:startColor="#ffffff"
        android:endColor="#ffffff"
        android:angle="270"/>
    <corners
        android:topLeftRadius="10dp"
        android:topRightRadius="10dp"/>

  • shape_normal

    <gradient
        android:startColor="#ffffff"
        android:endColor="#ffffff"
        android:angle="270"/>
    <corners
        android:topLeftRadius="10dp"
        android:topRightRadius="10dp"/>

  • shape_bottom

    <gradient
        android:startColor="#ffffff"
        android:endColor="#ffffff"
        android:angle="270"/>
    <corners
        android:bottomRightRadius="10dp"
        android:bottomRightRadius="10dp"/>

  • shape_rounded

    <gradient
        android:startColor="#ffffff"
        android:endColor="#ffffff"
        android:angle="270"/>
    <corners
        android:topLeftRadius="10dp"
        android:topRightRadius="10dp"
        android:bottomRightRadius="10dp"
        android:bottomRightRadius="10dp"/>

Ora, crea un layout di riga diverso per ogni forma, ovvero per shape_top:

  • Puoi anche farlo programmaticamente cambiando lo sfondo.

    <TextView
        android:id="@+id/textView1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:layout_marginLeft="20dp"
        android:layout_marginRight="10dp"
        android:fontFamily="sans-serif-light"
        android:text="TextView"
        android:textSize="22dp" />
    
    <TextView
        android:id="@+id/txtValue1"
        android:layout_width="match_parent"
        android:layout_height="48dp"
        android:textSize="22dp"
        android:layout_gravity="right|center"
        android:gravity="center|right"
        android:layout_marginLeft="20dp"
        android:layout_marginRight="35dp"
        android:text="Fix"
        android:scaleType="fitEnd" />

E definire un selettore per ogni elenco sagomato, ovvero per shape_top:

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

    <item android:state_selected="true"
        android:drawable="@drawable/shape_top" />
    <item android:state_activated="true"
        android:drawable="@drawable/shape_top" />

    <!-- Default Item -->
    <item android:state_selected="false"
        android:drawable="@android:color/transparent" />
</selector>

Cambia il tuo CustomAdapter

Infine, definisci le opzioni di layout all'interno di CustomAdapter:

if(position==0)
{
 convertView = mInflater.inflate(R.layout.list_layout_top, null);
}
else
{
 convertView = mInflater.inflate(R.layout.list_layout_normal, null);
}

if(position==getCount()-1)
{
convertView = mInflater.inflate(R.layout.list_layout_bottom, null);
}

if(getCount()==1)
{
convertView = mInflater.inflate(R.layout.list_layout_unique, null);
}

E questo è fatto!


1

per creare il bordo devi creare un altro file xml con proprietà di solido e angoli nella cartella disegnabile e chiamarlo in background


0

Sto usando una vista personalizzata che ho il layout sopra gli altri e che disegna solo i 4 piccoli angoli dello stesso colore dello sfondo. Funziona qualunque sia il contenuto della vista e non alloca molta memoria.

public class RoundedCornersView extends View {
    private float mRadius;
    private int mColor = Color.WHITE;
    private Paint mPaint;
    private Path mPath;

    public RoundedCornersView(Context context) {
        super(context);
        init();
    }

    public RoundedCornersView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();

        TypedArray a = context.getTheme().obtainStyledAttributes(
                attrs,
                R.styleable.RoundedCornersView,
                0, 0);

        try {
            setRadius(a.getDimension(R.styleable.RoundedCornersView_radius, 0));
            setColor(a.getColor(R.styleable.RoundedCornersView_cornersColor, Color.WHITE));
        } finally {
            a.recycle();
        }
    }

    private void init() {
        setColor(mColor);
        setRadius(mRadius);
    }

    private void setColor(int color) {
        mColor = color;
        mPaint = new Paint();
        mPaint.setColor(mColor);
        mPaint.setStyle(Paint.Style.FILL);
        mPaint.setAntiAlias(true);

        invalidate();
    }

    private void setRadius(float radius) {
        mRadius = radius;
        RectF r = new RectF(0, 0, 2 * mRadius, 2 * mRadius);
        mPath = new Path();
        mPath.moveTo(0,0);
        mPath.lineTo(0, mRadius);
        mPath.arcTo(r, 180, 90);
        mPath.lineTo(0,0);
        invalidate();
    }

    @Override
    protected void onDraw(Canvas canvas) {

        /*Paint paint = new Paint();
        paint.setColor(Color.RED);
        canvas.drawRect(0, 0, mRadius, mRadius, paint);*/

        int w = getWidth();
        int h = getHeight();
        canvas.drawPath(mPath, mPaint);
        canvas.save();
        canvas.translate(w, 0);
        canvas.rotate(90);
        canvas.drawPath(mPath, mPaint);
        canvas.restore();
        canvas.save();
        canvas.translate(w, h);
        canvas.rotate(180);
        canvas.drawPath(mPath, mPaint);
        canvas.restore();
        canvas.translate(0, h);
        canvas.rotate(270);
        canvas.drawPath(mPath, mPaint);
    }
}
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.