¿Cómo debo dar imágenes de esquinas redondeadas en Android?

Me gustaría cambiar una imagen que cargué para tener esquinas redondeadas.

¿Algún consejo, tutorial, mejores prácticas que conoces?

Para un método más controlado dibuje un rectángulo redondeado y enmasírelo en su imagen usando el modo Xfer porter-duff de la pintura.

Primero configure la pintura Xfer y el bitmap redondeado:

Bitmap myCoolBitmap = ... ; // <-- Your bitmap you want rounded int w = myCoolBitmap.getWidth(), h = myCoolBitmap.getHeight(); // We have to make sure our rounded corners have an alpha channel in most cases Bitmap rounder = Bitmap.createBitmap(w,h,Bitmap.Config.ARGB_8888); Canvas canvas = new Canvas(rounder); // We're going to apply this paint eventually using a porter-duff xfer mode. // This will allow us to only overwrite certain pixels. RED is arbitrary. This // could be any color that was fully opaque (alpha = 255) Paint xferPaint = new Paint(Paint.ANTI_ALIAS_FLAG); xferPaint.setColor(Color.RED); // We're just reusing xferPaint to paint a normal looking rounded box, the 20.f // is the amount we're rounding by. canvas.drawRoundRect(new RectF(0,0,w,h), 20.0f, 20.0f, xferPaint); // Now we apply the 'magic sauce' to the paint xferPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN)); 

Ahora aplica este bitmap en la parte superior de tu imagen:

 Bitmap result = Bitmap.createBitmap(myCoolBitmap.getWidth(), myCoolBitmap.getHeight() ,Bitmap.Config.ARGB_8888); Canvas resultCanvas = new Canvas(result) resultCanvas.drawBitmap(myCoolBitmap, 0, 0, null); resultCanvas.drawBitmap(rounder, 0, 0, xferPaint); 

El bitmap con esquinas redondeadas ahora reside en el resultado.

¿Por qué no usar clipPath?

 protected void onDraw(Canvas canvas) { Path clipPath = new Path(); float radius = 10.0f; float padding = radius / 2; int w = this.getWidth(); int h = this.getHeight(); clipPath.addRoundRect(new RectF(padding, padding, w - padding, h - padding), radius, radius, Path.Direction.CW); canvas.clipPath(clipPath); super.onDraw(canvas); } 

El propio Romain Guy escribe sobre esto en su blog :

Para generar las imágenes redondeadas, simplemente escribí un Drawable personalizado que dibuja un rectángulo redondeado utilizando Canvas.drawRoundRect (). El truco consiste en utilizar una pintura con un BitmapShader para rellenar el rectángulo redondeado con una textura en lugar de un color simple. Así es como se ve el código:

 BitmapShader shader; shader = new BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP); Paint paint = new Paint(); paint.setAntiAlias(true); paint.setShader(shader); RectF rect = new RectF(0.0f, 0.0f, width, height); // rect contains the bounds of the shape // radius is the radius in pixels of the rounded corners // paint contains the shader that will texture the shape canvas.drawRoundRect(rect, radius, radius, paint); 

La aplicación de muestra va un poco más lejos y simula un efecto de viñeta combinando el BitmapShader con un RadialGradient.

