Android

Android


8.GRÁFICOS

Página 9 de 25

8.   GRÁFICOS

El paquete android.graphics proporciona herramientas gráficas para dibujar directamente en la pantalla. Ilustraremos cómo se dibuja sobre un objeto de la clase Canvas (que correspondería al lienzo sobre el que se pinta) utilizando un objeto de tipo Paint       (herramienta  que contiene los colores y estilos de dibujo).

8.1.   Dibujando en un Canvas

La siguiente aplicación muestra en pantalla un objeto grafico       de tipo View. No se necesita el fichero main.xml. Todo está definido en código Java.

La parte gráfica se define en el método onDraw(Canvas canvas). Primero se crea un objeto Paint:

Paint paint = new Paint();

y luego usamos sus métodos para cambiar el color, tamaño de texto, etc. Por ejemplo, para pintar de blanco:

paint.setColor(Color.WHITE);

El canvas se pinta entero de este color llamando al método:

canvas.drawPaint(paint)

Para dibujar algo sobre el canvas se dan las coordenadas, (x,y), y el objeto paint. Por ejemplo, para dibujar un texto:

canvas.drawText("texto",x,y,paint)

y para dibujar una línea uniendo los puntos (x1,y1) y (x2,y2):

canvas.drawLine(x1,y1,x2,y2,paint);

En este ejemplo escribimos en las coordenadas (20,40) la anchura y la altura del canvas. Dibujamos también una linea horizontal y otra vertical que pasan por ese punto.

  public class Graficos1 extends Activity {

    @Override

    public void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        GraficoView grafico =new GraficoView(this);

        setContentView(grafico);

    }

    private class GraficoView extends View{

    public GraficoView(Context context) {

         super(context);

      }

    @Override protected void onDraw(Canvas canvas){

      super.onDraw(canvas);

      Paint paint=new Paint();

      paint.setColor(Color.WHITE);

      canvas.drawPaint(paint);

      int width=canvas.getWidth();

      int height=canvas.getHeight();

      paint.setColor(Color.BLACK);

      paint.setTextSize(30);

      paint.setAntiAlias(true);

      canvas.drawText("width= "+width+", height= "+height,

                       20,40,paint);

      paint.setColor(Color.rgb(100,20,0));

      canvas.drawLine(0,40,width,40,paint);

      paint.setColor(Color.rgb(0,100,20));

      canvas.drawLine(20,0,20,height,paint);

      }

    }

   }

El resultado lo vemos en la figura 8.1.

Figura 8.1. La anchura y altura del canvas.

8.2.   Formato del texto

En la siguiente actividad ilustramos distintos métodos de Paint para cambiar las propiedades del texto: alineamiento, inclinación, escalado, estilo de fuente y antialias. El resultado se ve en la figura 8.2.

  public class Graficos2 extends Activity {

    @Override

    public void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        GraficoView grafico =new GraficoView(this);

        setContentView(grafico);

    }

    private class GraficoView extends View{

    public GraficoView(Context context) {

         super(context);

      }

      @Override protected void onDraw(Canvas canvas){

         super.onDraw(canvas);

         Paint paint=new Paint();

         paint.setColor(Color.WHITE);

         canvas.drawPaint(paint);

         int width=canvas.getWidth();

         int height=canvas.getHeight();

         paint.setTextSize(30);

         paint.setAntiAlias(true);

         paint.setColor(Color.rgb(0,100,20));

         canvas.drawLine(width/2,0,width/2,height,paint);

         paint.setColor(Color.BLACK);

         paint.setTextAlign(Align.RIGHT);

         canvas.drawText("Align.RIGHT",width/2, 160, paint);

         paint.setTextAlign(Align.CENTER);

         canvas.drawText("Align.CENTER",width/2, 120, paint);

         paint.setTextAlign(Align.LEFT);

         canvas.drawText("Align.LEFT",width/2, 80, paint);

         paint.setTextSkewX(0.2f);

         canvas.drawText("SkewX 0.2",20, 210, paint);

         paint.setTextSkewX(-0.2f);

         canvas.drawText("SkewX -0.2",width/2, 210, paint);

         paint.setTextSkewX(0f);

         paint.setTextScaleX(2f);

         canvas.drawText("TextScaleX 2",10, 250, paint);

         paint.setTextScaleX(-2f);

         canvas.drawText("TextScaleX -2",width, 290, paint);

         paint.setTextSize(60);

         paint.setTextScaleX(0.5f);

         canvas.drawText("TextScaleX 0.5",width/2, 360, paint);

         paint.setTextScaleX(1f);

         paint.setTextSize(30);

         paint.setTypeface(Typeface.SANS_SERIF);

         canvas.drawText("Sans serif",20, 330, paint);

         paint.setTypeface(Typeface.DEFAULT_BOLD);

         canvas.drawText("Default bold",20, 370, paint);

         paint.setTypeface(Typeface.MONOSPACE);

         canvas.drawText("Monospace",20, 410, paint);

         paint.setTypeface(Typeface.SERIF);

         canvas.drawText("Serif",20, 450, paint);

         paint.setTypeface(Typeface.DEFAULT);

         paint.setTextSize(50);

         paint.setAntiAlias(false);

         canvas.drawText("Antialias false",20, 500, paint);

         paint.setAntiAlias(true);

         canvas.drawText("Antialias true",20, 550, paint);

       }

     }

   }

