Comment créer un ListView avec des coins arrondis sous Android?

176

Comment créer un ListView avec des coins arrondis sous Android?

Légende
la source
Cette question est vraiment utile, votre réponse l'est aussi .. !!
Sajad Karuthedath

Réponses:

371

Voici une façon de le faire (grâce à la documentation Android!):

Ajoutez ce qui suit dans un fichier (par exemple, customshape.xml), puis placez-le dans (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> 

Une fois que vous avez terminé de créer ce fichier, définissez simplement l'arrière-plan de l'une des manières suivantes:

Par code: listView.setBackgroundResource(R.drawable.customshape);

Via XML , ajoutez simplement l'attribut suivant au conteneur (ex: LinearLayout ou à n'importe quel champ):

android:background="@drawable/customshape"

J'espère que quelqu'un le trouvera utile ...

Légende
la source
2
Merci pour le bon conseil. Juste pour info, le copier-coller m'a donné une exception d'exécution disant: "XmlPullParserException: La balise <gradient> de la ligne de fichier XML binaire # 4 nécessite que l'attribut 'angle' soit un multiple de 45" .. Facilement corrigé en changeant l'angle en 270.
allclaws
Merci pour le correctif ... Mais je ne sais pas pourquoi cela pourrait arriver ... Avez-vous trouvé une raison spécifique?
Legend
@teedyay: Anytime pal :)
Legend
1
même que allclaws, l'angle doit être multiple de 45: "XmlPullParserException: La balise Binary XML file line # 4 <gradient> nécessite que l'attribut 'angle' soit un multiple de 45"
Youssef
29
Cela ne fonctionne pas bien avec la mise en surbrillance de la sélection: lorsque l'élément du haut ou du bas est sélectionné, son arrière-plan coloré est rectangulaire et dessiné au-dessus de l'arrière-plan aux coins arrondis.
Kris Van Bael le
56

Bien que cela ait fonctionné, cela a également supprimé toute la couleur d'arrière-plan. Je cherchais un moyen de faire juste la bordure et de remplacer simplement ce code de mise en page XML par celui-ci et j'étais prêt à partir!

<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> 
Kevin Parker
la source
Consultez également cette réponse
ThomasRS
12

@ kris-van-bael

Pour ceux qui rencontrent des problèmes avec la sélection, mettez en surbrillance la ligne du haut et du bas où le rectangle d'arrière-plan apparaît lors de la sélection, vous devez définir le sélecteur de votre vue de liste sur une couleur transparente.

listView.setSelector(R.color.transparent);

Dans color.xml, ajoutez simplement ce qui suit -

<color name="transparent">#00000000</color>
alvins
la source
5
cela n'a pas fonctionné pour moi. J'ai ajouté la ligne suivante, cependant, et elle s'en est débarrassée:android:cacheColorHint="@android:color/transparent"
cesar
1
Cela a définitivement résolu le problème de sélection pour moi - merci! Vous pouvez également utiliser android.R.color.transparent pour la couleur du sélecteur au lieu de créer la vôtre.
greg7gkb
3
Au lieu de le faire par programme, ajoutez ceci à votre ListView dans la mise en page XML pour masquer la couleur de sélection: android: listSelector = "# 00000000"
Elad Nava
@alvins Existe-t-il un moyen de rendre la mise en page sélectionnable pour la mise en évidence comme un élément de vue de liste?
Bharat Dodeja
que dois-je faire si je veux utiliser une couleur opaque pour listSelector?
suitianshi
3

Les autres réponses sont très utiles, merci aux auteurs!

Mais je ne voyais pas comment personnaliser le rectangle lors de la mise en évidence d'un élément lors de la sélection plutôt que de désactiver la mise en évidence @alvins @bharat dojeha.

Ce qui suit fonctionne pour moi pour créer un conteneur d'éléments de vue de liste arrondis sans contour et d'un gris plus clair lorsqu'il est sélectionné de la même forme:

Votre xml doit contenir un sélecteur tel que par exemple (dans 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>

Ensuite, vous devez implémenter un adaptateur de liste et remplacer la méthode getView pour définir le sélecteur personnalisé comme arrière-plan

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

et il faut également `` masquer '' le rectangle de sélection par défaut, par exemple dans onCreate (je cache également ma fine ligne de séparation grise entre les éléments):

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

Cette approche résout une solution générale pour les drawables, pas seulement ListViewItem avec différents états de sélection.

dr_g
la source
3

Mettre à jour

La solution de nos jours est d'utiliser un CardViewavec support pour les coins arrondis intégré.


Réponse originale *

Une autre façon que j'ai trouvée était de masquer votre mise en page en dessinant une image au-dessus de la mise en page. Cela pourrait vous aider. Découvrez les coins arrondis arrondis d'Android XML

Richard Le Mesurier
la source
2

Encore une autre solution à la sélection met en évidence les problèmes avec le premier et le dernier élément de la liste:

Ajoutez un remplissage en haut et en bas de l'arrière-plan de votre liste égal ou supérieur au rayon. Cela garantit que la mise en évidence de la sélection ne chevauche pas vos courbes d'angle.

C'est la solution la plus simple lorsque vous avez besoin d'une mise en surbrillance non transparente de la sélection.

<?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>
William Morrison
la source
1

Cela m'a été incroyablement utile. Je voudrais suggérer une autre solution de contournement pour mettre parfaitement en évidence les coins arrondis si vous utilisez le vôtreCustomAdapter .

Définition de fichiers XML

Tout d'abord, allez dans votre dossier dessinable et créez 4 formes différentes:

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

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

Maintenant, créez une disposition de ligne différente pour chaque forme, c'est-à-dire pour shape_top:

  • Vous pouvez également effectuer cette opération en modifiant l'arrière-plan par programme.

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

Et définissez un sélecteur pour chaque liste de formes, c'est-à-dire pour 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>

Changer votre CustomAdapter

Enfin, définissez les options de mise en page dans votre 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);
}

Et c'est fait!

Machado
la source
1

pour créer une bordure, vous devez créer un autre fichier xml avec la propriété de solide et de coins dans le dossier pouvant être dessiné et l'appeler en arrière-plan

Pawan Kumar
la source
0

J'utilise une vue personnalisée que je dispose au-dessus des autres et qui dessine simplement les 4 petits coins de la même couleur que l'arrière-plan. Cela fonctionne quel que soit le contenu de la vue et n'alloue pas beaucoup de mémoire.

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);
    }
}
mbonnin
la source