Feb'11
23

Hace una semana comentábamos el modo de crear un ListView para Android con, como mínimo, un CheckBox en cada fila de la lista. Este mini tutorial de hoy, en el que vamos a explicar como marcar de una todos los CheckBox de un ListView, vamos a basarnos en el contenido explicado en dicho artículo.

En principio la metodología parece sencilla, en nuestro fichero main.xml, además de declarar un ListView, declaramos en la parte inferior un CheckBox cuyo comportamiento determinaremos más adelante, de manera que el contenido del main.xml quedaría de la siguiente manera:

main.xml

<?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">
    <ListView
    	android:id="@+id/list"
    	android:layout_width="fill_parent"
    	android:layout_height="wrap_content"
        android:layout_weight="1"
        android:drawSelectorOnTop="false"/>
	<CheckBox
		android:id="@+id/chkSelectAll"
		android:text="@string/chkSelectAll"
		android:visibility="visible"
		android:layout_width="fill_parent"
		android:layout_height="wrap_content"/>
</LinearLayout>

Hasta aquí todo ha sido coser y cantar, de nuevo hemos de definir un fichero con el Layout de cada una de las filas de lo que será nuestro ListView, en nuestro caso item.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
	android:layout_height="wrap_content"
	android:layout_width="fill_parent">
	<CheckBox
		android:id="@+id/chkItem"
		android:visibility="visible"
		android:layout_width="fill_parent"
		android:layout_height="wrap_content"/>
</LinearLayout>

Una vez que tenemos hecho esto nos bastará con definir el comportamiento de la clase principal para que al marchar el chkSelectAll se marquen todos los CheckBox de la lista, para ello en un principio, con poner el array que determina el valor de cada CheckBox a true o false, en función del caso, debería sernos suficiente. Para ello añadiríamos en el onCreate las liguientes lineas:

        chkAll = (CheckBox)findViewById(R.id.chkSelectAll);
        chkAll.setOnCheckedChangeListener(new OnCheckedChangeListener(){
			@Override
			public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
				for (int i = 0; i < adapter.getItemsLength(); i++) {
    	                                adapter.set(i, b);
    	                        }
			}
        });

El problema nos lo encontramos cuando lo que queremos es que además de marcarlos en el sistema queremos que se visualicen los CheckBox marcados directamente, para ello, lo que podemos hacer (AVISO: es una solución un poco cutre y simplemente para salir del paso) es reasignar el adaptador, para lo que después del for podríamos añadir las siguientes lineas:

        int pos = list.getFirstVisiblePosition();
    	list.setAdapter(adapter);
    	list.setSelection(pos);

Si ahora compilamos y ejecutamos el código podremos observar como el comportamiento es el deseado.

Si disfrutaste del artículo, puedes suscríbete a nuestro feed RSS
Categoría(s): Android, Manuales, Programación
Feb'11
16

Android es un gran sistema operativo para móviles que le supone una competencia directa al iOS, y por lo tanto meterse como programador en su mundo puede ser algo muy atractivo. Pero como programadores más o menos experimentados sabemos que no todo es un paseo, tal y como algunos pretenden plantearlo; siempre surgen problemas que habremos de solucionar. Hoy, vamos a ver como evitar que, al tener un ListView en el que cada fila contenga un CheckBox, al hacer scroll, los elementos de la parte no visible se marquen al marcar uno de la parte visible de manera automática.

¿Por qué?

Esto sucede porque Android reutiliza las mismas vistas una y otra vez a la hora de pintar los elementos en pantalla, de manera que aunque el CheckBox que ha de mostrar no está seleccionado, se mostrará como tal dado que uno visible anteriormente ya lo estaba. De este modo se ahorra una gran cantidad de ciclos de CPU a la hora de generar la imagen que se va a mostrar.

Cómo podemos ver, el comportamiento por defecto del sistema operativo no siempre nos viene bien ya que, en casos como este, puede dar lugar a confusiones en el usuario final de la aplicación.

Solución

La manera de solucionar este pequeño inconveniente, aunque no de la forma más óptima, es tan simple como establecer a mano el valor del CheckBox que ha de mostrarse en cada momento, para ello tendremos que apoyarnos en una serie de clases y ficheros XML.

Antes de nada, vamos a analizar los ficheros que componen nuestro Layout, es decir, el que establece la distribución de la pantalla principal y el que establece el aspecto de cada una de las filas.

main.xml

<?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">
<ListView
android:id="@+id/list"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:drawSelectorOnTop="false"/>
</LinearLayout>

row.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_height="wrap_content"
android:layout_width="fill_parent">
<CheckBox
android:id="@+id/chkItem"
android:visibility="visible"
android:layout_width="fill_parent"
android:layout_height="wrap_content"/>
</LinearLayout>