Figura 8.2. Controlando propiedades del texto con Paint.

8.3.   Altura del canvas

El siguiente ejemplo demuestra que la coordenada y la parte inferior del canvas no coincide con canvas.getHeight(). Esto se debe a que la altura total del canvas es igual a la altura de la pantalla completa, que incluye las barras superiores de notificación y del título de la actividad, cuya altura habría que restar. En el ejemplo de la figura 8.3 esa diferencia valdría alrededor de 80.

Figura 8.3.   Examinando la altura efectiva del canvas.

  public class Graficos3 extends Activity {

    /** Called when the activity is first created. */

    @Override

    public void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        SpecialView myView= new SpecialView(this);

        setContentView(myView);

    }

    private class SpecialView extends View{

    public SpecialView(Context context) {

      super(context);

    }

    @Override protected void onDraw(Canvas canvas){

      int width=canvas.getWidth();

      int height=canvas.getHeight();

      canvas.drawColor(Color.WHITE);

      Paint paintBlack=new Paint();

      Paint paintGray=new Paint();

      paintBlack.setColor(Color.BLACK);

      paintGray.setColor(Color.GRAY);

      for(int i=30;i<height;i+=30){

        canvas.drawLine(0,i,width,i, paintGray);

        canvas.drawText(""+i,30,i,paintBlack);    

      }

      paintBlack.setTextSize(40);

      paintBlack.setAntiAlias(true);

      canvas.drawText("height= "+height,

                      100,height/2,paintBlack);

    }

   }

  }

8.4.   Dimensiones del canvas

En el siguiente ejemplo demostramos que las dimensiones correctas del canvas pueden obtenerse con los métodos de la clase View: getMeasuredWidth(); getMeasuredHeight(); o alternativamente con getBottom(); getRight();

Figura 8.4. Examinando la altura efectiva del canvas.

En la figura 8.4 vemos que onDraw() dibuja dos líneas uniendo las esquinas opuestas del canvas y escribe los valores obtenidos con los anteriores métodos:

  public class Formas extends Activity {

    /** Called when the activity is first created. */

    @Override

    public void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        SpecialView myView = new SpecialView(this);

        setContentView(myView);

    }

    class SpecialView extends View{

      public SpecialView(Context context) {

         super(context);

         // TODO Auto-generated constructor stub

      }

      @Override

      protected void onDraw(Canvas canvas){

         canvas.drawColor(Color.WHITE);

         Paint paint=new Paint();

         paint.setColor(Color.BLACK);

         paint.setTextSize(30);

         paint.setAntiAlias(true);

         int width=getMeasuredWidth();

         int height=getMeasuredHeight();

         int bottom=getBottom();

         int right=getRight();

         paint.setTextAlign(Align.CENTER);

         canvas.drawText("Width "+width, width/2,40,paint);

         canvas.drawText("Height "+height, width/2,80,paint);

         canvas.drawText("Right "+right, width/2,120,paint);

         canvas.drawText("Bottom "+bottom,

                          width/2,160,paint);

         paint.setColor(Color.BLUE);

         canvas.drawLine(0,0,right,bottom, paint);

         canvas.drawLine(right,0,0,bottom, paint);

      }

    }

  }

En la figura 8.5 vemos cómo cambian las dimensiones cuando giramos el dispositivo. Esto se puede hacer en el emulador mediante las teclas Ctrl-F11.

Figura 8.5. Examinando la altura efectiva del canvas.

8.5.   Formas geométricas

En la siguiente aplicación mostramos cómo dibujar círculos y cuadrados de varios colores y luego pintamos su perímetro de color negro con distintas anchuras de trazo. El canvas lo enmarcamos dibujando un rectángulo. El resultado se ve en la figura 8.6.

