697 votes

Comment créer une ImageView avec des coins arrondis?

Sur Android, un ImageView est un rectangle par défaut. Comment puis-je le rendre un rectangle arrondi (en coupant les 4 coins de mon Bitmap pour qu'ils soient des rectangles arrondis) dans l'ImageView?


Notez qu'à partir de 2021, utilisez simplement ShapeableImageView

0 votes

Cela pourrait être utile stackoverflow.com/questions/26850780/…

0 votes

Caché sous des réponses plus anciennes et plus compliquées se trouve ce que je pense devrait être maintenant la réponse acceptée : RoundedBitmapDrawable, ajoutée dans la révision 21 de la bibliothèque de support v4.

0 votes

Vous pouvez le faire de la manière la plus simple en utilisant simplement CardView avec une ImageView à l'intérieur - regardez l'exemple ici stackoverflow.com/a/41479670/4516797

578voto

George Walters II Points 3051

C'est assez tard pour répondre, mais pour quiconque d'autre cherche ceci, vous pouvez utiliser le code suivant pour arrondir manuellement les coins de vos images.

http://www.ruibm.com/?p=184

Ce n'est pas mon code, mais je l'ai utilisé et il fonctionne merveilleusement bien. Je l'ai utilisé comme un helper dans une classe ImageHelper et je l'ai étendu juste un peu pour passer la quantité de lissage dont j'ai besoin pour une image donnée.

Le code final ressemble à ceci:

package com.company.app.utils;

import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.Bitmap.Config;
import android.graphics.PorterDuff.Mode;

public class ImageHelper {
    public static Bitmap getRoundedCornerBitmap(Bitmap bitmap, int pixels) {
        Bitmap output = Bitmap.createBitmap(bitmap.getWidth(), bitmap
                .getHeight(), Config.ARGB_8888);
        Canvas canvas = new Canvas(output);

        final int color = 0xff424242;
        final Paint paint = new Paint();
        final Rect rect = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight());
        final RectF rectF = new RectF(rect);
        final float roundPx = pixels;

        paint.setAntiAlias(true);
        canvas.drawARGB(0, 0, 0, 0);
        paint.setColor(color);
        canvas.drawRoundRect(rectF, roundPx, roundPx, paint);

        paint.setXfermode(new PorterDuffXfermode(Mode.SRC_IN));
        canvas.drawBitmap(bitmap, rect, rect, paint);

        return output;
    }
}

0 votes

Est-ce que la couleur peut être transparente, George?

4 votes

Il ne fonctionne pas pour tous les appareils. Ai-je besoin de changer quelque chose quelque part?

15 votes

Il faut environ 0,03 seconde pour le faire pour une image de 200*200, donc je ne pense pas que ce soit la meilleure solution.

217voto

vinc3m1 Points 1664

Alors que la réponse ci-dessus fonctionne, Romain Guy (un développeur Android core) montre une meilleure méthode dans son blog qui utilise moins de mémoire en utilisant un shader ne créant pas une copie de l'image. L'idée générale de la fonctionnalité est la suivante :

Shader bitmapShader;
bitmapShader = new BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);

Paint paint = new Paint();
paint.setAntiAlias(true);
paint.setShader(bitmapShader);

RectF rect = new RectF(0.0f, 0.0f, width, height);

// rect contient les limites de la forme
// radius est le rayon en pixels des coins arrondis
// paint contient le shader qui texturera la forme
canvas.drawRoundRect(rect, radius, radius, paint);

Les avantages de cette méthode par rapport à d'autres sont qu'elle :

  • ne crée pas de copie séparée de l'image, ce qui consomme beaucoup de mémoire avec de grandes images [par rapport à la plupart des autres réponses ici]
  • prend en charge l'antialiasing [par rapport à la méthode clipPath]
  • prend en charge l'alpha [par rapport à la méthode xfermode+porterduff]
  • prend en charge l'accélération matérielle [par rapport à la méthode clipPath]
  • dessine uniquement une fois sur le canvas [par rapport aux méthodes xfermode et clippath]