Tal y como se puede observar, hasta este momento no hemos hecho más que definir dos layouts, uno que contiene un ListView y otro que contiene el CheckBox que ha de aparecer en cada fila.

Prosigamos programando nuestra clase Java para manejar estos Layouts:

package org.dipler.chkList;

import java.util.ArrayList;

import android.app.Activity;
import android.content.Context;
import android.database.Cursor;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.ListView;
import android.widget.CompoundButton.OnCheckedChangeListener;

public class Main extends Activity {
private ChkListAdapter adapter;
private ListView list;
private CheckBox chkAll;

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
list = (ListView)findViewById(R.id.list);
fillList();
}

private void fillList() {
int num = 50;
adapter = new ChkListAdapter(num);
for(int i = 0; i < num; i++){
adapter.addItem(new Item(String.valueOf(i), "item number " + i));
}
list.setAdapter(adapter);
}

private class ChkListAdapter extends BaseAdapter {
private ArrayList<Item> items = new ArrayList<Item>();
private LayoutInflater inflater;
private boolean[] itemSelection;
public ChkListAdapter(int size) {
inflater = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);
this.itemSelection = new boolean[size];
}

public void addItem(final Item item) {
items.add(item);
notifyDataSetChanged();
}

@Override
public int getCount() {
return items.size();
}

@Override
public String getItem(int position) {
return items.get(position).toString();
}

@Override
public long getItemId(int position) {
return position;
}

@Override
public View getView(final int position, View convertView, ViewGroup parent) {
convertView = inflater.inflate(R.layout.row, null);
final ViewHolder holder = new ViewHolder();
holder.chkItem = (CheckBox)convertView.findViewById(R.id.chkItem);
holder.chkItem.setOnCheckedChangeListener(new OnCheckedChangeListener(){
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
itemSelection[position] = holder.chkItem.isChecked();
}
});

holder.chkItem.setChecked(itemSelection[position]);
convertView.setTag(holder);
holder.chkItem.setText(getItem(position));
return convertView;
}

public int getItemsLength() {
if(itemSelection == null) return 0;
return itemSelection.length;
}

public void set(int i, boolean b) {
itemSelection[i] = b;
}

}

public static class ViewHolder {
public CheckBox chkItem;
}

}

Como podemos observar el la, bueno, las clases Java que hemos declarado tenemos:

  • La clase Activity principal que utiliza el Layout main.xml y que en el método onCreate() rellena el ListView con elementos, en nuestro caso de tipo Item (Item es una clase cualquiera con dos atributos, un id y un texto)
  • El adapter, que es la clase que se va a dedicar a repintar las filas tantas veces como sea necesario llamando al método getView() en cada una de esas ocasiones.
  • La clase ViewHolder que nos facilita el trabajo con la clase Row, esta clase no es en sí necesaria, pero vi la idea en amberfog y me gustó, de hecho de esta misma página obtuve una visión mucho más clara del funcionamiento de estos artificios llamados “Views”

El procedimiento para evitar que se marquen solos los CheckBox que cumplen el periodo, es sencillo, llevamos un array de booleanos en el que establecemos el estado de cada elemento de la lista confome cambia el valor del CheckBox, de manera que cada vez quedeseemos mostrar dicho elemento, el método getView(), en lugar de pintar como cree que debería pintar estos CheckBox, los muestra marcados o desmarcados en función del array que hemos creado y que vamos actualizando dinámicamente.

El método propuesto no es el más eficiente que nos podamos encontrar, pero funciona y nos puede ayudar a salir del paso.

Si disfrutaste del artículo, puedes suscríbete a nuestro feed RSS
Categoría(s): Android, Manuales, Programación
Feb'11
10

http://diary.dipler.org

Como ya sabréis, las versiones de Diary 0.2.x están girando en torno a los diferentes tipos de entradas que podemos tener, así como en una mejora del rendimiento y de la seguridad que presenta la aplicación para permitir al usuario utilizar de una forma sencilla y práctica la aplicación sin tener que preocuparse de nada en absoluto. Dentro de las mejoras podemos diferenciar las de dos tipos:

  • De usuario (mejora la experiencia del usuario para con la aplicación)
    • Nueva interfaz de usuario
    • Nueva interfaz de búsqueda con nuevos filtros
    • Nuevo estilo de marcado de tareas pendientes y terminadas (imágenes en lugar de chekbox)
  • De servicio (mejora la calidad del servicio de forma transparente al usuario)
    • Ajax combinado con XML
    • Mayor seguridad a la hora de intentar replicar sesiones

Por el momento la aplicación está optimizada, como ya hemos dicho, para navegadores modernos, es decir, últimas versiones de Chrome y Firefox, en este último caso, y para sacarle el máximo jugo a la interfaz, será necesario el uso de Firefox 4.0

http://diary.dipler.org

