miércoles, 23 de noviembre de 2011

Mensajes Toast personalizados V2.0

Buenos días a todos,

ayer publique la primera versión de como hacer mensajes Toast personalizados. En esa publicación indicaba que había varias cosas que no sabia como solucionar, pues nada, hoy pongo la solución a estos problemas, espero que os guste.

Para realizar los mensajes toast personalizados que yo estaba buscando, debemos realizar los siguientes pasos:

1- Crear el layout (vista) que luego asignaremos al Toast.
2- Crear el xml (borde) donde indicaremos como tienen que ser los bordes para e mensaje.
3- Introduciremos el código Java necesario para cargar la vista y poder poner el mensaje que queramos en cada momento.
4- Llevaremos todo esto a una clase static, para compartir el mensaje en todo momento, y así tener un control sobre él para hacer que desaparezca el mensaje cuando creamos oportuno.

Este ultimo paso lo considero indispensable, ya que sino nos pasara que pulsaremos multiples veces sobre un botón, y estaremos viendo dicho Toast durante un rato hasta que se muestren todos. Para evitar que pueda pasar esto, y para evitar que el Toast se siga mostrando incluso después de abandonar la pantalla donde se mostró vamos ha realizar el paso 4.

Este ultimo paso es opcional, ya que aunque yo lo considero útil no tiene por que servir o gustar a todo el mundo.

PASO 1:
Crearemos el layout que sera la vista tal y como queremos que se muestre en los mensajes.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/toast_layout_root"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:layout_gravity="center"
    android:layout_marginLeft="20px"
    android:layout_marginRight="20px"
    android:background="#0FFF"
    android:orientation="horizontal"
    android:padding="20dp" 
    android:gravity="center">
 <LinearLayout 
     android:layout_width="wrap_content"
     android:layout_height="wrap_content"
     android:layout_gravity="center"
     android:background="@drawable/borde"
    android:orientation="horizontal"
     >
     <ImageView
         android:id="@+id/toastImagen"
         android:layout_width="58dp"
         android:layout_height="58dp"
         android:src="@drawable/icon" android:layout_gravity="center"/>
     <TextView android:id="@+id/toastText"
              android:layout_width="wrap_content"
              android:layout_height="wrap_content"
              android:textColor="#000"
              android:gravity="center" android:layout_marginRight="10px" android:layout_marginLeft="10px" android:layout_gravity="center"/>
 </LinearLayout>
</LinearLayout>

Como se puede observar a diferencia de la entrada anterior en este caso la vista esta compuesta por un LinearLayout dentro de otro, esto es necesario si queremos que nuestro mensaje tenga un margen o separación entre los laterales del terminal y él.

El LinearLayout mas externo sera el que cargaremos en la clase java, de ahí que tenga un id. También se puede observar que hemos puesto un background a dicho layout, esto es necesario si queremos que el fondo sea transparente. Y mediante el padding indicamos la distancia que habrá entre el borde del terminal y el mensaje que mostramos.

El LinearLayout mas interior sera el que contendrá el background encargado de hacer el borde y el color del fondo del mensaje.

El resto de componentes es adaptable, ya que en nuestro caso hemos puesto una imagen y un texto, pero se podría modificar y añadir otra clase de objetos.

Ahora seguimos con el paso 2, que es el encargado de crear el borde y el fondo del mensaje.

PASO 2:

En este paso creamos el xml que contendrá el borde y el fondo del mensaje. Para ello crearemos un xml en el directorio res/drawable, el cual tendrá el siguiente código.

<?xml version="1.0" encoding="UTF-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
    <stroke android:width="4dp" android:color="#FAAA" />
    <padding android:left="7dp" android:top="7dp"
            android:right="7dp" android:bottom="7dp" />
    <corners android:radius="4dp" />
    <solid android:color="#DAAA" />
</shape>

PASO 3:
Ahora pondremos el código necesario para hacer uso de la vista que hemos creado y poder montar nuestros Toast personalizados.

