Cómo agrupar elementos en un ListView (HTML)
[ Este artículo está destinado a desarrolladores de Windows 8.x y Windows Phone 8.x que escriben aplicaciones de Windows Runtime. Si estás desarrollando para Windows 10, consulta la documentación más reciente ]
Aprende a agrupar elementos en un control ListView. Para mostrar información de grupo, como encabezados de grupo y límites de grupo, tu ListView debe usar un diseño de cuadrícula. Para que la agrupación funcione, la propiedad loadingBehavior del control ListView debe estar establecida en "randomaccess" (el valor predeterminado).
Lo que debes saber
Tecnologías
Requisitos previos
- Damos por supuesto que puedes crear y usar un objeto ListView básico. Para ver una introducción al control ListView, consulta Inicio rápido: Agregar ListView.
Instrucciones
Paso 1: Crear los datos
La agrupación requiere dos orígenes de datos: un IListDataSource que contenga los elementos y un IListDataSource que contenga los grupos. En los elementos IListDataSource, cada elemento contiene una propiedad groupKey que lo vincula al grupo al que pertenece en el grupo IListDataSource.
Agrega un nuevo archivo JavaScript al proyecto para que contenga tus datos. Asígnale el nombre "data.js".
En el archivo data.js que acabas de crear, crea el origen de datos subyacente que proporcionará datos a tu control ListView.
Un modo de crear un IListDataSource consiste en crear un objeto WinJS.Binding.List. Cada WinJS.Binding.List tiene una propiedad dataSource que devuelve un IListDataSource que contiene tus datos.
En este ejemplo, se crea un objeto WinJS.Binding.List a partir de una matriz de objetos JSON (myData):
// Start of data.js (function () { "use strict"; var myData = [ { title: "Banana Blast", text: "Low-fat frozen yogurt", picture: "images/60Banana.png" }, { title: "Banana Blast", text: "Low-fat frozen yogurt", picture: "images/60Banana.png" }, { title: "Banana Blast", text: "Low-fat frozen yogurt", picture: "images/60Banana.png" }, { title: "Banana Blast", text: "Low-fat frozen yogurt", picture: "images/60Banana.png" }, { title: "Lavish Lemon Ice", text: "Sorbet", picture: "images/60Lemon.png" }, { title: "Lavish Lemon Ice", text: "Sorbet", picture: "images/60Lemon.png" }, { title: "Lavish Lemon Ice", text: "Sorbet", picture: "images/60Lemon.png" }, { title: "Lavish Lemon Ice", text: "Sorbet", picture: "images/60Lemon.png" }, { title: "Marvelous Mint", text: "Gelato", picture: "images/60Mint.png" }, { title: "Marvelous Mint", text: "Gelato", picture: "images/60Mint.png" }, { title: "Marvelous Mint", text: "Gelato", picture: "images/60Mint.png" }, { title: "Marvelous Mint", text: "Gelato", picture: "images/60Mint.png" }, { title: "Creamy Orange", text: "Sorbet", picture: "images/60Orange.png" }, { title: "Creamy Orange", text: "Sorbet", picture: "images/60Orange.png" }, { title: "Creamy Orange", text: "Sorbet", picture: "images/60Orange.png" }, { title: "Creamy Orange", text: "Sorbet", picture: "images/60Orange.png" }, { title: "Succulent Strawberry", text: "Sorbet", picture: "images/60Strawberry.png" }, { title: "Succulent Strawberry", text: "Sorbet", picture: "images/60Strawberry.png" }, { title: "Succulent Strawberry", text: "Sorbet", picture: "images/60Strawberry.png" }, { title: "Succulent Strawberry", text: "Sorbet", picture: "images/60Strawberry.png" }, { title: "Very Vanilla", text: "Ice Cream", picture: "images/60Vanilla.png" }, { title: "Very Vanilla", text: "Ice Cream", picture: "images/60Vanilla.png" }, { title: "Very Vanilla", text: "Ice Cream", picture: "images/60Vanilla.png" }, { title: "Very Vanilla", text: "Ice Cream", picture: "images/60Vanilla.png" }, { title: "Orangy Orange", text: "Sorbet", picture: "images/60Orange.png" }, { title: "Orangy Orange", text: "Sorbet", picture: "images/60Orange.png" }, { title: "Absolutely Orange", text: "Sorbet", picture: "images/60Orange.png" }, { title: "Absolutely Orange", text: "Sorbet", picture: "images/60Orange.png" }, { title: "Triple Strawberry", text: "Sorbet", picture: "images/60Strawberry.png" }, { title: "Triple Strawberry", text: "Sorbet", picture: "images/60Strawberry.png" }, { title: "Double Banana Blast", text: "Low-fat frozen yogurt", picture: "images/60Banana.png" }, { title: "Double Banana Blast", text: "Low-fat frozen yogurt", picture: "images/60Banana.png" }, { title: "Double Banana Blast", text: "Low-fat frozen yogurt", picture: "images/60Banana.png" }, { title: "Green Mint", text: "Gelato", picture: "images/60Mint.png" } ]; // Create a WinJS.Binding.List from the array. var itemsList = new WinJS.Binding.List(myData);
Nota Estos datos hacen referencia a varias imágenes. Para obtener las imágenes, descarga la Muestra de agrupación de ListView y SemanticZoom y después copia las imágenes de la muestra en tu proyecto. También puedes usar tus propias imágenes —pero asegúrate de actualizar el valor de la propiedad
picture
en los datos.Sugerencia
No tienes por qué limitarte a usar un WinJS.Binding.List: también podrías usar un VirtualizedDataSource personalizado. (StorageDataSource no admite la agrupación). Para ver más información sobre cómo crear un origen de datos personalizado, consulta el tema sobre cómo crear un origen de datos personalizado.
Crea una versión del origen de datos que contenga información de agrupación. Si estás usando un WinJS.Binding.List, puedes llamar a su método createGrouped para que cree una versión agrupada del objeto List.
El método createGrouped toma 3 parámetros.
- getGroupKey: una función que, según un elemento dado de la lista, devuelve la clave de grupo a la que pertenece el elemento.
- getGroupData: una función que, según un elemento dado de la lista, devuelve el objeto de datos que representa el grupo al que pertenece el elemento.
- compareGroups: una función que se usa para ordenar grupos, de manera que el grupo A esté antes que el grupo B. La función toma dos claves de grupo como entrada, compara los dos grupos y devuelve un valor menor que cero si el primer grupo es menor que el segundo, cero si los grupos son iguales y un valor positivo si el primer grupo es mayor que el segundo.
El método createGrouped devuelve un objeto WinJS.Binding.List que contiene dos proyecciones de los datos de la lista sin agrupar original. Las proyecciones son dinámicas, por tanto, si modificas la lista, modificas el original.
Este ejemplo usa el método List.createGrouped para crear una versión agrupada de List. Usa la primera letra del título de cada elemento para definir los grupos.
// Sorts the groups function compareGroups(leftKey, rightKey) { return leftKey.charCodeAt(0) - rightKey.charCodeAt(0); } // Returns the group key that an item belongs to function getGroupKey(dataItem) { return dataItem.title.toUpperCase().charAt(0); } // Returns the title for a group function getGroupData(dataItem) { return { title: dataItem.title.toUpperCase().charAt(0) }; } // Create the groups for the ListView from the item data and the grouping functions var groupedItemsList = itemsList.createGrouped(getGroupKey, getGroupData, compareGroups);
Permite el acceso a tus datos desde el ámbito global. De esa manera, cuando crees tu ListView, podrás acceder a los datos de manera declarativa (las instrucciones se incluyen en el Paso 2.3).
En este ejemplo se usa WinJS.Namespace.define para que la lista agrupada sea accesible al público.
WinJS.Namespace.define("myData", { groupedItemsList: groupedItemsList }); })(); // End of data.js
Paso 2: Crear un ListView que use un diseño de cuadrícula
Después, crea un ListView y conéctalo a tus datos.
En la sección head de la página HTML que va a contener el ListView, agrega una referencia al archivo de datos que creaste en el paso anterior.
<!-- Your data file. --> <script src="/js/data.js"></script>
En el body del archivo HTML, crea un ListView. Establece su propiedad layout en GridLayout.
<div id="groupedListView" data-win-control="WinJS.UI.ListView" data-win-options="{layout: {type: WinJS.UI.GridLayout}}" ></div>
Establece la propiedad itemDataSource del control ListView en el origen de datos de los elementos agrupados.
En el paso 1, creaste un miembro del espacio de nombres que contiene los elementos agrupados que quieres mostrar: myData.groupedItemsList. Si llamas a este campo, se devuelve un WinJS.Binding.List. Para obtener un IListDataSource que el ListView pueda usar, llama a su propiedad dataSource: myData.groupedItemsList.dataSource.
<div id="groupedListView" data-win-control="WinJS.UI.ListView" data-win-options="{itemDataSource: myData.groupedItemsList.dataSource, layout: {type: WinJS.UI.GridLayout}}" ></div>
Después, establece la propiedad groupDataSource del control ListView en el origen de datos que contiene los datos de grupo. Usas la propiedad groups del objeto List para obtener otra List que contiene la información de grupo. Para obtener un IListDataSource, llama a myData.groupedItemsList.groups.dataSource.
<div id="groupedListView" data-win-control="WinJS.UI.ListView" data-win-options="{itemDataSource: myData.groupedItemsList.dataSource, groupDataSource: myData.groupedItemsList.groups.dataSource, layout: {type: WinJS.UI.GridLayout}}"> </div>
Ejecuta la aplicación. Como no has especificado ninguna plantilla de elemento, los datos no tienen formato:
Paso 3: Crear un plantilla de elemento y una plantilla de encabezado de grupo
En tu página HTML, antes de definir tu control ListView, crea un elemento WinJS.UI.Template llamado "mediumListIconTextTemplate" y establece la propiedad itemTemplate del control ListView en el nombre de esta plantilla.
<div id="mediumListIconTextTemplate"
data-win-control="WinJS.Binding.Template"
style="display: none">
<div class="mediumListIconTextItem">
<img class="mediumListIconTextItem-Image" data-win-bind="src: picture" />
<div class="mediumListIconTextItem-Detail">
<h4 data-win-bind="innerText: title"></h4>
<h6 data-win-bind="innerText: text"></h6>
</div>
</div>
</div>
<div id="groupedListView"
data-win-control="WinJS.UI.ListView"
data-win-options="{itemDataSource: myData.groupedItemsList.dataSource,
itemTemplate: select('#mediumListIconTextTemplate'),
groupDataSource: myData.groupedItemsList.groups.dataSource,
layout: {type: WinJS.UI.GridLayout}}">
</div>
(Ten en cuenta que la plantilla especifica varios estilos. Los definirás más adelante.)
Ejecuta la aplicación. Se da formato a los elementos, pero no a los encabezados de grupo.
Paso 4: Crear una plantilla de encabezado de grupo
Define un WinJS.UI.Template para el encabezado de grupo y asígnale el identificador "headerTemplate". Establece la propiedad groupHeaderTemplate del control ListView en esta plantilla.
<div id="headerTemplate" data-win-control="WinJS.Binding.Template"
style="display: none">
<div class="simpleHeaderItem">
<h1 data-win-bind="innerText: title"></h1>
</div>
</div>
<div id="mediumListIconTextTemplate"
data-win-control="WinJS.Binding.Template"
style="display: none">
<div class="mediumListIconTextItem">
<img class="mediumListIconTextItem-Image" data-win-bind="src: picture" />
<div class="mediumListIconTextItem-Detail">
<h4 data-win-bind="innerText: title"></h4>
<h6 data-win-bind="innerText: text"></h6>
</div>
</div>
</div>
<div id="groupedListView"
data-win-control="WinJS.UI.ListView"
data-win-options="{itemDataSource: myData.groupedItemsList.dataSource,
itemTemplate: select('#mediumListIconTextTemplate'),
groupDataSource: myData.groupedItemsList.groups.dataSource,
groupHeaderTemplate: select('#headerTemplate'),
layout: {type: WinJS.UI.GridLayout}}">
</div>
Ejecuta la aplicación. Ahora los elementos y los encabezados de grupo ya tienen el formato.
Paso 5: Aplicar estilo a tus plantillas
Si quieres especificar de manera más detallada el aspecto de tus elementos y encabezados, puedes agregar tus propios estilos CSS a tu hoja de estilos. El CSS en este ejemplo aplica estilos a los elementos y encabezados, además de al ListView en sí.
/* CSS for the ListView */
#groupedListView
{
width: 600px;
height: 300px;
border: solid 2px rgba(0, 0, 0, 0.13);
}
/* Template for headers */
.simpleHeaderItem
{
width: 50px;
height: 50px;
padding: 8px;
}
/* Template for items */
.mediumListIconTextItem
{
width: 282px;
height: 70px;
padding: 5px;
overflow: hidden;
display: -ms-grid;
}
.mediumListIconTextItem img.mediumListIconTextItem-Image
{
width: 60px;
height: 60px;
margin: 5px;
-ms-grid-column: 1;
}
.mediumListIconTextItem .mediumListIconTextItem-Detail
{
margin: 5px;
-ms-grid-column: 2;
}
Cuando ejecutas la aplicación, tus elementos se dividen en grupos:
También puedes usar las clases CSS win-groupheader
y win-container
para aplicar estilo a los grupos y elementos. Para más información, consulta el tema sobre la aplicación de estilos a ListView y sus elementos.
Observaciones
Ordenar y filtrar elementos y grupos
WinJS.Binding.List puede ordenar y filtrar tus elementos y grupos. Para más información, consulta los métodos createSorted y createFiltered.
Crear una vista alejada de tus grupos
Ahora que sabes crear un ListView agrupado, no te queda mucho más por aprender para usar el control SemanticZoom para crear una vista reducida de tus grupos.
Para obtener instrucciones de uso de SemanticZoom, consulta Inicio rápido: Agregar controles SemanticZoom.
Controles ListView agrupados que contienen encabezados interactivos
Cuando el control ListView agrupado contiene encabezados interactivos, recomendamos que hagas compatible el método abreviado de teclado Ctrl+Alt+G y lo uses para mover al usuario al grupo en el que está navegando. Esto debería proporcionar el mismo comportamiento que hacer clic o pulsar en el propio encabezado de grupo.
Eliminar grupos y desplazar
Cuando se elimina un grupo, el ListView podría desplazarse a una ubicación no esperada; por lo tanto, realiza una llamada al método ensureVisible para que se desplace a una posición que tenga sentido para la aplicación.
Ejemplo completo
Para obtener una muestra completa que indica cómo crear un ListView agrupado, consulta la muestra de agrupación de ListView y SemanticZoom.