Si disfrutaste del artículo, puedes suscríbete a nuestro feed RSS
Etiqueta(s):
Categoría(s): PHP, Producción propia, Programas
Feb'11
9

Muchos son los manuales que a día de hoy nos “enseñan”, o al menos eso dicen, a publicar con todo detalle los pasos para publicar nuestras aplicaciones para android en el market, y no digo que no sea cierta dicha aseveración, sino que, además deberían contar algunos inconvenientes a la hora de hacerlo, vamos a intentar proponer estos baches que a mi me han hecho perder un poco de tiempo para que no tengáis que perderlo vosotros también.

Este artículo parte de que todo lo que pone en el resto de páginas lo sabéis y no tenéis demasiado problema a la hora de hacer (en caso de dudas, preguntad sin temor en los comentarios de este artículo).

Lo más probable, es que si estás leyendo este artículo es que desarrolles aplicaciones para dispositivos con una versión de Android instalada superior a la 1.5.

A la hora de publicar para estas versiones aplicaciones hemos de tener en cuenta varios parámetros de fichero AndroidManifest.xml y, es que, para que se publique en el android para todos los dispositivos tendremos que decirlo expresamente en este fichero:

<manifest ...>
<uses-sdk android:minSdkVersion="4" />
 <supports-screens
 android:largeScreens="true"
 android:normalScreens="true"
 android:smallScreens="true"
 android:anyDensity="true" />

En estas líneas estamos diciendo que independientemente del tipo de pantalla de nuestro dispositivo, la aplicación va a ser compatible. Si no incluimos estas líneas, veremos como nuestra aplicación aparece en el Market para pantallas normales y grandes, pero no para pequeñas, es decir, en mi caso, la aplicación no se mostraba para mi HTC Wildfire, dispositivo en el que había estado haciendo todo el proceso de depurado de la aplicación.

Por otra parte, si deseamos publicar una aplicación de pago, deberemos tener una empresa registrada para darla como dato en la página de Google Checkout, la cual nos serviría para recibir pagos. Como alternativa recomiendo hacer uso de sistemas publicitarios en caso de que deseemos sacar algo de dinero de la aplicación y no tengamos empresa a la que asociar nuestra cuenta.

Si disfrutaste del artículo, puedes suscríbete a nuestro feed RSS
Categoría(s): Android, Manuales
Feb'11
3

http://diary.dipler.org

Como ya comenté en el post de introducción de Diary 0.1.2, esa versión no era nada más que un aperitivo de la que estaba desarrollando en ese momento y, dado que algunas personas me recordaron lo incómodo que era el cambio de hora en los artículos escritos hice una pre-versión estable y la subí, pero no traía grandes cambios; esta sí:

  • Las tareas pueden marcarse como terminadas o no utilizando el checkbox que hay a la izquierda del texto que hemos introducido (más tarde se añadirá búsqueda según el estado de las mismas)
  • Mejorados los logs internos de funcionamiento
  • Coloreadas las entradas de contenido en función del tipo
    • Diario: borde gris
    • Tarea: borde rojo
    • Idea: borde azul
  • Mejorado el sistema de funcionamiento de ajax, basándose ahora en el intercambio de ficheros xml sencillos, permitiendo así gestionar varias partes de la ventana con una sola petición y por ende, mejorando la experiencia de usuario
  • Añadido panel oculto en la parte superior que muestra mensajes de estado de la aplicación, estos pueden ser de tres tipos
    • OK
    • Alerta
    • Error

http://diary.dipler.org

Si disfrutaste del artículo, puedes suscríbete a nuestro feed RSS
Etiqueta(s):
Categoría(s): PHP, Producción propia, Programas
Feb'11
1

http://diary.dipler.org

Me complace presentarles la versión 0.1.2 de Diary. Esta versión ya mencionada se ha adelantado un poco a lo que estaba previsto por los comentarios de algunas de las personas que utilizan la herramienta, entre sus mejoras tenemos:

  • Muestra de la hora local de Madrid por el momento en lugar de la costa oeste de Estados Unidos (fecha que se estaba mostrando hasta ahora)
  • Posibilidad de guardar y buscar entradas por tipo, en un futuro no muy lejano se pretende permitir al usuario marcar las tareas como terminadas y las ideas con estados.
    • Log: función de diario
    • Idea: nos permite almacenar fácilmente las ideas que vamos teniendo
    • Tarea: nos permite almacenar las tareas que debemos hacer en un futuro y no queramos olvidarnos

http://diary.dipler.org

Si disfrutaste del artículo, puedes suscríbete a nuestro feed RSS
Etiqueta(s):
Categoría(s): PHP, Producción propia, Programas
Jan'11
29

Sagrada Familia

