2009-11-10 11 views

Respuesta

41

Para un método más controlado, dibuja un rectángulo redondeado y enmascara en tu imagen usando el modo Xfer porter-duff de la pintura.

Primera configuración pintar la Reenviar y el mapa de bits redondeada:

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 aplique este mapa de bits sábana de su 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); 

memoria de imagen con esquinas redondeadas ahora reside en consecuencia.

+0

Guau, ¡muy bien! Mi única preocupación con este método es la velocidad: si aplicara esta técnica a nueve imágenes a la vez, ¿funcionaría la aplicación? – iamkoa

+1

Uso esta técnica en una situación de gráficos de alto rendimiento, y no he visto ningún problema con ella (¡incluso después del perfilado)! Solo asegúrese de guardar el xferPaint y el mapa de bits redondo como un campo en su clase, creando un mapa de bits es lento, pero dibujarlo es razonablemente rápido. – Ralphleon

+0

Sería genial si pudieras editar algunas explicaciones sobre los parámetros que estás usando en tu publicación. El código de muestra se ve bien, pero comprenderlo no es tan fácil si aún no has trabajado con estas clases. – Janusz

5

¿Qué hay de la creación de una imagen NinePatchDrawable que tiene esquinas redondeadas y tiene un cuerpo transparente. Superponga su imagen con una versión de tamaño apropiado de su NinePatchDrawable.

+1

Muy buena idea, pero ¿y si la imagen de mi esquinas redondeadas se coloca sobre un fondo degradado? ¿Esto todavía funcionaría? – iamkoa

+1

Estoy de acuerdo en que esta es la forma menos hack-ish para lograr esto. Simplemente puede poner la imagen y el marco de la imagen en FrameLayout (en este orden) y listo. – Matthias

+0

@iamkoa: asegúrese de que las partes en blanco de la imagen de las esquinas redondeadas sean transparentes. Si está usando un degradado en sus esquinas, use el canal alfa del píxel. (Uso Gimp y establezco un degradado para pasar de transparente a su color.) – idbrii

28

¿Por qué no utilizar clipPath? mismo

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); 
} 
+0

No he probado esto todavía, pero parece que esto lo hará. Gracias Jerry! – iamkoa

+2

Nota, después de probar esto he encontrado: 1 - primero recorta lienzo y luego dibuja mapa de bits 2 - no es más rápido que usar una máscara de mapa de bits y la superposición de modo xfer 3 - uno no puede anti-alias clipPath, mientras que uno puede anti-alias la pintura que dibuja una máscara para la superposición del modo xfer. – Lumis

+0

Esto funcionó muy bien para el caso que estaba buscando, aunque no dibujaba un mapa de bits con esquinas redondeadas, sino una vista completa. – Jes

4
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; 
    } 
} 
+0

este código lo ayuda a obtener una imagen redondeada. – Swati

+1

pero este código no ayuda a obtener esquinas redondeadas cuando las necesitamos transparentes. ¿Sabes cómo lograr eso? – Thiago

15

Romain tipo escribe acerca de esto en his blog:

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

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 ejemplo va un poco más allá y falsificaciones una viñeta efecto mediante la combinación de la BitmapShader con un radialGradient.

6

He aquí una manera que descubrí para hacerlo con un 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 mapa de bits. Aplicar directamente al mapa de bits no funcionará si está escalando/recortando/panoramizando ese mapa de bits, ya que las esquinas también serán escaladas/recortadas/panoramizadas.

public class RoundedCornersImageView extends ImageView { 
    private final Paint restorePaint = 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)); 
     restorePaint.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, restorePaint, 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.restore(); 
     canvas.restore(); 
    } 
} 

Aquí es una alternativa que utiliza capas de hardware para el material compuesto capa final:

public class RoundedCornersImageView extends ImageView { 
    private final Paint restorePaint = 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)); 
     restorePaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_ATOP)); 
     maskXferPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.MULTIPLY)); 

     setLayerType(View.LAYER_TYPE_HARDWARE, restorePaint); 
    } 

    @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.restore(); 
    } 
} 

Al principio no fue capaz de conseguir que funcione con este método porque mis esquinas estaban convirtiendo en negro; Luego me di cuenta de cuál era el problema después de leer esta pregunta: Android how to apply mask on ImageView?. Resulta que modificar el alfa en el lienzo 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.

+1

funciona como un encanto – Softlion