Figura 8.6. Formas geométricas.

  public class Formas2 extends Activity {

    @Override

    public void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        SpecialView myView=new SpecialView(this);

        setContentView(myView);

    }

    class SpecialView extends View{

      public SpecialView(Context context) {

         super(context);

      }

      @Override

      protected void onDraw(Canvas canvas){

         int bottom=getBottom();

         int right=getRight();

         canvas.drawColor(Color.WHITE);

         Paint paint=new Paint();

         paint.setAntiAlias(true);

         paint.setStyle(Paint.Style.FILL);

         paint.setColor(Color.RED);

         canvas.drawCircle(50,50,30,paint);

         canvas.drawRect(150,50,200,100, paint);

         paint.setColor(Color.BLUE);

         canvas.drawCircle(50,100,30,paint);

         canvas.drawRect(150,150,200,200, paint);

         paint.setColor(Color.GREEN);

         canvas.drawCircle(50,150,30,paint);

            canvas.drawRect(150,250,200,300, paint);

         paint.setColor(Color.MAGENTA);

         canvas.drawCircle(50,200,30,paint);

         canvas.drawRect(150,350,200,400, paint);

         paint.setColor(Color.BLACK);

         paint.setStyle(Paint.Style.STROKE);

         canvas.drawCircle(50,50,30,paint);

         canvas.drawCircle(50,100,30,paint);

         canvas.drawCircle(50,150,30,paint);

         canvas.drawCircle(50,200,30,paint);

         canvas.drawRect(150,50,200,100, paint);

         paint.setStrokeWidth(2);

         canvas.drawRect(150,150,200,200, paint);

         paint.setStrokeWidth(4);

         canvas.drawRect(150,250,200,300, paint);

         paint.setStrokeWidth(6);

         canvas.drawRect(150,350,200,400, paint);

         canvas.drawRect(10,10,right-10,bottom-10, paint);

      }

    }

  }

8.6.   Curvas

En el siguiente ejemplo mostramos cómo se define una curva mediante un objeto de tipo Path compuesto de muchas lineas, que se añaden al path mediante path.lineTo(). Esta curva se puede trasladar mediante path.offset() y dibujar con distintos estilos de línea: discontinua, puntos y trazos, puntos, etc. Para ello se usa paint.setPathEffect(). En este ejemplo dibujamos la función sin(x). El resultado se ve en la figura 8.7.

Figura 8.7. Curvas. Representación gráfica de la función sin(x).

  public class Curvas extends Activity {

    @Override

    public void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        SpecialView myView = new SpecialView(this);

        setContentView(myView);

    }

    class SpecialView extends View{

      public SpecialView(Context context) {

         super(context);

      }

      @Override

      protected void onDraw(Canvas canvas){

         canvas.drawColor(Color.WHITE);

         Paint paint=new Paint();

         paint.setColor(Color.BLACK);

         paint.setStyle(Paint.Style.STROKE);

         paint.setStrokeWidth(2);

         paint.setAntiAlias(true);

         int width=getMeasuredWidth();

         int height=getMeasuredHeight();

         Path path=new Path();

         path.moveTo(0, 0);

         for(int i=1;i<width;i++){

                path.lineTo(i, (float) Math.sin(i/20f)*(-50f));

         }

         path.offset(0,100);

         canvas.drawPath(path,paint);

         float[] intervalos={10,10};

         DashPathEffect dash =

                        new DashPathEffect(intervalos,1);

         paint.setPathEffect(dash);

         path.offset(0,100);

         canvas.drawPath(path,paint);

         float[] intervalos2={10,10,2,10};

         DashPathEffect dash2 =

                        new DashPathEffect(intervalos2,0);

         paint.setPathEffect(dash2);

         path.offset(0,100);

         canvas.drawPath(path,paint);

         float[] intervalos3={2,4};

         DashPathEffect dash3 =

                        new DashPathEffect(intervalos3,0);

         paint.setPathEffect(dash3);

         path.offset(0,100);

         canvas.drawPath(path,paint);

      }

    }

  }

8.7.   Traslaciones y rotaciones

El canvas puede sufrir traslaciones y rotaciones aparte de otras transformaciones más generales. En el siguiente ejemplo realizamos una traslación y una rotación. La rotación se realiza con respecto al punto medio de un texto que se va a rotar. El rectángulo que limita al texto (bounding box) se dibuja en rojo antes de la rotación. El canvas vuelve a su posición inicial con canvas.restore(). El resultado se ve en la figura 8.8.