El fin de pasado anterior estuve en Barcelona con unos amigos para ver el Mare Nostrum y la ciudad entre otras cosas, a continuación os dejo, como de costumbre un enlace a mi galería de Flickr para los que deseen ver las fotos.

Si disfrutaste del artículo, puedes suscríbete a nuestro feed RSS
Categoría(s): Fotografía
Jan'11
10

http://diary.dipler.org

Fugaz entrada para informar de la actualización de la aplicación de Diary para corregir dos errores leves:

  • Los mensajes de más de una línea se muestran bien tras ser guardados
  • Eliminado el autofocus del formulario de registro en el campo del correo electrónico.

http://diary.dipler.org

Si disfrutaste del artículo, puedes suscríbete a nuestro feed RSS
Etiqueta(s):
Categoría(s): Producción propia, Programas
Jan'11
8

http://diary.dipler.org

Hace ya un tiempo, un amigo me preguntó acerca del día en el que había hecho una determinada actividad y no fui capaz de responderle, no suelo fijarme en las fechas en las que hago las cosas; el problema quedaría ahí de no ser porque si te roban una cuenta de correo electrónico te preguntan sobre la fecha aproximada en la que creaste la cuenta y así en muchos otros ámbitos; también cabe la posibilidad de que hayas establecido por sistema llevar un diario o simplemente que desees empezar a llevar uno.

Si la respuesta a alguna de estas preguntas es sí, eres un perfecto candidato para utilizar Diary, una aplicación muy sencilla que llevo desarrollando ya unos meses para uso exclusivamente personal pero que, después de que un amigo me dijese que le parecía una idea interesante y que quería usarlo también, hoy he abierto al público general para que pueda ser utilizada por aquellas personas que piensen que es una aplicación interesante para ellos.

¿Qué es Diary?

Diary es una aplicación escrita íntegramente en HTML5, PHP y Javascript apoyándose en hojas de estilo CSS3 y una base de datos MySQL, por lo que para poder visualizarlo perfectamente hará falta un navegador que soporte HTML5 y CSS3 (lo cual, sinceramente, no es muy complicado, todos los navegadores modernos deberían visualzarlo sin problema alguno.

¿Porqué no es compatible con todos los navegadores de la “historia”?

Muy sencillo, nació como una aplicación personal, y por ahora sigue siéndolo, si veo que a la gente le interesa y se va registrando gente, la aplicación irá creciendo, entre otras cosas, en compatibilidad con navegadores.

¿En qué se diferencia de un blog, Facebook o Twitter?

Es una aplicación de uso privado para el usuario registrado, el usuario que escribe algo podrá verlo de varias maneras, pero nadie más tendrá ese privilegio, por así decirlo es un diario en toda regla para el usuario que lo utilice con la ventaja de que está en la nube y puede ser accedido desde cualquier navegador moderno para insertar entradas nuevas a nuestra lista.

Es una aplicación muy simple ¿alguna mejora futura?

Yo soy de los que utilizan infinidad de aplicaciones de la web para escribir y leer cosas, así que una de las ideas que podrían ser interesantes en esta aplicación es permitir publicar (mediante un botón especial dentro del diario) una entrada determinada en redes sociales como Facebook o Twitter.

Otra mejora que se me había ocurrido es no solo utilizarlo como diario de cosas hechas, sino como lista de tareas pendientes.

Manual de uso

Continue reading “Diary 0.1” »

Si disfrutaste del artículo, puedes suscríbete a nuestro feed RSS
Etiqueta(s):
Categoría(s): PHP, Producción propia, Programas, Web
Dec'10
28

Recientemente me comprometí a continuar 18 meses más con vodafone por obtener a cambio un HTC Wildfire “gratis”. Cuando uno firma un contrato de estas características es consciente de que está a merced de la operadora en cuestión (Vodafone en mi caso). Mi experiencia con terminales anteriores, como por ejemplo el Samsung Omnia i900, es que entre otras cosas capadas está la posibilidad de actualizar el sistema operativo que viene instalado en el equipo a la última versión sin tener que enviarlo al servicio técnico.

Cuan grata fue mi sorpresa al darme cuenta de que no sólo no estaba capada esta opción en la HTC Wildfire, sino que se notifica automáticamente la existencia de la misma en el propio terminal. Tras seguir los pasos que se indican en el instalador (que a decir verdad son casi inexistentes) y después de esperar un rato considerable a que todo estuviese operativo de nuevo, ya tengo el terminal corriendo con Android 2.2 (Froyo) sin mayor problema.

Por esto he de reconocer la mejora en el servicio y las políticas de Vodafone en este aspecto ayudando, así, a mejorar la tan importante “experiencia del usuario”. Me han sorprendido.

Si disfrutaste del artículo, puedes suscríbete a nuestro feed RSS
Etiqueta(s): ,
Categoría(s): Reflexiones, Tecnología