Para ello necesitaremos obtener la vista mediante el siguiente codigo:


Mediante este codigo obtenemos la vista, que posteriormente pasaremos al toast con esto:
Toast toast = new Toast(ctx);
     toast.setView(layout);
     text = (TextView) vista.findViewById(R.id.toastText);
     text.setText("texto a mostar");
     toast.show();

Ya con esto es suficiente para poder personalizar los mensajes, pero claro para mis desarrollos necesito una vuelta de tuerca mas, ya que con lo que hemos hecho hasta ahora lo que conseguimos es personalizar los mensajes, pero no evitamos que si pulsamos repetidamente un elemento que muestre el toast este se tenga que mostrar tantas veces como pulsaciones hubo, ni evita que si se cambia de ventana mientras se muestra el mensaje, este se siga viendo en la siguiente ventana a la que vayamos.

Para poder solucionar esto yo he realizado el paso 4, a ver que os parece.

PASO 4:
Para realizar este paso crearemos una clase static, la cual tendrá el toast que generaremos al iniciar la aplicación, la vista, la cual cargaremos nada mas empezar, y algunos objetos mas.

El código de la clase static será:
package es.atndroider.qui.util;
import android.content.Context;
import android.graphics.Paint.Join;
import android.view.Gravity;
import android.view.View;
import android.widget.TextView;
import android.widget.Toast;
import es.atndroider.qui.R;

public class MensajeToast {
 private static Toast toast = null;
 private static Context ctx = null;
 private static View vista = null;
 private static TextView text = null;

 public static void prepararVista(Context c, View view){
  if (ctx==null)
   ctx = c;
  if (vista==null)
   vista=view;
  text = (TextView) vista.findViewById(R.id.toastText);
  toast = Toast.makeText(ctx, "", Toast.LENGTH_LONG);
  toast.setView(vista);
 }

 public static void mostrarMensajeLargo(int mensaje){
  mostrarMensaje(mensaje, Toast.LENGTH_LONG);
 }

 public static void mostrarMensajeCorto(int mensaje){
  mostrarMensaje(mensaje, Toast.LENGTH_SHORT);
 }

 private static void mostrarMensaje(int mensaje, int duration) {
  ctx = ctx.getApplicationContext();
  Thread th = null;
  if (toast!=null){
   th = new Thread(new Runnable() {
    @Override
    public void run() {
     toast.cancel();
    }
   });
   th.start();
  }
  try {
   if (th!=null)
    th.join();
  } catch (InterruptedException e) {}
  text.setText(mensaje);
  toast.setDuration(duration);
  toast.show();
 }
}

Como se puede observar, la clase necesita una inicialización que vamos a realizar llamando al método prepararVista() al cual le pasaremos el contexto global de la aplicación y la vista obtenida a partir del layout que creamos al principio.
  LayoutInflater inflater =  getLayoutInflater();
  View layout = inflater.inflate(R.layout.toast_layout,
                                 (ViewGroup) findViewById(R.id.toast_layout_root));
  MensajeToast.prepararVista(getApplicationContext(),layout);
A partir de este momento cada vez que queramos escribir un mensaje Toast llamaremos a MensajeToast.mostrarMensaje(R.string.mensaje) el cual cancelara el toast anterior (si es que se esta mostrando), y cambiara el texto por el nuevo mensaje.

Se pueden hacer variantes, como cambiar la imagen que se muestre y otras cosas, pero eso ya queda a la imaginación de cada uno.

Espero que os haya gustado todo lo que he puesto, y si veis algo raro, no dudéis en corregidme.

Nos vemos, espero que pronto.

martes, 22 de noviembre de 2011

Mensajes Toast personalizados

Después de mucho buscar y realizar muchas pruebas, he llegado a la conclusión de que quedan bonitos los menajes Toast personalizados, es decir, dando la posibilidad de incluir una imagen al mensaje, o incluso cambiar la ubicación del mismo.

