Android Tip: Cómo crear imágenes circulares

jueves, 16 de abril de 2015

Android logo

En el diseño de aplicaciones web y móbiles esta bastante del moda mostrar imágenes circulares, en Android antes era bastante tedioso poder realizar esta tarea, incluso éxisten librerías de terceros que básicamente suelen consistir en un control que hereda de ImageView, con un nombre tipo CircularImageView o RoundedImageView. Esto supone tener que arrastrar el control de una librería externa por todas los layouts que requieran una imagen circular y tener una dependencia tan fuerte de algo externo no es una de mis opciones favoritas.

En este artículo vamos a ver como podemos hacer esta tarea en Android ahora de una forma más sencilla y que viene soportado por el propio framework.

RoundedBitmapDrawable

En la versión 21 de la libreria support appcompat, que es la libreria utilizada en Android para dar soporte de nuevas funcionalidades del framework para versiones anteriores, existe una nueva clase que se llama RoundedBitmapDrawable, hereda de la clase Drawable y el trabajo de redondear los bordes de una imagen o hacerla circular completamente es bastante sencillo.

Ejemplo

En el activity tenemos un ImageView

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
    android:layout_height="match_parent" android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    android:paddingBottom="@dimen/activity_vertical_margin" tools:context=".MainActivity"
    android:background="@android:color/black">

    <ImageView
        android:layout_width="300dp"
        android:layout_height="300dp"
        android:id="@+id/imageView"
        android:layout_centerInParent="true" />
</RelativeLayout>


Si no hicieramos la imagen circular el código seria el siguiente:

  @Override
  protected void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      setContentView(R.layout.activity_main);

      //obtenemos el drawable original
      Drawable originalDrawable = getResources().getDrawable(R.drawable.image);

      ImageView imageView = (ImageView) findViewById(R.id.imageView);

      imageView.setImageDrawable(originalDrawable);
  }


El resultado sería este



Si quisieramos hacer la imagen circular el código es el siguiente:

  @Override
  protected void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      setContentView(R.layout.activity_main);

      //extraemos el drawable en un bitmap
      Drawable originalDrawable = getResources().getDrawable(R.drawable.image);
      Bitmap originalBitmap = ((BitmapDrawable) originalDrawable).getBitmap();

      //creamos el drawable redondeado
      RoundedBitmapDrawable roundedDrawable =
              RoundedBitmapDrawableFactory.create(getResources(), originalBitmap);

      //asignamos el CornerRadius
      roundedDrawable.setCornerRadius(originalBitmap.getHeight());

      ImageView imageView = (ImageView) findViewById(R.id.imageView);

      imageView.setImageDrawable(roundedDrawable);
  }


El resultado es este

Resumen

Hemos visto lo sencillo que es crear imagenes circulares en Android utilizando la clase RoundedBitmapDrawable que existe en la librería support appcompat desde la versión 21.

Libros relacionados

Android Programming: The Big Nerd Ranch Guide
Android Programming In a Day!: The Power Guide for Beginners In Android App Programming

14 comentarios:

  1. Gracias por tu aporte, buena la explicación

    ResponderEliminar
  2. Muchas gracias por tu comentario Carlos.

    ResponderEliminar
  3. Gracias por el tip.

    tengo un problema, las imagenes con dimensiones rectangulares, horizontal o vertical, no se ven redondas, tienden a verse extrañas, use este codigo:

    roundedBitmapDrawable.setCornerRadius(Math.max(bitmap.getWidth(), bitmap.getHeight()) / 1.25f);

    pero no es perfectamente redondo, se ven tipo huevos, o cosas asi... alguna idea???

    ResponderEliminar
    Respuestas
    1. Hola Elder

      Para que quede circular la imagen tiene que ser cuadrada, si tienes una imagen rectangular, tendrás que cortarla para dejarla cuadrada. Puedes crear una copia de la original pero con las dimensiones apropiadas para que sea cuadrada, te dejo una posible solución, espero que te sirva:

      //extraemos el drawable en un bitmap
      Drawable originalDrawable = getResources().getDrawable(R.drawable.rectangular);
      Bitmap originalBitmap = ((BitmapDrawable) originalDrawable).getBitmap();

      if (originalBitmap.getWidth() > originalBitmap.getHeight()){
      originalBitmap = Bitmap.createBitmap(originalBitmap, 0, 0, originalBitmap.getHeight(), originalBitmap.getHeight());
      }else if (originalBitmap.getWidth() < originalBitmap.getHeight()) {
      originalBitmap = Bitmap.createBitmap(originalBitmap, 0, 0, originalBitmap.getWidth(), originalBitmap.getWidth());
      }

      //creamos el drawable redondeado
      RoundedBitmapDrawable roundedDrawable =
      RoundedBitmapDrawableFactory.create(getResources(), originalBitmap);

      //asignamos el CornerRadius
      roundedDrawable.setCornerRadius(originalBitmap.getWidth());

      ImageView imageView = (ImageView) findViewById(R.id.imageView);

      imageView.setImageDrawable(roundedDrawable);

      Eliminar
  4. Muchas gracias, usaré este código como contingencia, cuando la imagen no sea cuadrada. Saludos

    ResponderEliminar
  5. Hola que tal si la imagen la estoy extrayendo de un servicio es la misma sintaxis??
    Saludos

    ResponderEliminar
  6. Hola!! Muy interesante.. me sirvio de mucho este aporte.. quisiera saber si tambien funciona a un ImageSwitcher?? o como puedo utilizarlo en ese caso?

    ResponderEliminar
    Respuestas
    1. Hola CHEO, nunca lo he utilizado con ImageSwitcher, lo siento pero no te puedo ayudar.

      Eliminar
  7. Hola buenas!

    Estoy intentando redondear una imagen, pero no dentro de un ImageView, sino una imagen que va en un TabSpec. He probado con el código que aparece en este Blog, pero no me funciona.

    ¿Es posible que funcione para un TabSpec? ¿O tiene que ir en un ImageView?

    ResponderEliminar
    Respuestas
    1. Hola Anónimo,

      Solo lo he probado como aparece en el artículo, lo siento pero no te puedo ayudar con tu caso.

      Saludos

      Eliminar
  8. Hola jorge:
    No me queda muy claro getResources() como lo obtengo en el caso de traer el bitmap de la SDcard (las extraigo por medio de una ruta que guardo en una base de dato SQLite)

    ResponderEliminar
    Respuestas
    1. Hola Cidius
      Prueba con esto:

      Bitmap myBitmap = BitmapFactory.decodeFile(pathName);
      Drawable myDrawable = new BitmapDrawable(getResources(), myBitmap);

      Eliminar
  9. Jorge , excelente aporte mi hermano, gracias muchas gracias

    ResponderEliminar