Figura 8.8. Rotación del canvas.

  public class Rotaciones extends Activity {

    @Override

    public void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        SpecialView myView = new SpecialView(this);

        setContentView(myView);

    }

    class SpecialView extends View{

      public SpecialView(Context context) {

         super(context);

      }

      @Override

      protected void onDraw(Canvas canvas){

         canvas.drawColor(Color.WHITE);

         Paint paint=new Paint();

         paint.setTextSize(40);

         paint.setAntiAlias(true);

         // Traslada el origen del canvas

         int x=50;

         int y=150;

         canvas.translate(x,y);

         // Rectangulo bounding-box de un texto

         String texto="Rotacion del canvas";

         Rect bounds= new Rect();

         paint.getTextBounds(texto,0,texto.length(),bounds);

         paint.setColor(Color.RED);

         paint.setStyle(Paint.Style.STROKE);

         canvas.drawRect(bounds,paint);

         //centro del rectangulo

         float centerX=bounds.exactCenterX();

         float centerY=bounds.exactCenterY();

         //rotacion del canvas

         canvas.rotate(-45,centerX,centerY);

         paint.setColor(Color.BLACK);

         paint.setStyle(Paint.Style.FILL);

         canvas.drawText(texto,0,0,paint);

         // restablece el canvas

         canvas.restore();

         canvas.drawText("Tras la rotacion",100,300,paint);

      }

    }

  }

8.8.   Texto siguiendo una curva

El siguiente ejemplo define una curva Path conteniendo un círculo y luego escribe un texto siguiendo la curva con canvas.drawTextOnPath(). El parámetro vOffset define la distancia vertical del texto (perpendicular a la curva), mientras que hOffset define la distancia horizontal del texto (a lo largo) al origen de la curva. Este método nos da total control sobre la  dirección que sigue un texto. El efecto se ve en la figura 8.9.

Figura 8.9. Texto en una curva.

  public class TextOnPath extends Activity {

    @Override

    public void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        SpecialView myView = new SpecialView(this);

        setContentView(myView);

    }

    class SpecialView extends View{

      public SpecialView(Context context) {

         super(context);

      }

      @Override

       protected void onDraw(Canvas canvas){

         canvas.drawColor(Color.WHITE);

         Paint paint=new Paint();

         paint.setTextSize(60);

         paint.setAntiAlias(true);

         int width=getWidth();

         paint.setColor(Color.RED);

         paint.setStyle(Paint.Style.STROKE);

         Path path=new Path();

         Direction dir=Direction.CW;

         float radio=100;

         path.addCircle(width/2,200,radio,dir);

         path.offset(0, 0);

         float hOffset=0;

         float vOffset=-20;

         canvas.drawPath(path, paint);

         paint.setColor(Color.BLACK);

         canvas.drawTextOnPath("texto en path externo",

                          path, hOffset, vOffset, paint);

         vOffset=20;

         hOffset=100;

         paint.setStyle(Paint.Style.FILL);

         paint.setTextSize(20);

         canvas.drawTextOnPath("texto interior comenzando a "

                              +hOffset+" del punto inicial",

                             path, hOffset, vOffset, paint);

      }

    }

  }

8.9.   Caracteres Unicode

