Generar Imágenes Redondas
En este nuevo post os queremos enseñar como generar de manera automática imágenes redondas al más puro estilo Google Plus, como os vamos a explicar a continuación veréis que es un proceso realmente sencillo. Manos a la obra!!!
El objetivo de este post es enseñaros como extender un ImageView de Android para que sea capaz de hacer la transformación que os mostramos a continuación:
![]() |
![]() |
| Imagen Original | Imagen Procesada |
Paso 1:
- Creamos una nueva clase en nuestro proyecto y la llamamos por ejemplo “RoundImageView.java“.
Paso 2:
- Extendemos esta clase de la clase “ImageView” de la API de Android, tal que así.
public class RoundImageView extends ImageView
Paso 3:
- Sobrescribimos el método “onDraw” de la clase para implementar aquí nuestra lógica.
@Override protected void onDraw(Canvas pCanvas)
Paso 4:
- Generamos un nuevo Bitmap, tomando como origen la imagen que hayamos configurado en el atributo “android:src” de la vista.
if (scaledBitmap == null) {
scaledBitmap = Bitmap.createScaledBitmap(((BitmapDrawable)getDrawable()).getBitmap(), size, size, true);
}
- Generamos un nuevo Bitmap en blanco sobre el que dibujaremos la imagen procesada y un Canvas asociado a este que usaremos después para dibujar sobre el Bitmap.
if (resultBitmap == null) {
resultBitmap = Bitmap.createBitmap(pCanvas.getWidth(), pCanvas.getHeight(), scaledBitmap.getConfig());
}
- Generamos un Path sobre el que dibujaremos el circulo de nuestra imagen y el que más tarde invertiremos, para ilustrar esto hemos generados la imágenes que os mostramos a continuación.
if (maskPath == null) {
maskPath = new Path();
maskPath.addCircle((size / 2), (size / 2), (size / 2), Direction.CCW);
maskPath.toggleInverseFillType();
maskPath.close();
}
![]() |
![]() |
| Path Original | Path Invertido |
- Dibujamos sobre el Bitmap en blanco la imagen original.
//Draw background image. maskedCanvas.drawBitmap(scaledBitmap, 0, 0, null);
- Eliminamos el contenido de los bordes de la imagen de la siguiente manera, no entraremos en explicar el porque, ya que la documentación de la API es muy extensa y siempre está disponible en la web de Android Dev.
//Draw transparent area masking the original bitmap. maskedCanvas.clipPath(maskPath); maskedCanvas.drawColor(Color.BLACK, PorterDuff.Mode.CLEAR);
- Dibujamos la imagen procesada sobre el objecto Canvas que nos llego como parámetro al método onDraw.
pCanvas.drawBitmap(resultBitmap, 0, 0, null);
Con esto ya tendréis lo necesario para que vuestras aplicaciones luzcan imágenes redondas, como nota a todo esto, decir que podemos hacer que las imágenes tomen cualquier otra forma únicamente variando el objeto Path. Os dejo el código completo de la clase para que podáis ver todo el proceso de a una.
/**
Copyright Mob&Me 2013 (@MobAndMe)
Licensed under the GPL General Public License, Version 3.0 (the "License"),
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.gnu.org/licenses/gpl.html
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Website: http://mobandme.com
Contact: Txus Ballesteros <txus.ballesteros@mobandme.com>
*/
package com.mobandme.toolkit;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Paint.Style;
import android.graphics.Path;
import android.graphics.Path.Direction;
import android.graphics.PorterDuff;
import android.util.AttributeSet;
import android.widget.ImageView;
import android.graphics.drawable.BitmapDrawable;
import com.mobandme.toolkit.helpers.ExceptionsHelper;
public class RoundImageView extends ImageView {
private int size = 0;
private Bitmap resultBitmap;
private Bitmap scaledBitmap;
private Path maskPath;
private Canvas maskedCanvas;
public RoundImageView(Context context) { super(context); }
public RoundImageView(Context context, AttributeSet attrs) { super(context, attrs); configureView(attrs); }
public RoundImageView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); configureView(attrs); }
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int parentWidth = MeasureSpec.getSize(widthMeasureSpec);
int parentHeight = MeasureSpec.getSize(heightMeasureSpec);
size = Math.min(parentWidth, parentHeight);
resultBitmap = null;
scaledBitmap = null;
maskedCanvas = null;
maskPath = null;
}
@Override
protected void onDraw(Canvas pCanvas) {
if (scaledBitmap == null) {
scaledBitmap = Bitmap.createScaledBitmap(((BitmapDrawable)getDrawable()).getBitmap(), size, size, true);
}
if (resultBitmap == null) {
resultBitmap = Bitmap.createBitmap(pCanvas.getWidth(), pCanvas.getHeight(), scaledBitmap.getConfig());
}
if (maskPath == null) {
maskPath = new Path();
maskPath.addCircle((size / 2), (size / 2), (size / 2), Direction.CCW);
maskPath.toggleInverseFillType();
maskPath.close();
}
if (maskedCanvas == null) {
maskedCanvas = new Canvas(resultBitmap);
//Draw background image.
maskedCanvas.drawBitmap(scaledBitmap, 0, 0, null);
//Draw transparent area masking the original bitmap.
maskedCanvas.clipPath(maskPath);
maskedCanvas.drawColor(Color.BLACK, PorterDuff.Mode.CLEAR);
}
pCanvas.drawBitmap(resultBitmap, 0, 0, null);
}
@Override
protected void onDetachedFromWindow() {
resultBitmap = null;
scaledBitmap = null;
maskedCanvas = null;
maskPath = null;
}
}




Nota: a partir de Android 3.0, y cuando se tiene la aceleración por hardware activada, la función
clipPath()no está soportada.Así lo indica la guía:
Podemos conseguir el mismo resultado con total compatibilidad utilizando los
PorterDuff.Mode:PD: El comentario anterior está mal editado. Aquí el bueno
Nota: a partir de Android 3.0, y cuando se tiene la aceleración por hardware activada, la función
clipPath()no está soportada.Así lo indica la guía:
http://developer.android.com/intl/es/guide/topics/graphics/hardware-accel.html#unsupported
Podemos conseguir el mismo resultado con total compatibilidad utilizando los
PorterDuff.Mode:http://developer.android.com/intl/es/reference/android/graphics/PorterDuff.Mode.html
Tienes toda la razón Eric,
Pero esta es la manera más fácil de conseguirlo, pese a que hay otras tantas técnicas.