La columna 80

El blog técnico-personal de Ángel J. Vico… en español

Diseños Android básicos: TableLayout

Posted by Ángel J. Vico en 5 de noviembre de 2012

Vamos a seguir avanzando en la creación de interfaces de usuario en Android, viendo otro de los diseños básicos que tenemos a nuestra disposición. Hasta ahora hemos visto diseños que permiten colocar vistas unas sobre otra o disponerlas en serie, una a continuación de otra, en horizontal o vertical. Con TableLayout añadimos una nueva dimensión, pudiendo disponer las vistas tanto verticalmente como horizontalmente, en forma de tabla.

Es necesario aclarar que no es el único diseño que permite esta distribución. Recientemente se ha añadido un nuevo diseño, GridLayout, que también permite distribuir las vistas en forma de tabla. Está disponible desde la versión 14 de la API de Android, que se corresponde con la versión 4.0 del sistema operativo (Ice Cream Sandwich), y es bastante más potente que TableLayout.

Por el momento, dado que usar GridLayout impide que la aplicación funcione en versiones anteriores, vamos a centrarnos en ver cómo se utiliza TableLayout y ya hablaremos de GridLayout más adelante.

Lo primero que es necesario destacar de TableLayout es que no tiene, estrictamente hablando, una estructura de tabla. En realidad, TableLayout es una especialización de LinearLayout. En concreto, de un LinearLayout vertical. Aunque con un comportamiento particularizado.

Al igual que en un LinearLayout, en un TableLayout se pueden incluir todo tipo de vistas. Sin embargo, hay una vista específica que sólo se puede utilizar en TableLayout y que es la que aporta la funcionalidad necesaria para crear la tabla: TableRow.

TableRow es, a su vez, otra especialización de LinearLayout. Esta vez de un LinearLayout horizontal. Así que resulta evidente que, lo que se nos vende como una estructura de tabla, es en realidad un grupo de LinearLayout horizontales dentro de un LinearLayout vertical.

Esta organización tampoco resulta tan extraña. De hecho, es muy similar a la de las tablas en HTML, con las que este diseño comparte otras características, como veremos a continuación.

Resulta evidente que cada TableRow representa una fila de la tabla y que las vistas que contengan harán las veces de columnas. En concreto, cada vista que se añade a un TableRow va a parar a una columna diferente. Por ese motivo se suele decir que cada celda de un TableLayout sólo puede contener una vista. No obstante, nada impide que cualquiera de esas vistas sea un diseño y que contenga, a su vez otras vistas dentro.

Lo que diferencia a TableLayout de una estructura similar creada con varios LinearLayout es el tratamiento global que le da a las vistas que se incluyen en todos los TableRow. Para empezar, aunque cada TableRow tenga una cantidad diferente de vistas en su interior, el conjunto se representará como una tabla donde todas las filas tienen el mismo número de columnas. La cantidad total de columnas que tendrá la tabla la determina el TableRow que más vistas incluya. De forma similar, el ancho de cada columna también vendrá determinado por la vista con mayor anchura de todas las incluidas en esa columna, aún estando en diferentes TableRow.

Propiedades del diseño

TableLayout hereda directamente de LinearLayout, por lo que dispone de todas sus propiedades. Aunque algunas, como android:orientation, carecen de efecto si se intentan usar aquí.