Esta es una forma en que descubrí hacerlo con ImageView. Probé con otros métodos, incluidas las respuestas aquí y con preguntas similares, pero descubrí que no me funcionaron bien, ya que necesitaba las esquinas para aplicarlas a la vista de la imagen y no directamente al bitmap. Aplicar directamente al bitmap no funcionará si está escalando / recortando / panoramizando ese bitmap, ya que las esquinas también serán escaladas / recortadas / panoramizadas.

 public class RoundedCornersImageView extends ImageView { private final Paint restrePaint = new Paint(); private final Paint maskXferPaint = new Paint(); private final Paint canvasPaint = new Paint(); private final Rect bounds = new Rect(); private final RectF boundsf = new RectF(); public RoundedCornersImageView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); init(); } public RoundedCornersImageView(Context context, AttributeSet attrs) { super(context, attrs); init(); } public RoundedCornersImageView(Context context) { super(context); init(); } private void init() { canvasPaint.setAntiAlias(true); canvasPaint.setColor(Color.argb(255, 255, 255, 255)); restrePaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_ATOP)); maskXferPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.MULTIPLY)); } @Override protected void onDraw(Canvas canvas) { canvas.getClipBounds(bounds); boundsf.set(bounds); canvas.saveLayer(boundsf, restrePaint, Canvas.ALL_SAVE_FLAG); super.onDraw(canvas); canvas.saveLayer(boundsf, maskXferPaint, Canvas.ALL_SAVE_FLAG); canvas.drawARGB(0, 0, 0, 0); canvas.drawRoundRect(boundsf, 75, 75, canvasPaint); canvas.restre(); canvas.restre(); } } 

Aquí hay una alternativa que usa capas de hardware para el compuesto de capa final:

 public class RoundedCornersImageView extends ImageView { private final Paint restrePaint = new Paint(); private final Paint maskXferPaint = new Paint(); private final Paint canvasPaint = new Paint(); private final Rect bounds = new Rect(); private final RectF boundsf = new RectF(); public RoundedCornersImageView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); init(); } public RoundedCornersImageView(Context context, AttributeSet attrs) { super(context, attrs); init(); } public RoundedCornersImageView(Context context) { super(context); init(); } private void init() { canvasPaint.setAntiAlias(true); canvasPaint.setColor(Color.argb(255, 255, 255, 255)); restrePaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_ATOP)); maskXferPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.MULTIPLY)); setLayerType(View.LAYER_TYPE_HARDWARE, restrePaint); } @Override protected void onDraw(Canvas canvas) { canvas.getClipBounds(bounds); boundsf.set(bounds); super.onDraw(canvas); canvas.saveLayer(boundsf, maskXferPaint, Canvas.ALL_SAVE_FLAG); canvas.drawARGB(0, 0, 0, 0); canvas.drawRoundRect(boundsf, 75, 75, canvasPaint); canvas.restre(); } } 

Al principio no pude hacer que funcionara con este método porque mis esquinas se estaban volviendo negras; Luego me di cuenta de cuál era el problema después de leer esta pregunta: Android ¿cómo aplicar máscara en ImageView? . Resulta que modificar el alfa en el canvas es en realidad “rayarlo” directamente en la pantalla, y perforar un agujero en la ventana subyacente que es negra. Es por eso que se necesitan dos capas: una para aplicar la máscara y otra para aplicar la imagen compuesta a la pantalla.

¿Qué tal crear una imagen de NinePatchDrawable que tenga esquinas redondeadas y un cuerpo transparente? Superponga su imagen con una versión de tamaño apropiado de su NinePatchDrawable.

 package com.pkg; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import android.app.Activity; import android.graphics.Bitmap; import android.graphics.BitmapFactory; 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; import android.os.Bundle; import android.os.Environment; import android.widget.ImageView; public class RoundedImage extends Activity { /** Called when the activity is first created. */ ImageView imag; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); imag=(ImageView)findViewById(R.id.image); //ImageView img1=(ImageView)findViewById(R.id.imageView1); BitmapFactory.Options bitopt=new BitmapFactory.Options(); bitopt.inSampleSize=1; // String img=Environment.getExternalStorageDirectory().toString(); // String filepath =Environment.getExternalStorageDirectory().toString(); String filepath ="/mnt/sdcard/LOST.DIR"; File imagefile = new File(filepath + "/logo.jpg"); FileInputStream fis = null; try { fis = new FileInputStream(imagefile); } catch (FileNotFoundException e1) { // TODO Auto-generated catch block e1.printStackTrace(); } Bitmap bi = BitmapFactory.decodeStream(fis); if(bi!=null){ imag.setImageBitmap(getRoundedCornerBitmap(bi)); } } public static Bitmap getRoundedCornerBitmap(Bitmap bitmap) { 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 = 12; 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; } }