Para ello voy a poner los distintos pasos a seguir para poder llegar a esto:


Para poder llegar a esto necesitamos hacer lo siguiente:
1- Crear un xml en res/layout, yo lo he creado con el nombre toast_layout.xml, con el siguiente código:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/toast_layout_root"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:layout_gravity="center"
    android:layout_marginLeft="20px"
    android:layout_marginRight="20px"
    android:background="@drawable/borde"
    android:fitsSystemWindows="true"
    android:orientation="horizontal"
    android:padding="10dp"
    android:gravity="center">
    <ImageView android:id="@+id/toastImagen"
        android:layout_width="58dp"
        android:layout_height="99dp"
        android:layout_marginRight="10dp"
        android:layout_marginLeft="10dp"
        android:src="@drawable/icon" />
    <TextView android:id="@+id/toastText"
              android:layout_width="wrap_content"
              android:layout_height="fill_parent"
              android:textColor="#FFF"
              android:text="esto es uyna prueba" android:gravity="center"/>
</LinearLayout>


En mi ejemplo, al utilizar una imagen, la cual es res/drawable/icon.png, y ser esa imagen mayor que el tamaño que quiero utilizar he preferido darle un tamaño de forma manual, como se ve en las lineas 15 y 16.

2- Asignar el borde al Toast, para ello creamos en res/drawable un xml, en mi caso borde.xml, el cual asignamos al background del linearlayout que contiene el Toast (linea 9). Tendra el siguiente código:
<?xml version="1.0" encoding="UTF-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
    <stroke android:width="2dp" android:color="#FFFFFFFF" />
    <padding android:left="3dp" android:top="3dp"
            android:right="3dp" android:bottom="3dp" />
    <corners android:radius="2dp" />
    <solid android:color="#DAAA" />
</shape>

En este código definimos el grosor de las lineas del borde (lineas 4 y 5) y el grosor de las esquinas (linea 6). Así como el color del fondo que tendrá (linea 7).

3- Lo ultimo es asignar al Toast que estemos utilizando la vista que crearemos con el linearlayout que tenemos al principio.

Para ello debemos realizar lo siguiente:
LayoutInflater inflater =  getLayoutInflater();
 View layout = inflater.inflate(R.layout.toast_layout,
                        (ViewGroup) findViewById(R.id.toast_layout_root));
 Toast toast = new Toast(ctx);
 toast.setView(layout);
 text = (TextView) vista.findViewById(R.id.toastText);
 text.setText("texto a mostar");
 toast.show();

En las lineas 2 y 3 obtendremos la vista (LinearLayout en nuestro caso) que se incluira en el Toast.

Cada vez que se quiera escribir en el Toast deberemos utilizar text.setText("Texto"); para modificarlo. Esto nos lleva a lo siguiente, un Toast persistente para asi poder cancelar los mensajes entre una ventana y otra. Pero eso se tratara en otro momento, que todavia estoy mirando como conseguir que el ancho de estos Toast personalizados sea menor que el ancho de los terminales.

Nos vemos.

martes, 7 de junio de 2011

Nueva aplicación - Juego grupal

Buenas, hace mucho que no escribo, casi 2 meses, pero en este tiempo he estado enfrascado en varios asuntos. He probado diferentes metodos para pintar un reloj de arena "real" en la pantalla, pero siempre me he chocado con el problema del rendimieto, ya que tarda mucho en pintar y poco en actualizar la fisica, por lo que no consigo avanzar en este asunto.

Dado mi estancamiento decidi retomar un proyecto que empece hace ya un tiempo. Y ya casi lo he terminado. Es un juego grupal donde se cruzan la inteligenca, la perspicacion y los conocimientos.

Este juego tiene una particularidad, y es que todos los usuarios juegan con el mismo terminal, es decir, cada usuario realiza su turno y posteriormente le pasa el terminal al jugador siguiente, y asi sucesivamente hasta terminar la partida.