Por su parte, TableLayout tiene algunas propiedades exclusivas:

  • android:collapseColumns (setColumnCollapsed): permite ocultar columnas, como si no estuvieran en el diseño. El espacio que dejan lo ocupan el resto de columnas.
    La atributo XML (android:collapseColumns) permite ocultar más de una columna, indicando sus índices separados por comas. Por el contrario, el método (setColumnCollapsed) sólo permite ocultar o mostrar una columna cada vez, pasándole como parámetros el índice de la columna y un booleano que indica si la columna debe ocultarse (true) o mostrarse (false). En ambos casos el índice de la primera columna es el cero.
    En la siguientes capturas se muestra un TableLayout con tres columnas. En la primera se muestran las tres y en la segunda se ha ocultado la de índice 1 (la segunda):

    0036.01 - TableLayout con tres columnas0036.02 - TableLayout con una columna oculta

  • android:shrinkColumns (setColumnShrinkable): permite marcar una o más columnas como encogibles, de forma que su anchura se pueda reducir para adaptarse al tamaño del contenedor del TableLayout.
    Los parámetros tanto del atributo como del método son iguales a los de la propiedad anterior, pero aquí se añade también el valor "*", que permite marcar todas las columnas del TableLayout. Además, también disponemos del método setShrinkAllColumns, que permite marcar todas las columnas de la tabla como encogibles con una sola llamada.
    En las siguientes capturas se muestra un TableLayout con una celda de bastante anchura. En la segunda captura se ha marcado esa columna como encogible, de forma que quepan todas en la pantalla. Se pueden usar las propiedades del TextView, como veremos en un futuro post, para evitar que aumente la altura de la fila y, en su lugar, se recorte el texto (como se muestra en la tercera captura). En este caso se ha usado android:lines="1" android:scrollHorizontally="true" android:ellipsize="end".

    0036.03 - Columna muy grande0036.04 - Columna encogida0036.05 - Columna encogida y texto recortado

  • android:stretchColumns (setColumnStretchable): esta propiedad viene a ser la opuesta de la anterior, dado que permite que una columna se expanda aumentando su anchura hasta que todo el contenido del TableLayout ocupe la totalidad de la anchura de su contenedor.
    Los parámetros que toma son iguales que los de las propiedades anteriores, incluyendo el valor especial "*", para expandir todas las columnas. Además, aquí también disponemos de un método, setStretchAllColumns, que también permite marcar todas las columnas como expandibles de una vez.
    En las siguientes capturas se muestra un TableLayout con tres columnas, primero sin marcar ninguna como expandible, después marcando la de índice 2 (la tercera) y, finalmente, marcando la 0 y la 2:

    0036.01 - TableLayout con tres columnas0036.06 - Columna expandida0036.07 - Dos columnas expandidas

Las propiedades de encoger y expandir permiten que nuestro diseño se adapte perfectamente a cualquier tamaño de pantalla, al tiempo que controlamos cuáles de las columnas pueden variar su tamaño y cuáles no. Una misma columna se puede marcar con ambas propiedades, de forma que se adapte a tamaños más pequeños o más grandes. Si las propiedades se aplican a más de una columna, el tamaño que es necesario añadir o reducir se reparte de forma equitativa entre todas ellas.

Parámetros

Al igual que ocurre con las propiedades, TableLayout hereda también todos los parámetros de diseño de LinearLayout. Sin embargo, aunque existe una clase TableLayout.LayoutParams, no se define en ella ningún nuevo parámetro. Así que sólo disponemos de los que proporciona LinearLayout, y con algunas limitaciones.

Por ejemplo, el parámetro android:layout_width de los elementos que incluyamos en un TableLayout siempre tendrá el valor match_parent, ignorando cualquier otro valor que tratemos de poner. Aunque hay que tener en cuenta que, normalmente, dentro del TableLayout sólo pondremos elementos de tipo TableRow, por lo que es normal que la anchura de estos elementos siempre iguale a la del TableLayout.

En el caso del parámetro android:layout_height, también encontramos una diferencia: TableLayout no obliga a definirlos en los elementos que contiene (los TableRow). Si no se incluyen, se asume el valor wrap_content.

Parámetros de TableRow

Como ya hemos comentado, TableRow es también una especialización de LinearLayout. Por lo tanto, es un diseño. Y como tal puede proporcionar parámetros para que se utilicen como atributos de las vistas que se incluyan en él.

En concreto, la clase TableRow.LayoutParams proporciona dos:

  • android:layout_column: sirve para colocar la vista a la que se aplica en una columna diferente a la que le correspondería según el orden en el que se ha incluido en el TableRow. Hay que tener en cuenta que las columnas se numeran a partir del cero.
    La siguiente captura muestra el TableLayout de los ejemplos anteriores, pero con el valor "2" en el parámetro android:layout_column del segundo TextView de la filas 2 y 4, y en la primera vista de la tercera fila:

    0036.08 - Columnas desplazadas

    Como se puede observar, cuando nos saltamos alguna columna usando este atributo, las columnas posteriores se colocan a continuación, desplazándose también de la posición que les hubiera correspondido, e incluso aumentando el total de columnas del TableLayout si es necesario.
    Por otro lado, se ignoran los valores que son inferiores a la posición que le corresponde actualmente a la vista. En el ejemplo, hemos usado el valor "1" en el atributo android:layout_column del tercer TextView de la fila 3. Sin embargo, el orden de las vistas no se altera y el valor "1", al ser inferior al que le corresponde a esta vista (que sería "3"), simplemente se ignora.

  • android:layout_span: permite que una vista ocupe más de una columna. Tiene que tener un valor numérico igual o superior a "1". El valor "1" es el predeterminado.
    En la siguiente captura podemos verlo en acción. En este caso hemos hecho que la primera vista de la fila 2 ocupe dos columnas y que la segunda vista de la fila 3 ocupe tres columnas, usando los valores "2" y "3", respectivamente:

    0036.09 - Vistas que ocupan más de una columna

    Como se puede observar, aquí también se aumenta el número de columnas del TableLayout si es necesario.