Muchos caracteres especiales pueden escribirse usando el código Unicode. El siguiente programa escribe algunos de ellos. Nótese que algunos códigos no están soportados en nuestro emulador, figura 8.10.

    class SpecialView extends View{

      public SpecialView(Context context) {

         super(context);

      }

      @Override

      protected void onDraw(Canvas canvas){

         canvas.drawColor(Color.WHITE);

         Paint paint=new Paint();

         paint.setTextSize(30);

         paint.setAntiAlias(true);

         int width=getWidth();

         int height=getHeight();

         paint.setColor(Color.BLACK);

         canvas.drawText("Unicode", 40,40,paint);

         canvas.drawText("http://www.unicode.org",

         20,height-10,paint);

         paint.setTextSize(20);

         canvas.drawText("\u222B \\u222B", 20,70,paint);

         canvas.drawText("\u2202 \\u2202", 20,100,paint);

         canvas.drawText("\u2206 \\u2207", 20,130,paint);

         canvas.drawText("\u220A \\u220A", 20,160,paint);

         canvas.drawText("\u2297 \\u2297", 20,190,paint);

         canvas.drawText("\u2264 \\u2264", 20,210,paint);

         canvas.drawText("\u2265 \\u2265", 20,240,paint);

         canvas.drawText("\u2218 \\u2218", 20,270,paint);

         canvas.drawText("\u2243 \\u2243", 20,300,paint);

         canvas.drawText("\u221A \\u221A", 20,330,paint);

         canvas.drawText("\u221B \\u221B", 20,360,paint);

         canvas.drawText("\u222C \\u222C", 20,390,paint);

         canvas.drawText("\u222D \\u222D", 20,420,paint);

         int w=width/3;

         canvas.drawText("\u03B1 \\u03B1", w,70,paint);

         canvas.drawText("\u03B2 \\u03B2", w,100,paint);

         canvas.drawText("\u03B3 \\u03B3", w,130,paint);

         canvas.drawText("\u03B4 \\u03B4", w,160,paint);

         canvas.drawText("\u03B5 \\u03B5", w,190,paint);

         canvas.drawText("\u03B6 \\u03B6", w,210,paint);

         canvas.drawText("\u03B7 \\u03B7", w,240,paint);

         canvas.drawText("\u03B8 \\u03B8", w,270,paint);

         canvas.drawText("\u03B9 \\u03B9", w,300,paint);

         canvas.drawText("\u03BA \\u03BA", w,330,paint);

         canvas.drawText("\u03BB \\u03BB", w,360,paint);

         canvas.drawText("\u03BC \\u03BC", w,390,paint);

         canvas.drawText("\u03BD \\u03BD", w,420,paint);

         canvas.drawText("\u03BE \\u03BE", w,450,paint);

         canvas.drawText("\u03BF \\u03BF", w,480,paint);

         w=2*width/3;

         canvas.drawText("\u03C1 \\u03C1", w,70,paint);

         canvas.drawText("\u03C2 \\u03C2", w,100,paint);

         canvas.drawText("\u03C3 \\u03C3", w,130,paint);

         canvas.drawText("\u03C4 \\u03C4", w,160,paint);

         canvas.drawText("\u03C5 \\u03C5", w,190,paint);

         canvas.drawText("\u03C6 \\u03C6", w,210,paint);

         canvas.drawText("\u03C7 \\u03C7", w,240,paint);

         canvas.drawText("\u03C8 \\u03C8", w,270,paint);

         canvas.drawText("\u03C9 \\u03C9", w,300,paint);

         canvas.drawText("\u03CA \\u03CA", w,330,paint);

         canvas.drawText("\u03CB \\u03CB", w,360,paint);

         canvas.drawText("\u03CC \\u03CC", w,390,paint);

         canvas.drawText("\u03CD \\u03CD", w,420,paint);

         canvas.drawText("\u03CE \\u03CE", w,450,paint);

         canvas.drawText("\u03CF \\u03CF", w,480,paint);

         canvas.drawText("\u03a3 \\u03a3", 10,520,paint);

         canvas.drawText("\u03a6 \\u03a6", 10,560,paint);

         canvas.drawText("\u03a8 \\u03a8", 10,600,paint);

         canvas.drawText("\u03a9 \\u03a9", 10,640,paint);

      }

  }

Figura 8.10. Texto Unicode.

8.10.   LayoutParams

Hasta ahora en este capítulo las dimensiones de nuestros objetos gráficos de tipo View han sido controladas por el sistema, ocupando toda la parte disponible de la pantalla. Estas dimensiones pueden controlarse externamente para añadir objetos view de un tamaño determinado a un layout. Para ello primero creamos un objeto de tipo LayoutParams, que almacena las dimensiones de anchura y altura, y luego asignamos esa geometría a nuestro gráfico mediante el método  setLayoutParams(params) de la clase View:

LayoutParams params=

                new LayoutParams(int anchura,int altura);

view1.setLayoutParams(params);

En el siguiente ejemplo añadimos tres gráficos a un layout con tres geometrías distintas. Cada gráfico contiene un texto con sus dimensiones y un color de fondo. Utilizaremos la siguiente interfaz de usuario:

<?xml version="1.0" encoding="utf-8"?>

<LinearLayout

xmlns:android="http://schemas.android.com/apk/res/android"

      android:orientation="vertical"

      android:layout_width="fill_parent"

      android:layout_height="fill_parent"

      android:id="@+id/layout"

      android:background="#ffffff">

<TextView android:text="LayoutParams"

      android:id="@+id/textView1"

      android:layout_width="wrap_content"

      android:layout_height="wrap_content">

</TextView>

</LinearLayout>

El programa Java para dibujar tres gráficos con distintas anchuras y alturas y añadirlos a un layout es el siguiente:

package es.amaro.ugr.layoutparametros;

import android.app.Activity;

import android.content.Context;

import android.graphics.Canvas;

import android.graphics.Color;

import android.graphics.Paint;

import android.graphics.Rect;

import android.os.Bundle;

import android.view.View;

Ir a la siguiente página

Report Page