En breve publicare la aplicación en el market y pondre aqui las reseñas y una explicación de como se juega.

Nos vemos dentro de poco

lunes, 11 de abril de 2011

Nada mas salir y ya toca actualización

Hola de nuevo,

puff este ritmo es mareante, dos entradas un mismo día, esto no creo que se repita en mucho tiempo.

Pues eso, que acabo de subir mi primera aplicación al Market de Android y ya he tenido que sacar una nueva actualización. Como bien me ha indicado osvasu, debería dejar que se pudiera pasar la aplicación del dispositivo a la tarjeta SD, así que dicho y hecho. Ya he actualizado a la versión 1.01, y lo único que incluyes es eso, bueno eso exactamente no, ahora la aplicación se instala por defecto en la tarjeta SD, siempre y cuando pueda hacerlo, en otro caso se instala en el dispositivo.

Y nada mas, eso es todo el cambio que he realizado, y para los que quieran saber como se hace os dejo el poco código que he tenido que modificar para ello.

Dentro del fichero AndroidManifest.xml he añadido lo siguiente:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
·
·
·
android:installLocation="preferExternal">

Mi primera publicación en el Market

Hola a todos,
pues como bien indica en titulo ya he publicado mi primera aplicación en el market. He publicado un cronometro de cuenta atras, lo he llamado reloj de arena, ya que la idea inicial era que la cuenta atras se hiciese con un reloj de arena, pero mis limitaciones en el desarrollo de aplicaciones que requieran aptitudes graficas pues me ha llevado a que en vez de un reloj de arena real la cuenta atras se lleve a cabo con un reloj digital. Promto que para futuras versiones modificare esto y conseguire que sea un reloj de arena de verdad, con sus granitos callendo y esas cosas.

Bueno, como iba diciendo, es un cronometro de cuenta atras, la idea surgio debidoa que mis amigo y yo tenemos muchos juegos de mesa, pero algunos de ellos o se ha perdido el reloj, o han sido manufacturados (ehcos por nosotros) y no disponemos de reloj de arena con la duración precisa para cada uno de los juegos, asi que decidi realizar este desarrollo, a mi con esto me vale, la verdad, cumple su función perfectamente, y ya no tenemos problemas de tener que estar con un reloj cronometrando a mano, pero vamos, si alguien piensa que es mejorable, pues nada, estoy abierto a las ideas de todo el que quiera aportarlas.

Su funcionamiento no requiere muchas explicaciones, en la primera pantalla que nos aparece metemos el tiempo que quieremos cronometrar, y le damos al boton comenzar, en ese momento empieza la cuenta atras, si poralgun motivo necesitamos para el tiempo tenemos en boton Parar de la segunda pantalla, que parar el tiempo y se cambiara el boton para poder continuar desde el momento en que se paro. Y si queremos reiniciar el tiempo, o el tiempo ya se ha acabado, y tenemos que volver a contar el mismo tiempo pues con reset empezara de nuevo la cuenta atras.

No os aburro mas, os dejo capturas de sus unicas dos pantallas.

primera pantalla
segunda pantalla













Para el que quiera descargarselo a su dispositivo android os dejo el enlace:
https://market.android.com/details?id=es.atndroider.relojDeArena

Y y a sabeis, si teneis algun consego o sugerencia no dudeis en comunicarmelo.

Nos vemos en un tiempo, a ver si termino otras aplicaciones que tengo etre manos.

viernes, 25 de febrero de 2011

Empezamos

Muy buenas,

llevo unos meses programando Android, la verdad es que todavía estoy muy verde, pero se hace lo que se puede, o por lo menos se intenta.

Por ahora he echo un par de aplicaciones, un cronometro que utilizo en los juegos de mesa que necesitan tiempo y no tenemos el reloj del juego, y otra aplicación "Super-Loto" que he realizado con mi amigo DarkAndroider.

A ver si saco tiempo y pongo algunas capturas de ambos proyectos y una pequeña descripción de cada uno de ellos.