Uso de TableLayout en XML

Veamos ahora un ejemplo de actividad cuyo diseño principal es un TableLayout:

0036.10 - Ejemplo de TableLayout

El código XML que permite crear esta tabla es el siguiente:

<?xml version="1.0" encoding="utf-8"?>
<TableLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/Tabla"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:stretchColumns="1" >

    <TableRow
        android:id="@+id/Cabecera"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content" >

        <TextView
            android:id="@+id/ColumnaAnio"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:padding="5px"
            android:text="Año"
            android:textColor="#005500"
            android:textSize="26sp" />

        <TextView
            android:id="@+id/ColumnaCiudad"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center_horizontal"
            android:padding="5px"
            android:text="Ciudad"
            android:textColor="#005500"
            android:textSize="26sp" />

        <TextView
            android:id="@+id/ColumnaOro"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:padding="5px"
            android:text="Oro"
            android:textColor="#005500"
            android:textSize="26sp" />

        <TextView
            android:id="@+id/ColumnaPlata"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:padding="5px"
            android:text="Plata"
            android:textColor="#005500"
            android:textSize="26sp" />

        <TextView
            android:id="@+id/ColumnaBronce"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:padding="5px"
            android:text="Bronce"
            android:textColor="#005500"
            android:textSize="26sp" />
    </TableRow>

    <TableRow
        android:id="@+id/SeparadorCabecera"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content" >

        <FrameLayout
            android:id="@+id/LineaCabecera"
            android:layout_width="fill_parent"
            android:layout_height="2px"
            android:layout_span="6"
            android:background="#FFFFFF" >
        </FrameLayout>
    </TableRow>

    <TableRow
        android:id="@+id/Fila1"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content" >

        <TextView
            android:id="@+id/Anio1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:gravity="center"
            android:text="1900"
            android:textSize="20sp" />

        <TextView
            android:id="@+id/Cuidad1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:gravity="center"
            android:text="París"
            android:textSize="20sp" />

        <TextView
            android:id="@+id/Oro1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:gravity="center"
            android:text="1"
            android:textSize="20sp" />
    </TableRow>

    <TableRow
        android:id="@+id/Fila2"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content" >

        <TextView
            android:id="@+id/Anio2"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:gravity="center"
            android:text="1976"
            android:textSize="20sp" />

        <TextView
            android:id="@+id/Cuidad2"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:gravity="center"
            android:text="Montreal"
            android:textSize="20sp" />

        <TextView
            android:id="@+id/Plata2"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_column="3"
            android:gravity="center"
            android:text="2"
            android:textSize="20sp" />
    </TableRow>

    <TableRow
        android:id="@+id/Fila3"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content" >

        <TextView
            android:id="@+id/Anio3"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:gravity="center"
            android:text="1992"
            android:textSize="20sp" />

        <TextView
            android:id="@+id/Cuidad3"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:gravity="center"
            android:text="Barcelona"
            android:textSize="20sp" />

        <TextView
            android:id="@+id/Oro3"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:gravity="center"
            android:text="13"
            android:textSize="20sp" />

        <TextView
            android:id="@+id/Plata3"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:gravity="center"
            android:text="7"
            android:textSize="20sp" />

        <TextView
            android:id="@+id/Bronce3"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:gravity="center"
            android:text="2"
            android:textSize="20sp" />
    </TableRow>

    <TableRow
        android:id="@+id/Fila4"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content" >

        <TextView
            android:id="@+id/Anio4"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:gravity="center"
            android:text="2012"
            android:textSize="20sp" />

        <TextView
            android:id="@+id/Cuidad4"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:gravity="center"
            android:text="Londres"
            android:textSize="20sp" />

        <TextView
            android:id="@+id/Oro4"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:gravity="center"
            android:text="3"
            android:textSize="20sp" />

        <TextView
            android:id="@+id/Plata4"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:gravity="center"
            android:text="10"
            android:textSize="20sp" />

        <TextView
            android:id="@+id/Bronce4"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:gravity="center"
            android:text="4"
            android:textSize="20sp" />
    </TableRow>

    <TableRow
        android:id="@+id/SeparadorTotales"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content" >

        <FrameLayout
            android:id="@+id/LineaTotales"
            android:layout_width="fill_parent"
            android:layout_height="2px"
            android:layout_span="5"
            android:background="#FFFFFF" >
        </FrameLayout>
    </TableRow>

    <TableRow
        android:id="@+id/Totales"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" >

        <TextView
            android:id="@+id/TextoTotal"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_span="2"
            android:gravity="right"
            android:text="Total"
            android:textColor="#0000CC"
            android:textSize="22sp" />

        <TextView
            android:id="@+id/OroTotal"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:gravity="center"
            android:text="17"
            android:textSize="22sp" />

        <TextView
            android:id="@+id/PlataTotal"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:gravity="center"
            android:text="19"
            android:textSize="22sp" />

        <TextView
            android:id="@+id/BronceTotal"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:gravity="center"
            android:text="6"
            android:textSize="22sp" />
    </TableRow>

