Como hemos vistos en los ejemplos anteriores, para poder dibujar en Android hemos tenido que crear una nueva clase EjemploView, descendiente de View. Esta clase era creada dentro de EjemploGraficosActivity por lo que solo podía ser utilizada desde esta clase. Va a resultar mucho más interesante crear esta clase en un fichero independiente. De esta forma podremos utilizarla desde cualquier parte de nuestro proyecto, o desde otros proyectos. Incluso estará disponible en la paleta de vistas del editor visual. El siguiente ejercicio, te permite verificar este concepto.

Ejercicio paso a paso: Creación de una nueva vista independiente

En este ejercicio vamos a poner la clase EjemploView en un fichero independiente para que pueda ser utilizada desde cualquier parte.

1. Abre el proyecto EjemploGraficos.

2. En la clase EjemploGraficosActivity selecciona todo el texto correspondiente a la definición de la clase EjemploView y córtalo al portapapeles.

3. Pulsa con el botón derecho sobre src/org.example/ejemplografico y selecciona la opción New/Class...

4. Introduce como nombre de la clase EjemploView.

5. Pega el texto que has puesto en el portapapeles.

6. Verifica que al ejecutar la aplicación el resultado es idéntico al obtenido en la sección anterior.

En este apartado aprovechamos para introducir otros aspectos que tendrás que tener en cuenta para crear nuevas vistas. Cuando quieres crear una nueva vista, tendrás que extender la clase View, escribir un constructor y como mínimo sobreescribir los métodos onSizeChanged()onDraw(). Es decir, tendrás que seguir el siguiente esquema:

 
public class MiVista extends View {
 
   public MiVista(Context context, AttributeSet attrs) {
          super(context, attrs);
          //Inicializa la vista
          //OjO: Aún no se conocen sus dimensiones
   }
 
   @Override protected void onSizeChanged(int ancho, int alto,
                 int ancho_anterior, int alto_anterior){
          //Te informan del ancho y el alto
   }
 
   @Override protected void onDraw(Canvas canvas) {
          //Dibuja aquí la vista
   }
}

Observa como el constructor utilizado tiene dos parámetros: El primero de tipo Context te permitirá acceder al contexto de aplicación, por ejemplo para utilizar recursos de esta aplicación. El segundo, de tipo AttributeSet, te permitirá acceder a los atributos de esta vista, cuando sea creada desde XML. El constructor es el lugar adecuado para crear todos los componentes de tu vista, pero cuidado, en este punto todavía no se conoce las dimensiones que tendrá.

Android realiza un proceso de varias pasadas para determinar el ancho y alto de cada vista dentro de un Layout. Cuando finalmente ha establecido las dimensiones de una vista llamará a su método onSizeChanged(). Nos indica como parámetros el ancho y alto asignado. En caso de tratarse de un reajuste de tamaños, por ejemplo una de las vistas del Layout desaparece y el resto tienen que ocupar su espacio, se nos pasará el ancho y alto anterior. Si es la primera vez que se llama al método estos parámetros valdrán 0.

El último método que siempre tendrás que reescribir es onDraw(). Es aquí donde tendrás que dibujar la vista.

Ejercicio paso a paso: Creación de una vista que pueda ser diseñada desde XML

Vamos a modificar la vista anterior para que pueda ser utilizada usando un diseño en XML:

1.     Modifica el código de la clase EjemploView. para que coincida con el siguiente (en negrita se resaltan las diferencias):

public class EjemploView extends View {
   private ShapeDrawable miImagen;
 
   public EjemploView(Context context, AttributeSet attrs) {
          super(context, attrs);
          miImagen = new ShapeDrawable(new OvalShape());
          miImagen.getPaint().setColor(0xff0000ff);
   }

   @Override protected void onSizeChanged(int ancho, int alto,
                int ancho_anterior, int alto_anterior){
          miImagen.setBounds(0, 0, ancho, alto);
   }
 
   @Override protected void onDraw(Canvas canvas) {
          miImagen.draw(canvas);
   }
}

La primera diferencia es la utilización de un constructor con el parámetro AttributeSet. Este constructor es imprescindible si quieres poder definir la vista en XML. También se ha añadido el métodoonSizeChanged, para que el óvalo se dibuje siempre ajustado al tamaño de la vista.

2.     Abre el fichero activity_main.xml y reemplaza su contenido por el siguiente:

<LinearLayout>
    xmls:android="http://schemas.android.com/apk/res/android"
    android:layout_with="match_parent"
    android:layout_height="match_parent"
    android:orientacion="vertical"
    <org.example.ejemplograficos.EjemploView
           android:id="@+id/ejemploView1"
           android:layout_width="400px"
           android:layout_height="200px" />
    <org.example.ejemplograficos.EjemploView
           android:id="@+id/ejemploView2"
           android:layout_width="match_parent"     
           android:layout_height="match_parent" />
</LinearLayout>

NOTA: No utilices el valor "wrap_content". Nuestra vista no ha sido programada para soportar este tipo de valor

3.     En la clase EjemploGraficosActivity  reemplaza setContentView(new EjemploView(this)) por setContentView(R.layout.main).

4.     Ejecuta la aplicación. El resultado ha de ser similar a:

       

5.     Esta nueva vista también puede ser insertada en un layout usando el editor visual. Pulsa en la lengüeta Design para pasar a este modo de edición. En la paleta de vistas, busca la sección Advanced

6.     Seleciona <view> y arrástralo entre los dos óvalos. A continuación te pedirá que indiques la clase a utilizar. Selecciona EjemploView.

7.     Modifica en la ventana de Properties los siguientes atributos:

8.    Selecciona la lengüeta Text para observar el código introducido:
 

<view

    class="org.example.ejemplograficos.EjemploView"

    android:id="@+id/view1"

    android:layout_width="300dp"

    android:layout_height="50dp" />

9.   Compáralo con el código introducido en el punto 2. Se trata dos formas alternativas para introducir una vista creada por ti.