Android SDK: Crea una aplicación de dibujo – Interacción táctil
Spanish (Español) translation by CYC (you can also view the original English article)
En esta serie, crearemos una aplicación para pintar con los dedos para Android utilizando la interacción táctil. El usuario podrá seleccionar desde una paleta de colores, elegir un tamaño de pincel, borrar, crear un nuevo dibujo o guardar su dibujo existente en la galería del dispositivo.
Formato de serie
Esta serie sobre Crear una aplicación de dibujo se dividirá en tres partes:
Vista previa final



En la primera parte de la serie, creamos la interfaz de usuario. En esta segunda parte implementaremos el dibujo en el lienzo y la elección de colores. En la parte final de la serie presentaremos la capacidad de borrar, crear nuevos dibujos y guardar un dibujo en la galería del dispositivo del usuario. Veremos las opciones que puedes usar para mejorar esta aplicación en tutoriales futuros, incluidos los rellenos de patrones, la opacidad y la interacción que no sean la pantalla táctil.
1. Prepararse para el dibujo
Paso 1
La última vez creamos una clase llamada "DrawingView" que es una vista personalizada para que las funciones de dibujo tengan lugar. Creamos el esquema de la declaración de clase y un método llamado "setupDrawing": implementaremos esto ahora. En tu clase DrawingView, agrega las siguientes instrucciones de importación:
1 |
import android.graphics.Bitmap; |
2 |
import android.graphics.Canvas; |
3 |
import android.graphics.Paint; |
4 |
import android.graphics.Path; |
5 |
import android.view.MotionEvent; |
A continuación, agrega algunas variables de instancia en la parte superior de la clase:
1 |
//drawing path
|
2 |
private Path drawPath; |
3 |
//drawing and canvas paint
|
4 |
private Paint drawPaint, canvasPaint; |
5 |
//initial color
|
6 |
private int paintColor = 0xFF660000; |
7 |
//canvas
|
8 |
private Canvas drawCanvas; |
9 |
//canvas bitmap
|
10 |
private Bitmap canvasBitmap; |
Cuando el usuario toque la pantalla y mueva su dedo para dibujar, utilizaremos una ruta para rastrear su acción de dibujo en el lienzo. Tanto el lienzo como el dibujo en la parte superior están representados por objetos de pintura. El color de pintura inicial corresponde al primer color de la paleta que creamos la última vez y se seleccionará inicialmente cuando se inicie la aplicación. Finalmente, declaramos las variables para el lienzo y el mapa de bits: las rutas de usuario dibujadas con drawPaint se dibujarán en el lienzo, que se dibujará con canvasPaint.
Paso 2
En el método setupDrawing, vamos a instalar algunas de estas variables ahora y así configurar la clase para el dibujo. Primero crea una instancia de los objetos Path y Paint:
1 |
drawPath = new Path(); |
2 |
drawPaint = new Paint(); |
Después, establece el color inicial:
1 |
drawPaint.setColor(paintColor); |
Ahora establece las propiedades de la ruta inicial:
1 |
drawPaint.setAntiAlias(true); |
2 |
drawPaint.setStrokeWidth(20); |
3 |
drawPaint.setStyle(Paint.Style.STROKE); |
4 |
drawPaint.setStrokeJoin(Paint.Join.ROUND); |
5 |
drawPaint.setStrokeCap(Paint.Cap.ROUND); |
Modificaremos parte de este código en el siguiente tutorial cuando implementemos la capacidad de elegir tamaños de pincel, por ahora establecemos un tamaño de pincel arbitrario. Al establecer los estilos de antialias, unión de trazos y de tapa, los dibujos del usuario se verán más suaves.
Completa el método setupDrawing instanciando el objeto Paint:
1 |
canvasPaint = new Paint(Paint.DITHER_FLAG); |
Esta vez establecemos el difuminado pasando un parámetro al constructor.
Paso 3
Necesitamos anular un par de métodos para hacer que la función de Vista personalizada sea una Vista de dibujo. Primero, aún dentro de la clase DrawingView, anula el método onSizeChanged, que se invocará cuando a la Vista personalizada se le asigne un tamaño:
1 |
@Override
|
2 |
protected void onSizeChanged(int w, int h, int oldw, int oldh) { |
3 |
//view given size
|
4 |
}
|
Dentro de este método, primero llama al método de la superclase:
1 |
super.onSizeChanged(w, h, oldw, oldh); |
Ahora crea una instancia del lienzo de dibujo y el mapa de bits usando los valores de ancho y alto:
1 |
canvasBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888); |
2 |
drawCanvas = new Canvas(canvasBitmap); |
Paso 4
Para permitir que la clase funcione como una vista de dibujo personalizada, también tenemos que anular el método onDraw, por lo tanto debes agregarlo ahora a la clase:
1 |
@Override
|
2 |
protected void onDraw(Canvas canvas) { |
3 |
//draw view
|
4 |
}
|
Dentro del método, dibuja el lienzo y la ruta de dibujo:
1 |
canvas.drawBitmap(canvasBitmap, 0, 0, canvasPaint); |
2 |
canvas.drawPath(drawPath, drawPaint); |
Todavía no hemos implementado la capacidad del usuario para dibujar la ruta usando el dibujo de pintura, pero una vez que lo hagamos, se presentará en la vista. Cada vez que el usuario dibuja usando la interacción táctil, invalidaremos la Vista, lo que hará que se ejecute el método onDraw.
2. Facilitar el dibujo
Paso 1
Cuando la Vista de dibujo se encuentra en la pantalla de la aplicación, queremos que los toques del usuario se registren como operaciones de dibujo. Para hacer esto, necesitamos recibir eventos táctiles. En tu clase drawingView, agrega el siguiente método:
1 |
@Override
|
2 |
public boolean onTouchEvent(MotionEvent event) { |
3 |
//detect user touch
|
4 |
}
|
Dentro del método, recupera las posiciones X e Y del toque del usuario:
1 |
float touchX = event.getX(); |
2 |
float touchY = event.getY(); |
Paso 2
El parámetro MotionEvent para el método onTouchEvent nos permitirá responder a eventos táctiles particulares. Las acciones que nos interesan para implementar el dibujo son down, move y up. Agrega una instrucción switch en el método para responder a cada uno de estos:
1 |
switch (event.getAction()) { |
2 |
case MotionEvent.ACTION_DOWN: |
3 |
drawPath.moveTo(touchX, touchY); |
4 |
break; |
5 |
case MotionEvent.ACTION_MOVE: |
6 |
drawPath.lineTo(touchX, touchY); |
7 |
break; |
8 |
case MotionEvent.ACTION_UP: |
9 |
drawCanvas.drawPath(drawPath, drawPaint); |
10 |
drawPath.reset(); |
11 |
break; |
12 |
default: |
13 |
return false; |
14 |
}
|
Toma un momento para revisar este código. Cuando el usuario toca la Vista, nos movemos a esa posición para comenzar a dibujar. Cuando mueven su dedo sobre la Vista, dibujamos el camino junto con su toque. Cuando levantan su dedo de la Vista, dibujamos la ruta y se reinicia para la siguiente operación de dibujo.
Paso 3
Después de la instrucción switch, completa el método invalidando View y devolviendo un valor true:
1 |
invalidate(); |
2 |
return true; |
Llamando invalidate hará que el método onDraw se ejecute.
3. Seleccionando colores
Paso 1
Implementemos ahora la capacidad del usuario para elegir colores de la paleta. En la Actividad principal de la aplicación, agrega las siguientes importaciones:
1 |
import android.view.View; |
2 |
import android.widget.ImageButton; |
3 |
import android.widget.LinearLayout; |
Agrega la siguiente variable de instancia a la clase:
1 |
private DrawingView drawView; |
Esto representa la instancia de la Vista personalizada que agregamos al diseño. En onCreate, después del código existente, crea una instancia de esta variable recuperando una referencia desde el diseño:
1 |
drawView = (DrawingView)findViewById(R.id.drawing); |
Ahora tenemos la Vista que se muestra en la Actividad en la que podemos llamar a los métodos en la clase DrawingView.
Paso 2
Establecemos el color de pintura inicial en la clase de dibujo de la vista, ahora establezcamos la interfaz de usuario para reflejar y administrar eso. En la clase de actividad principal, agrega otra variable de instancia para representar el botón de color de pintura en la paleta:
1 |
private ImageButton currPaint; |
En onCreate, ahora queremos recuperar el primer botón de color de pintura en el área de la paleta, que inicialmente se seleccionará. Primero recupera el diseño lineal que se encuentra dentro de:
1 |
LinearLayout paintLayout = (LinearLayout)findViewById(R.id.paint_colors); |
Obtén el primer botón y guárdalo como la variable de instancia:
1 |
currPaint = (ImageButton)paintLayout.getChildAt(0); |
Utilizaremos una imagen dibujable diferente en el botón para mostrar que está seleccionada actualmente:
1 |
currPaint.setImageDrawable(getResources().getDrawable(R.drawable.paint_pressed)); |
Agrega ahora este archivo a los objetos extraíbles de tu aplicación, dándole el nombre "paint_pressed.xml" e ingresando la siguiente forma:
1 |
<layer-list xmlns:android="https://schemas.android.com/apk/res/android" > |
2 |
<item>
|
3 |
<shape android:shape="rectangle" > |
4 |
<stroke
|
5 |
android:width="4dp" |
6 |
android:color="#FF333333" /> |
7 |
|
8 |
<solid android:color="#00000000" /> |
9 |
|
10 |
<padding
|
11 |
android:bottom="0dp" |
12 |
android:left="0dp" |
13 |
android:right="0dp" |
14 |
android:top="0dp" /> |
15 |
</shape>
|
16 |
</item>
|
17 |
<item>
|
18 |
<shape xmlns:android="http://schemas.android.com/apk/res/android" > |
19 |
<stroke
|
20 |
android:width="4dp" |
21 |
android:color="#FF333333" /> |
22 |
|
23 |
<solid android:color="#00000000" /> |
24 |
|
25 |
<corners android:radius="10dp" /> |
26 |
</shape>
|
27 |
</item>
|
28 |
</layer-list>
|
Esto es muy similar al dibujable "paint.xml" que creamos la última vez, pero con un color más oscuro alrededor de la pintura.
Paso 3
Ahora podemos dejar que el usuario elija colores. Cuando creamos el diseño la última vez, enumeramos un atributo onClick para los botones de la paleta de colores - agrega ahora el método a tu clase de actividad principal:
1 |
public void paintClicked(View view){ |
2 |
//use chosen color
|
3 |
}
|
Dentro de este método, primero verifica que el usuario haya hecho clic en un color de pintura que no es el seleccionado actualmente:
1 |
if(view!=currPaint){ |
2 |
//update color
|
3 |
}
|
Dentro del bloque if, recupera la etiqueta que establecemos para cada botón en el diseño, que representa el color elegido:
1 |
ImageButton imgView = (ImageButton)view; |
2 |
String color = view.getTag().toString(); |
Necesitamos usar la clase de Vista personalizada para establecer el color. Ve a la clase DrawingView ahora y agrega el siguiente método:
1 |
public void setColor(String newColor){ |
2 |
//set color
|
3 |
}
|
Dentro del método, comienza por invalidar la Vista:
1 |
invalidate(); |
A continuación, analiza y establece el color para el dibujo:
1 |
paintColor = Color.parseColor(newColor); |
2 |
drawPaint.setColor(paintColor); |
De vuelta en tu actividad principal, en el método paintClicked después de recuperar la etiqueta de color, llama al nuevo método en el objeto de vista de dibujo personalizado:
1 |
drawView.setColor(color); |
Ahora actualiza la interfaz de usuario para reflejar la nueva pintura elegida y restablece la anterior a la normalidad:
1 |
imgView.setImageDrawable(getResources().getDrawable(R.drawable.paint_pressed)); |
2 |
currPaint.setImageDrawable(getResources().getDrawable(R.drawable.paint)); |
3 |
currPaint=(ImageButton)view; |
Conclusión
Ahora puedes ejecutar la aplicación y dibujar en el lienzo, eligiendo los colores para dibujar. Deberías ver que los botones de la paleta de colores reflejan el color elegido actualmente. En este tutorial hemos trabajado a través de las características esenciales de cualquier aplicación de dibujo táctil para Android, por lo que ahora debes tener las habilidades básicas para implementar tus propias funciones de dibujo en otras aplicaciones. En la parte final de la serie implementaremos el borrado, selección de los tamaños de pincel y borrador, guardando dibujos y comenzando nuevos dibujos.