</TableLayout>

Como se puede observar, la actividad contiene un único TableLayout que ocupa todo su espacio visible. Dentro del TableLayout se incluyen únicamente diseños TableRow, uno por cada fila. Y dentro de los TableRow se incluyen diversos TextView, con las cadenas de texto que se muestran en cada celda de la tabla.

La única excepción son los TableRow que se utilizan para las líneas separadoras (la que separa la cabecera de la tabla y la que separa la fila de totales). En estos TableRow se ha incluido un FrameLayout con una altura muy pequeña (2 píxeles) y con el fondo de color blanco.

Es una forma sencilla de crear líneas y se utiliza con frecuencia con todo tipo de diseños, no únicamente con TableLayout. Esto se debe a que, a diferencia de otros entornos, en Android los widgets no tienen propiedades específicas para los bordes. No podemos definir, como, por ejemplo, en HTML, el ancho, color y estilo de cada borde simplemente asignando valores a propiedades.

Esto no quiere decir que no se puedan mostrar bordes en las celdas de un TableLayout, sino que hacerlo resulta un poco más complejo de lo que cabría suponer. En Android los bordes forman parte de la imagen gráfica del widget, la cual se puede modificar mediante un tipo de recursos llamados dibujables (drawables). De estos recursos hablaremos en un futuro post.

Además de usar un FrameLayout para crear líneas, también podemos jugar con los colores de fondo del TableRow y el de los widgets de las celdas, junto con el padding, para simular los bordes. Aunque de esta forma las opciones de personalización son algo menores.

Ejemplo en Java