J'ai créé un RoundedImageView basé sur ce code qui encapsule cette logique dans un ImageView et ajoute un support adéquat pour ScaleType ainsi qu'une bordure arrondie facultative.

0 votes

Dans votre fichier / exemple / res / layout / rounded_item.xml , pourquoi spécifiez-vous un src d'image alors que toutes vos sources sont codées en dur ? Belle démonstration, juste un peu exagérée.

0 votes

Votre échantillon a un grave problème de mémoire insuffisante, tout comme l'échantillon original de Romain Guy. Je ne sais toujours pas ce qui le cause, mais tout comme son code, il est très difficile de le trouver. Si vous ne pouvez pas voir de crash de l'application à cause de l'OOM, vous pouvez faire pivoter l'application plusieurs fois jusqu'à ce qu'il se produise (selon votre appareil, ROM, etc...) . J'en ai parlé dans le passé ici: stackoverflow.com/questions/14109187/…

0 votes

Également, cette solution (qui est écrite ici) ne fonctionne tout simplement pas si vous l'utilisez directement sur une image bitmap. vous devez créer un dessinable qui l'utilisera. cela ne change pas vraiment du tout l'image bitmap. testé sur android 4.1.

59voto

CaspNZ Points 4357

J'ai constaté que les deux méthodes étaient très utiles pour trouver une solution fonctionnelle. Voici ma version composite, qui est indépendante des pixels et vous permet d'avoir des coins carrés avec le reste des coins ayant le même rayon (ce qui est le cas d'utilisation habituel). Merci aux deux solutions ci-dessus :

public static Bitmap getRoundedCornerBitmap(Context context, Bitmap input, int pixels, int w, int h, boolean squareTL, boolean squareTR, boolean squareBL, boolean squareBR) {

    Bitmap output = Bitmap.createBitmap(w, h, Config.ARGB_8888);
    Canvas canvas = new Canvas(output);
    final float densityMultiplier = context.getResources().getDisplayMetrics().density;

    final int color = 0xff424242;
    final Paint paint = new Paint();
    final Rect rect = new Rect(0, 0, w, h);
    final RectF rectF = new RectF(rect);

    // vérifiez que notre coin arrondi est mis à l'échelle de manière appropriée
    final float roundPx = pixels * densityMultiplier;

    paint.setAntiAlias(true);
    canvas.drawARGB(0, 0, 0, 0);
    paint.setColor(color);
    canvas.drawRoundRect(rectF, roundPx, roundPx, paint);

    // dessiner des rectangles sur les coins que nous voulons être carrés
    if (squareTL) {
        canvas.drawRect(0, h / 2, w / 2, h, paint);
    }
    if (squareTR) {
        canvas.drawRect(w / 2, h / 2, w, h, paint);
    }
    if (squareBL) {
        canvas.drawRect(0, 0, w / 2, h / 2, paint);
    }
    if (squareBR) {
        canvas.drawRect(w / 2, 0, w, h / 2, paint);
    }

    paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
    canvas.drawBitmap(input, 0, 0, paint);

    return output;
}

De plus, j'ai redéfini ImageView pour y insérer cela afin de pouvoir le définir dans xml. Vous voudrez peut-être ajouter une partie de la logique que l'appel super fait ici, mais je l'ai commentée car elle n'est pas utile dans mon cas.

@Override
protected void onDraw(Canvas canvas) {
    //super.onDraw(canvas);
    Drawable drawable = getDrawable();

    Bitmap b = ((BitmapDrawable) drawable).getBitmap();
    Bitmap bitmap = b.copy(Bitmap.Config.ARGB_8888, true);

    int w = getWidth(), h = getHeight();

    Bitmap roundBitmap = CropImageView.getRoundedCornerBitmap(getContext(), bitmap, 10, w, h, true, false, true, false);
    canvas.drawBitmap(roundBitmap, 0, 0, null);
}

J'espère que cela vous aidera!

4 votes

Vraiment super, surtout en étendant l'ImageView

2 votes

Un moyen simple de garder la logique de ImageView#onDraw() est de définir l'image bitmap avec des coins arrondis comme drawable de l'ImageView, et de laisser le super.onDraw() dessiner l'image bitmap. J'ai créé une classe RoundedCornerImageView, et son exemple d'utilisation est ici. Veuillez noter que la méthode getRoundedCornerBitmap() que j'ai utilisée n'est pas indépendante des pixels.

0 votes

Merci pour le RoundedCornerImageView. Je l'ai utilisé mais je l'ai modifié pour être indépendant de la densité de pixels.

50voto

shailesh Points 368

Image arrondie Utilisant ImageLoader ici

Créez DisplayImageOptions:

DisplayImageOptions options = new DisplayImageOptions.Builder()
    // cela fera un cercle, passez la largeur de l'image 
    .displayer(new RoundedBitmapDisplayer(getResources().getDimensionPixelSize(R.dimen.image_dimen_menu))) 
    .cacheOnDisc(true)
    .build();

imageLoader.displayImage(url_for_image,ImageView,options);

Ou vous pouvez utiliser la bibliothèque Picasso de Square.

Picasso.with(mContext)
    .load(com.app.utility.Constants.BASE_URL+b.image)
    .placeholder(R.drawable.profile)
    .error(R.drawable.profile)
    .transform(new RoundedTransformation(50, 4))
    .resizeDimen(R.dimen.list_detail_image_size, R.dimen.list_detail_image_size)
    .centerCrop()
    .into(v.im_user);

vous pouvez télécharger le fichier RoundedTransformation ici ici

3 votes

La bibliothèque Picasso est bonne et très facile à implémenter, merci beaucoup +1

3 votes

La bibliothèque Picasso ne semble pas transformer les images "placeholder" et "error", donc si votre image ne se charge pas (erreur) ou prend du temps à se charger initialement (placeholder), elle n'affichera pas l'image comme une image arrondie. github.com/square/picasso/issues/337

0 votes

D'autres transformations utiles de Picasso sont fournies par cette bibliothèque, qui contient également une RoundedCornersTransformation : github.com/wasabeef/picasso-transformations

28voto

Christian Points 1231

Comme toutes les réponses semblaient trop compliquées pour moi juste pour les coins arrondis, j'ai réfléchi et je suis arrivé à une autre solution que je pense qui vaut la peine de partager, juste avec XML au cas où vous auriez de l'espace autour de l'image :

Créez une forme bordée avec un contenu transparent comme ceci :

Ensuite, dans un RelativeLayout, vous pouvez d'abord placer votre image, puis au même emplacement au-dessus de la forme avec une autre ImageView. La forme de couverture doit être plus grande en taille de la largeur de la bordure. Faites attention à prendre un rayon de coin plus grand car le rayon extérieur est défini mais le rayon intérieur est ce qui recouvre votre image.

J'espère que ça aidera quelqu'un d'autre aussi.

Éditer, comme demandé par CQM, voici l'exemple de RelativeLayout :

0 votes

Pouvez-vous élaborer davantage sur cela avec plus de code, en particulier sur ce qui est fait avec la deuxième vue de l'image et où le xml de la "forme bordée" est appliqué (en tant que src ou en tant que background?) plusieurs questions ici. Je veux aimer cette solution car elle me permettra de contrôler indépendamment les quatre coins.

1 votes

Bien que cela semble être une réponse simple, cela ajoute malheureusement une marge autour de la vue de l'image "masquée", ce qui est un effet secondaire indésirable.

0 votes

Oui, mais ça fonctionne de la même manière avec une ImageView basée sur un PNG-Drawable avec des coins arrondis et un arrière-plan transparent ou un 9-Patch-Drawable si vous avez un aspect non défini.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X