Como ya es habitual, ahora veremos la forma de crear la misma interfaz de usuario mediante código Java:

    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);

        // Datos para la tabla
        String cabeceras[] = { "Año", "Ciudad", "Oro", "Plata", "Bronce" };
        String datos[][] = { { "1900", "París", "1", "", "" },
                             { "1976", "Montreal", "", "2", "" },
                             { "1992", "Barcelona", "13", "7", "2" },
                             { "2012", "Londres", "3", "10", "4" } };

        // TableLayout (diseño principal de la actividad)
        TableLayout tabla = new TableLayout(this);
        tabla.setLayoutParams(new TableLayout.LayoutParams(
           LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT));
        tabla.setColumnStretchable(1, true);

        // Cabecera de la tabla
        TableRow cabecera = new TableRow(this);
        cabecera.setLayoutParams(new TableLayout.LayoutParams(
           LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT));
        tabla.addView(cabecera);

        // Textos de la cabecera
        for (int i = 0; i < 5; i++)
        {
           TextView columna = new TextView(this);
           columna.setLayoutParams(new TableRow.LayoutParams(
              LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
           columna.setText(cabeceras[i]);
           columna.setTextColor(Color.parseColor("#005500"));
           columna.setTextSize(TypedValue.COMPLEX_UNIT_SP, 26);
           columna.setGravity(Gravity.CENTER_HORIZONTAL);
           columna.setPadding(5, 5, 5, 5);
           cabecera.addView(columna);
        }

        // Línea que separa la cabecera de los datos
        TableRow separador_cabecera = new TableRow(this);
        separador_cabecera.setLayoutParams(new TableLayout.LayoutParams(
           LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT));
        FrameLayout linea_cabecera = new FrameLayout(this);
        TableRow.LayoutParams linea_cabecera_params =
           new TableRow.LayoutParams(LayoutParams.FILL_PARENT, 2);
        linea_cabecera_params.span = 6;
        linea_cabecera.setBackgroundColor(Color.parseColor("#FFFFFF"));
        separador_cabecera.addView(linea_cabecera, linea_cabecera_params);
        tabla.addView(separador_cabecera);

        // Array para los totales
        int valores_totales[] = { 0, 0, 0 };

        // Filas de datos
        for (int f = 0; f < 4; f++)
        {
           TableRow fila = new TableRow(this);

           for (int c = 0; c = 2) valores_totales[c-2] += Integer.parseInt(datos[f][c]);
              }
           }

           tabla.addView(fila);
        }

        // Línea que separa los datos de la fila de totales
        TableRow separador_totales = new TableRow(this);
        separador_totales.setLayoutParams(new TableLayout.LayoutParams(
           LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT));
        FrameLayout linea_totales = new FrameLayout(this);
        TableRow.LayoutParams linea_totales_params =
           new TableRow.LayoutParams(LayoutParams.FILL_PARENT, 2);
        linea_totales_params.span = 6;
        linea_totales.setBackgroundColor(Color.parseColor("#FFFFFF"));
        separador_totales.addView(linea_totales, linea_totales_params);
        tabla.addView(separador_totales);

        // Fila de totales
        TableRow totales = new TableRow(this);
        totales.setLayoutParams(new TableLayout.LayoutParams(
           LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT));

        TextView texto_total = new TextView(this);
        TableRow.LayoutParams texto_total_params =
           new TableRow.LayoutParams(
              LayoutParams.WRAP_CONTENT,
              LayoutParams.WRAP_CONTENT);
        texto_total_params.span = 2;
        texto_total.setText("Total");
        texto_total.setTextColor(Color.parseColor("#0000CC"));
        texto_total.setTextSize(TypedValue.COMPLEX_UNIT_SP, 22);
        texto_total.setGravity(Gravity.RIGHT);
        totales.addView(texto_total, texto_total_params);

        for (int i = 0; i < 3; i++)
        {
           TextView columna = new TextView(this);
           columna.setLayoutParams(new TableRow.LayoutParams(
              LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
           columna.setText(String.valueOf(valores_totales[i]));
           columna.setTextSize(TypedValue.COMPLEX_UNIT_SP, 22);
           columna.setGravity(Gravity.CENTER);
           totales.addView(columna);
        }

        tabla.addView(totales);

        // Añadimos la tabla a la actividad
        setContentView(tabla);
    }

En este caso me he creado varios arrays con la información que tiene que mostrarse en la tabla. Los recorro mediante bucles for, dentro de los cuales voy creando un widget para cada cadena de texto a mostrar. Además, los totales los calculo a medida que voy añadiendo las filas de datos, guardándolos en otro array para mostrarlos después en la última fila de la tabla.

En las filas de datos, las cadenas vacías las ignoro, pero cada widget lo asocio a la columna que le corresponde para que se coloque en su sitio, dejando columnas vacías si es necesario. Esto se hace mediante el atributo público column de la clase TableRow.LayoutParams.

Esta clase no dispone de un constructor que permita definir al ancho y alto del widget y, al mismo tiempo, asociarlo a una columna. Así que primero tenemos que crear el objeto, luego asignar el número de columna al atributo column y después asociarle el objeto con los parámetros al widget al incluirlo en el TableRow (en la llamada a addView).

Con el parámetro android:layout_span que necesitamos para que los FrameLayout que crean las líneas horizontales ocupen todo el ancho del TableLayout hay que hacer lo mismo: crear un objeto TableRow.LayoutParams, asignar el número de columnas a ocupar al atributo público span y asociar los parámetros al widget al llamar a addView para agregarlo al TableRow.

Por último, un detalle importante a tener en cuenta: si se va a crear un objeto LayoutParams para un TableRow, debe ser siempre de la clase TableRow.LayoutParams, aunque sólo se vaya a definir ancho y alto y no sea necesario utilizar ninguno de los parámetros propios del TableRow. Si usamos un objeto de la clase ViewGroup.LayoutParams el TableRow podría incluso no mostrarse en la actividad.

Recuerda que en esta página dispones de enlaces a todos los artículos sobre Android que he publicado en La columna 80.

6 comentarios to “Diseños Android básicos: TableLayout”

  1. cordobapadelMiguel said

    Hay una parte que no entiendo bien: “En la segunda captura se ha marcado esa columna como encogible, de forma que quepan todas en la pantalla. Se pueden usar las propiedades del TextView, como veremos en un futuro post, para evitar que aumente la altura de la fila y, en su lugar, se recorte el texto (como se muestra en la tercera captura). En este caso se ha usado android:lines=”1″ android:scrollHorizontally=”true” android:ellipsize=”end”.”
    Exactamente donde hay que poner estas lineas para por ejemplo yo que tengo unos textview no se expandan en altura, ¿hay otra manera?

    • Esas tres propiedades son del TextView, por lo que tienes que ponérselas a cada TextView que quieras que ocupe una sola línea:
      – android:lines=”1″ hace que el texto no se expanda a más de una línea. También puedes usar android:maxLines=”1″.
      – android:scrollHorizontally=”true” sirve para permitir que el texto ocupe más de la anchura que quieres para el TextView (o sea, para que no lo pase a la siguiente línea).
      – android:ellipsize=”end” sirve para que corte el texto y ponga puntos suspensivos indicando que el texto es más largo que lo que se muestra. Los puntos se pueden poner a la derecha (“end”), a la izquierda (“start”) o en medio (“middle”). También puedes hacer que el texto se corte sin poner puntos (“none”) o que se mueva de izquierda a derecha para poder leerlo todo cuando el campo reciba el foco (“marquee”).

      Hay otra opción, android:singleLine=”true”, que también sirve (equivale a las dos primeras de las que he utilizado), pero se considera obsoleta, por lo que no conviene utilizarla.

      Y supongo que también se podría forzar la altura de forma que sólo cupiera una línea de texto, pero esa alternativa es aún menos recomendable, por los problemas que puede dar cuando la aplicación se ejecute en pantallas con diferente resolución o densidad de píxeles.

      • sirven esas mismas propiedades para botones y editText?, las he probado y no consigo que funcionen. Muchas gracias.

      • En principio, esas propiedades son de la clase TextView, por lo que las clases Button y EditText las heredan.
        Aún así, dependiendo de la versión de Android puede que no funcionen correctamente.

        Prueba a usar android:maxLines=”1″ y android:inputMethod=”text”, en los EditText, o android:inputMethod=”none” en TextView o Button.

  2. Juan C said

    Qué tal buenas tardes, de casualidad alguno de ustedes sabe si es posible poder controlar el “focus” de manera “horizontal”?. Lo que quiero es lo siguiente:
    Tengo 1 TableLayout que contiene algunos TableRow y cada fila tiene únicamente 2 celdas que las estoy manejando como EditText, pero, me interesa que cuando escriban los datos se empiece a escribir en la posición 0,0, posteriormente en la (0,1),(1,0),(1,1)(2,0) y así sucesivamente. Les agradecería si me pudieran orientar, ya que estoy empezando con esto del mundo de la programación.

    De antemano les agradezco su fina atención.

    • La clase View dispone de una serie de propiedades que permiten controlar qué elemento obtiene el foco a continuación. Son las propiedades nextFocusUp, nextFocusDown, nextFocusLeft, nextFocusRight y nextFocusForward (todas con el espacio de nombres android:). Con estas propiedades puedes indicar, en cada vista, qué otra tomará el foco si se utiliza un control direccional que tenga el teléfono (un D-pad, una trackball o un teclado que incluye flechas de dirección).
      Por ejemplo, en el EditText de tu celda (0,0) puedes usar android:nextFocusRight y asignarle el ID del EditText de la celda (0,1), y a android:nextFocusDown el del EditText de la celda (1,0).

      La propiedad android:nextFocusForward es la que se consulta cuando se usa el botón “Siguiente” que aparece en el teclado (para que se vea, hay que añadir android:imeOptions=”actionNext” en cada EditText que deba mostrarlo). Seguramente esta es la que estás buscando.
      En tu caso, la propiedad android:nextFocusForward del EditText de la celda (0,0) contendría el ID de la celda (0,1). El de la celda (0,1) apuntaría a la celda (1,0). El de la (1,0) a la (1,1) y así hasta el final de la tabla. Y en todas ellas se asignaría “actionNext” a la propiedad android:imeOptions.

      Todas estas propiedades son para usarlas en el XML. Si quieres asignarlas por código (para automatizar el proceso, por ejemplo), tienes que usar setNextFocusForwardId y setImeOptions (con la constante IME_ACTION_NEXT).

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s