Compartir a través de


Trabajar con vistas de tabla tvOS en Xamarin

En este artículo se describe el diseño y el trabajo con vistas de tabla y controladores de vistas de tabla dentro de una aplicación de Xamarin.tvOS.

En tvOS, una vista de tabla se presenta como una sola columna de filas de desplazamiento que se pueden organizar opcionalmente en grupos o secciones. Las vistas de tabla deben usarse cuando necesite mostrar una gran cantidad de datos de forma eficaz para el usuario, de forma clara para comprenderlo.

Las vistas de tabla se muestran normalmente en un lado de una Vista dividida como navegación, con los detalles del elemento seleccionado mostrado en el lado opuesto:

Vista de tabla de ejemplo

Acerca de las vistas de tabla

Muestra UITableView una sola columna de filas desplazables como una lista jerárquica de información que se puede organizar opcionalmente en grupos o secciones:

Un elemento seleccionado

Apple tiene las siguientes sugerencias para trabajar con tablas:

  • Tener en cuenta el ancho: Intente alcanzar el equilibrio correcto en los anchos de la tabla. Si la tabla es demasiado ancha, puede ser difícil examinar desde una distancia y puede quitarse del área de contenido disponible. Si la tabla es demasiado estrecha, puede hacer que la información se trunquen o encapsulan, de nuevo esto puede ser difícil para que el usuario lea desde la sala.
  • Mostrar contenido de tabla rápidamente: Para listas grandes de datos, cargue el contenido diferida y empiece a mostrar información en cuanto se presente la tabla al usuario. Si la tabla tarda mucho tiempo en cargarse, el usuario podría perder interés en la aplicación o pensar que está bloqueado.
  • Informar al usuario de cargas de contenido largo: Si un tiempo de carga de tabla larga es inevitable, presente una Barra de progreso o un indicador de actividad para que sepan que la aplicación no se ha bloqueado.

Tipos de celdas de vista de tabla

UITableViewCell Se usa para representar las filas de datos individuales en la vista tabla. Apple ha definido varios tipos de celdas de tabla predeterminados:

  • Valor predeterminado: Este tipo presenta una opción Imagen en el lado izquierdo de la celda y el título alineado a la izquierda a la derecha.
  • Subtítulo: Este tipo presenta un título alineado a la izquierda en la primera línea y un subtítulo alineado a la izquierda más pequeño en la línea siguiente.
  • Valor 1: Este tipo presenta un título alineado a la izquierda con un subtítulo alineado a la derecha más claro en la misma línea.
  • Valor 2: Este tipo presenta un título alineado a la derecha con un subtítulo de color más claro y alineado a la izquierda en la misma línea.

Todos los tipos de celdas de vista de tabla predeterminados también admiten elementos gráficos como indicadores de divulgación o marcas de verificación.

Además, puede definir un tipo de celda Personalizado vista de tabla y presentar un Prototipo de celda, que se crea en el Diseñador de interfaces o a través del código.

Apple tiene las siguientes sugerencias para trabajar con celdas de vista de tabla:

  • Evitar recorte de texto: Mantenga las líneas individuales de texto cortas para que no terminen truncadas. Las palabras o frases truncadas son difíciles para que el usuario analice desde toda la sala.
  • Considerar el estado de fila centrado: Dado que una fila se vuelve más grande, con esquinas más redondeadas cuando está en el foco, debe probar la apariencia de la celda en todos los estados. Es posible que las imágenes o el texto se recorten o parezcan incorrectos en el estado Centrado.
  • Usar tablas editables con moderación: Mover o eliminar filas de tabla es más lento en tvOS que en iOS. Debe decidir cuidadosamente si esta característica agregará o distrae la aplicación tvOS.
  • Crear tipos de celda personalizados cuando proceda: Aunque los tipos de celda integrados de vista de tabla son excelentes para muchas situaciones, considere la posibilidad de crear tipos de celda personalizados para información no estándar para proporcionar un mayor control y presentar mejor la información al usuario.

Trabajar con vistas de tabla

La manera más fácil de trabajar con vistas de tabla en una aplicación de Xamarin.tvOS es crear y modificar su apariencia en el Diseñador de interfaces.

Para comenzar, haga lo siguiente:

  1. En Visual Studio para Mac, inicie un nuevo proyecto de aplicación tvOS y seleccione tvOS>App>Single View App y haga clic en el botón Siguiente:

    Seleccionar aplicación de vista única

  2. Escriba un Nombre para la aplicación y haga clic en Siguiente:

    Escriba un nombre para la aplicación

  3. Ajuste el Nombre de proyecto y Nombre de solución o acepte los valores predeterminados y haga clic en el botón Crear para crear la nueva solución:

    El nombre del proyecto y el nombre de la solución

  4. En el Panel de solución, haga doble clic en el Main.storyboard archivo para abrirlo en el Diseñador de iOS:

    El archivo Main.storyboard

  5. Seleccione y elimine el Controlador de vista predeterminado:

    Seleccione y elimine el Controlador de vista predeterminado

  6. Seleccione un Controlador de vista dividido en el Cuadro de herramientas y arrástrelo a la Superficie de diseño.

  7. De forma predeterminada, obtendrá una Vista dividida con un Controlador de vista de navegación y un Controlador de vista de tabla en el lado izquierdo y unControlador de vista en el lado derecho. Este es el uso sugerido de Apple de una vista de tabla en tvOS:

    Agregar una vista dividida

  8. Deberá seleccionar todas las partes de la vista de tabla y asignarle un Nombre de clase personalizadoen la pestaña Widget del Explorador de propiedades para que pueda acceder a ella más adelante en el código de C#. Por ejemplo, el Controlador de vista de tabla:

    Asignar un nombre de clase

  9. Asegúrese de crear una clase personalizada para el Controlador de vista de tabla, la Vista de tabla y cualquier Celda prototipo. Visual Studio para Mac agregará las clases personalizadas al árbol de proyectos a medida que se crean:

    Clases personalizadas en el árbol de proyecto

  10. A continuación, seleccione la Vista de tabla en la Superficie de diseño y ajuste sus propiedades según sea necesario. Por ejemplo, el número de Celdas prototipo y el Estilo (sin formato o agrupado):

    La pestaña Widget

  11. Para cada Celda prototipo, selecciónelo y asígnele un Identificadorúnico en la pestaña Widget del Explorador de propiedades. Este paso es muy importante, ya que necesitará este identificador más adelante al rellenar la tabla. Por ejemplo:AttrCell

    La pestaña Widget

  12. También puede seleccionar presentar la celda como una de los Tipos de celda de vista de tabla predeterminada a través de la lista desplegable Estilo o establecerla en Personalizado y usar la Superficie de diseño para diseñar la celda arrastrando en otros widgets de interfaz de usuario desde el Cuadro de herramientas:

    Diseño de celda

  13. Asigne un Nombre únicoa cada elemento de la interfaz de usuario en el diseño de celda prototipo en la pestaña Widget del Explorador de propiedades para que pueda acceder a ellos más adelante en el código de C#:

    Asignar un nombre

  14. Repita el paso anterior para todas las celdas prototipo en la vista tabla.

  15. A continuación, asigne clases personalizadas al resto del diseño de la interfaz de usuario, diseñe la vista Detalles y asigne Nombres únicos a cada elemento de la interfaz de usuario de la vista Detalles para poder acceder a ellas también en C#. Por ejemplo:

    Diseño de la interfaz de usuario

  16. Guarde los cambios en el guión gráfico.

Diseño de un modelo de datos

Para facilitar el trabajo con la información que mostrará la vista de tabla y facilitar la presentación de información detallada (como el usuario selecciona o resalta filas en la vista tabla), cree una clase o clases personalizadas para que actúen como modelo de datos para la información presentada.

Tome el ejemplo de una aplicación de reserva de viajes que contiene una lista de Ciudades, cada una que contiene una lista única de Atracciones que el usuario puede seleccionar. El usuario podrá marcar una atracción como Favorita, seleccionar para obtener Indicaciones a una atracción y Reservar un vuelo a una ciudad determinada.

Para crear el modelo de datos para una Atracción, haga clic con el botón derecho en el nombre del proyecto en el Panel de solución y seleccione Agregar>Nuevo archivo.... Escriba AttractionInformation para el Nombre y haga clic en el botón Nuevo:

Escriba AttractionInformation para el nombre

Edite el archivo AttractionInformation.cs para que quede de la siguiente manera:

using System;
using Foundation;

namespace tvTable
{
    public class AttractionInformation : NSObject
    {
        #region Computed Properties
        public CityInformation City { get; set;}
        public string Name { get; set;}
        public string Description { get; set;}
        public string ImageName { get; set;}
        public bool IsFavorite { get; set;}
        public bool AddDirections { get; set;}
        #endregion

        #region Constructors
        public AttractionInformation (string name, string description, string imageName)
        {
            // Initialize
            this.Name = name;
            this.Description = description;
            this.ImageName = imageName;
        }
        #endregion
    }
}

Esta clase proporciona las propiedades para almacenar la información sobre una Atracción determinada.

A continuación, haga clic con el botón derecho en el nombre del proyecto en el Panel de solución de nuevo y seleccione Agregar>Nuevo archivo.... Escriba CityInformation para el Nombre y haga clic en el botón Nuevo:

Escriba CityInformation para el nombre

Edite el archivo CityInformation.cs para que quede de la siguiente manera:

using System;
using System.Collections.Generic;
using Foundation;

namespace tvTable
{
    public class CityInformation : NSObject
    {
        #region Computed Properties
        public string Name { get; set; }
        public List<AttractionInformation> Attractions { get; set;}
        public bool FlightBooked { get; set;}
        #endregion

        #region Constructors
        public CityInformation (string name)
        {
            // Initialize
            this.Name = name;
            this.Attractions = new List<AttractionInformation> ();
        }
        #endregion

        #region Public Methods
        public void AddAttraction (AttractionInformation attraction)
        {
            // Mark as belonging to this city
            attraction.City = this;

            // Add to collection
            Attractions.Add (attraction);
        }

        public void AddAttraction (string name, string description, string imageName)
        {
            // Create attraction
            var attraction = new AttractionInformation (name, description, imageName);

            // Mark as belonging to this city
            attraction.City = this;

            // Add to collection
            Attractions.Add (attraction);
        }
        #endregion
    }
}

Esta clase contiene toda la información sobre una Ciudad de destin, una colección de Atracciones para esa ciudad y proporciona dos métodos auxiliares (AddAttraction) para facilitar la adición de atracciones a la ciudad.

Origen de datos de vista de tabla

Cada vista de tabla requiere un origen de datos (UITableViewDataSource) para proporcionar los datos de la tabla y generar las filas necesarias según sea necesario en la vista tabla.

Para el ejemplo anterior, haga clic con el botón derecho en el nombre del proyecto en el Explorador de soluciones, seleccione Agregar>Nuevo archivo... y llámelo AttractionTableDatasource y haga clic en el botón Nuevo para crear. A continuación, edite el archivo AttractionTableDatasource.cs y haga que tenga un aspecto similar al siguiente:

using System;
using System.Collections.Generic;
using UIKit;

namespace tvTable
{
    public class AttractionTableDatasource : UITableViewDataSource
    {
        #region Constants
        const string CellID = "AttrCell";
        #endregion

        #region Computed Properties
        public AttractionTableViewController Controller { get; set;}
        public List<CityInformation> Cities { get; set;}
        #endregion

        #region Constructors
        public AttractionTableDatasource (AttractionTableViewController controller)
        {
            // Initialize
            this.Controller = controller;
            this.Cities = new List<CityInformation> ();
            PopulateCities ();
        }
        #endregion

        #region Public Methods
        public void PopulateCities ()
        {
            // Clear existing
            Cities.Clear ();

            // Define cities and attractions
            var Paris = new CityInformation ("Paris");
            Paris.AddAttraction ("Eiffel Tower", "Is a wrought iron lattice tower on the Champ de Mars in Paris, France.", "EiffelTower");
            Paris.AddAttraction ("Musée du Louvre", "is one of the world's largest museums and a historic monument in Paris, France.", "Louvre");
            Paris.AddAttraction ("Moulin Rouge", "French for 'Red Mill', is a cabaret in Paris, France.", "MoulinRouge");
            Paris.AddAttraction ("La Seine", "Is a 777-kilometre long river and an important commercial waterway within the Paris Basin.", "RiverSeine");
            Cities.Add (Paris);

            var SanFran = new CityInformation ("San Francisco");
            SanFran.AddAttraction ("Alcatraz Island", "Is located in the San Francisco Bay, 1.25 miles (2.01 km) offshore from San Francisco.", "Alcatraz");
            SanFran.AddAttraction ("Golden Gate Bridge", "Is a suspension bridge spanning the Golden Gate strait between San Francisco Bay and the Pacific Ocean", "GoldenGateBridge");
            SanFran.AddAttraction ("San Francisco", "Is the cultural, commercial, and financial center of Northern California.", "SanFrancisco");
            SanFran.AddAttraction ("Telegraph Hill", "Is primarily a residential area, much quieter than adjoining North Beach.", "TelegraphHill");
            Cities.Add (SanFran);

            var Houston = new CityInformation ("Houston");
            Houston.AddAttraction ("City Hall", "It was constructed in 1938-1939, and is located in Downtown Houston.", "CityHall");
            Houston.AddAttraction ("Houston", "Is the most populous city in Texas and the fourth most populous city in the US.", "Houston");
            Houston.AddAttraction ("Texas Longhorn", "Is a breed of cattle known for its characteristic horns, which can extend to over 6 ft.", "LonghornCattle");
            Houston.AddAttraction ("Saturn V Rocket", "was an American human-rated expendable rocket used by NASA between 1966 and 1973.", "Rocket");
            Cities.Add (Houston);
        }
        #endregion

        #region Override Methods
        public override UITableViewCell GetCell (UITableView tableView, Foundation.NSIndexPath indexPath)
        {
            // Get cell
            var cell = tableView.DequeueReusableCell (CellID) as AttractionTableCell;

            // Populate cell
            cell.Attraction = Cities [indexPath.Section].Attractions [indexPath.Row];

            // Return new cell
            return cell;
        }

        public override nint NumberOfSections (UITableView tableView)
        {
            // Return number of cities
            return Cities.Count;
        }

        public override nint RowsInSection (UITableView tableView, nint section)
        {
            // Return the number of attractions in the given city
            return Cities [(int)section].Attractions.Count;
        }

        public override string TitleForHeader (UITableView tableView, nint section)
        {
            // Get the name of the current city
            return Cities [(int)section].Name;
        }
        #endregion
    }
}

Echemos un vistazo a algunas secciones de la clase en detalle.

En primer lugar, hemos definido una constante para contener el identificador único de la celda prototipo (este es el mismo identificador asignado en el Diseñador de interfaces anterior), se ha agregado un acceso directo al controlador de vista de tabla y se ha creado almacenamiento para nuestros datos:

const string CellID = "AttrCell";
public AttractionTableViewController Controller { get; set;}
public List<CityInformation> Cities { get; set;}

A continuación, guardamos el controlador de vista de tabla y, a continuación, compilamos y rellenamos nuestro origen de datos (con los modelos de datos definidos anteriormente) cuando se crea la clase:

public AttractionTableDatasource (AttractionTableViewController controller)
{
    // Initialize
    this.Controller = controller;
    this.Cities = new List<CityInformation> ();
    PopulateCities ();
}

Por ejemplo, el método PopulateCities simplemente crea objetos data Model en memoria, pero estos podrían leerse fácilmente desde una base de datos o un servicio web en una aplicación real:

public void PopulateCities ()
{
    // Clear existing
    Cities.Clear ();

    // Define cities and attractions
    var Paris = new CityInformation ("Paris");
    Paris.AddAttraction ("Eiffel Tower", "Is a wrought iron lattice tower on the Champ de Mars in Paris, France.", "EiffelTower");
    ...
}

El método NumberOfSections devuelve el número de secciones de la tabla:

public override nint NumberOfSections (UITableView tableView)
{
    // Return number of cities
    return Cities.Count;
}

Para vistas de tabla con estilo Sin formato, siempre devuelve 1.

El método RowsInSection devuelve el número de filas de la sección actual:

public override nint RowsInSection (UITableView tableView, nint section)
{
    // Return the number of attractions in the given city
    return Cities [(int)section].Attractions.Count;
}

De nuevo, para vistas de tabla Sin formato, devuelva el número total de elementos del origen de datos.

El método TitleForHeader devuelve el título de la sección especificada:

public override string TitleForHeader (UITableView tableView, nint section)
{
    // Get the name of the current city
    return Cities [(int)section].Name;
}

Para un tipo de vista tabla sin formato, deje el título en blanco ("").

Por último, cuando lo solicite la vista tabla, cree y rellene una celda prototipo mediante el GetCell método:

public override UITableViewCell GetCell (UITableView tableView, Foundation.NSIndexPath indexPath)
{
    // Get cell
    var cell = tableView.DequeueReusableCell (CellID) as AttractionTableCell;

    // Populate cell
    cell.Attraction = Cities [indexPath.Section].Attractions [indexPath.Row];

    // Return new cell
    return cell;
}

Para obtener más información sobre cómo trabajar con, UITableViewDatasourcevea la documentación de UITableViewDatasourcede Apple.

Delegado de vista de tabla

Cada vista de tabla requiere un delegado (UITableViewDelegate) para responder a la interacción del usuario u otros eventos del sistema en la tabla.

Para el ejemplo anterior, haga clic con el botón derecho en el nombre del proyecto en el Explorador de soluciones, seleccione Agregar>Nuevo archivo... y llámelo AttractionTableDelegate y haga clic en el botón Nuevo para crear. A continuación, edite el archivo AttractionTableDelegate.cs y haga que tenga un aspecto similar al siguiente:

using System;
using System.Collections.Generic;
using UIKit;

namespace tvTable
{
    public class AttractionTableDelegate : UITableViewDelegate
    {
        #region Computed Properties
        public AttractionTableViewController Controller { get; set;}
        #endregion

        #region Constructors
        public AttractionTableDelegate (AttractionTableViewController controller)
        {
            // Initializw
            this.Controller = controller;
        }
        #endregion

        #region Override Methods
        public override void RowSelected (UITableView tableView, Foundation.NSIndexPath indexPath)
        {
            var attraction = Controller.Datasource.Cities [indexPath.Section].Attractions [indexPath.Row];
            attraction.IsFavorite = (!attraction.IsFavorite);

            // Update UI
            Controller.TableView.ReloadData ();
        }

        public override bool CanFocusRow (UITableView tableView, Foundation.NSIndexPath indexPath)
        {
            // Inform caller of highlight change
            RaiseAttractionHighlighted (Controller.Datasource.Cities [indexPath.Section].Attractions [indexPath.Row]);
            return true;
        }
        #endregion

        #region Events
        public delegate void AttractionHighlightedDelegate (AttractionInformation attraction);
        public event AttractionHighlightedDelegate AttractionHighlighted;

        internal void RaiseAttractionHighlighted (AttractionInformation attraction)
        {
            // Inform caller
            if (this.AttractionHighlighted != null) this.AttractionHighlighted (attraction);
        }
        #endregion
    }
}

Echemos un vistazo a varias secciones de esta clase en detalles.

En primer lugar, creamos un acceso directo al controlador de vista de tabla cuando se crea la clase :

public AttractionTableViewController Controller { get; set;}
...

public AttractionTableDelegate (AttractionTableViewController controller)
{
    // Initialize
    this.Controller = controller;
}

A continuación, cuando se selecciona una fila (el usuario hace clic en la superficie táctil del Apple Remote) queremos marcar la Atracción representada por la fila seleccionada como favorito:

public override void RowSelected (UITableView tableView, Foundation.NSIndexPath indexPath)
{
    var attraction = Controller.Datasource.Cities [indexPath.Section].Attractions [indexPath.Row];
    attraction.IsFavorite = (!attraction.IsFavorite);

    // Update UI
    Controller.TableView.ReloadData ();
}

A continuación, cuando el usuario resalta una fila (al darle el foco mediante la superficie táctil Apple Remote) queremos presentar los detalles de la Atracción representada por esa fila en la sección Detalles de nuestro controlador de vista dividida:

public override bool CanFocusRow (UITableView tableView, Foundation.NSIndexPath indexPath)
{
    // Inform caller of highlight change
    RaiseAttractionHighlighted (Controller.Datasource.Cities [indexPath.Section].Attractions [indexPath.Row]);
    return true;
}
...

public delegate void AttractionHighlightedDelegate (AttractionInformation attraction);
public event AttractionHighlightedDelegate AttractionHighlighted;

internal void RaiseAttractionHighlighted (AttractionInformation attraction)
{
    // Inform caller
    if (this.AttractionHighlighted != null) this.AttractionHighlighted (attraction);
}

Se llama al método CanFocusRow para cada fila que está a punto de obtener el foco en la vista de tabla. Devuelve true si la fila puede obtener el foco; de lo contrario, devuelve false. En el caso de este ejemplo, hemos creado un evento personalizado AttractionHighlighted que se generará en cada fila a medida que recibe el foco.

Para obtener más información sobre cómo trabajar con, UITableViewDelegatevea la documentación de UITableViewDatasourcede Apple.

Celda Vista de tabla

Para cada celda prototipo que agregó a la vista de tabla en el Diseñador de interfaces, también creó una instancia personalizada de la celda vista de tabla (UITableViewCell) para permitirle rellenar la nueva celda (fila) tal como se crea.

Para la aplicación de ejemplo, haga doble clic en el archivo AttractionTableCell.cs para abrirlo para su edición y que tenga el siguiente aspecto:

using System;
using Foundation;
using UIKit;

namespace tvTable
{
    public partial class AttractionTableCell : UITableViewCell
    {
        #region Private Variables
        private AttractionInformation _attraction = null;
        #endregion

        #region Computed Properties
        public AttractionInformation Attraction {
            get { return _attraction; }
            set {
                _attraction = value;
                UpdateUI ();
            }
        }
        #endregion

        #region Constructors
        public AttractionTableCell (IntPtr handle) : base (handle)
        {
        }
        #endregion

        #region Private Methods
        private void UpdateUI ()
        {
            // Trap all errors
            try {
                Title.Text = Attraction.Name;
                Favorite.Hidden = (!Attraction.IsFavorite);
            } catch {
                // Since the UI might not be fully loaded, ignore
                // all errors at this point
            }
        }
        #endregion
    }
}

Esta clase proporciona almacenamiento para el objeto del Modelo de Datos de Atracción (AttractionInformation tal y como se definió anteriormente) que se muestra en la fila determinada:

private AttractionInformation _attraction = null;
...

public AttractionInformation Attraction {
    get { return _attraction; }
    set {
        _attraction = value;
        UpdateUI ();
    }
}

El UpdateUI método rellena los Widgets de interfaz de usuario (que se agregaron al prototipo de celda en el Diseñador de interfaces) según sea necesario:

private void UpdateUI ()
{
    // Trap all errors
    try {
        Title.Text = Attraction.Name;
        Favorite.Hidden = (!Attraction.IsFavorite);
    } catch {
        // Since the UI might not be fully loaded, ignore
        // all errors at this point
    }
}

Para obtener más información sobre cómo trabajar con un UITableViewCell, vea la documentación de UITableViewCell de Apple.

Controlador de vista de tabla

Un controlador de vista de tabla (UITableViewController) administra una vista de tabla que se ha agregado a un guión gráfico a través del Diseñador de interfaces.

Para la aplicación de ejemplo, haga doble clic en el archivo AttractionTableViewController.cs para abrirlo para su edición y que tenga el siguiente aspecto:

using System;
using Foundation;
using UIKit;

namespace tvTable
{
    public partial class AttractionTableViewController : UITableViewController
    {
        #region Computed Properties
        public AttractionTableDatasource Datasource {
            get { return TableView.DataSource as AttractionTableDatasource; }
        }

        public AttractionTableDelegate TableDelegate {
            get { return TableView.Delegate as AttractionTableDelegate; }
        }
        #endregion

        #region Constructors
        public AttractionTableViewController (IntPtr handle) : base (handle)
        {
        }
        #endregion

        #region Override Methods
        public override void ViewDidLoad ()
        {
            base.ViewDidLoad ();

            // Setup table
            TableView.DataSource = new AttractionTableDatasource (this);
            TableView.Delegate = new AttractionTableDelegate (this);
            TableView.ReloadData ();
        }
        #endregion
    }
}

Echemos un vistazo más detallado a esta clase. En primer lugar, hemos creado accesos directos para facilitar el acceso a la vista de tablaDataSource y TableDelegate. Los usaremos más adelante para comunicarse entre la vista de tabla en el lado izquierdo de la vista dividida y la vista detalles de la derecha.

Por último, cuando la vista de tabla se carga en la memoria, creamos instancias de AttractionTableDatasource y AttractionTableDelegate (ambas creadas anteriormente) y las adjuntamos a la vista de tabla.

Para obtener más información sobre cómo trabajar con una UITableViewController, vea la documentación de UITableViewController de Apple.

Extraerlo todo juntos

Como se indica al principio de este documento, las vistas de tabla se muestran normalmente en un lado de un Vista dividida como navegación, con los detalles del elemento seleccionado mostrado en el lado opuesto. Por ejemplo:

Ejecución de aplicación de ejemplo

Dado que se trata de un patrón estándar en tvOS, echemos un vistazo a los pasos finales para reunir todo y hacer que los lados izquierdo y derecho de la vista dividida interactúen entre sí.

Vista de detalles

Para el ejemplo de la aplicación de viajes presentada anteriormente, se define una clase personalizada (AttractionViewController) para el controlador de vista estándar que se presenta en el lado derecho de la vista dividida como vista de detalles:

using System;
using Foundation;
using UIKit;

namespace tvTable
{
    public partial class AttractionViewController : UIViewController
    {
        #region Private Variables
        private AttractionInformation _attraction = null;
        #endregion

        #region Computed Properties
        public AttractionInformation Attraction {
            get { return _attraction; }
            set {
                _attraction = value;
                UpdateUI ();
            }
        }

        public MasterSplitView SplitView { get; set;}
        #endregion

        #region Constructors
        public AttractionViewController (IntPtr handle) : base (handle)
        {
        }
        #endregion

        #region Public Methods
        public void UpdateUI ()
        {
            // Trap all errors
            try {
                City.Text = Attraction.City.Name;
                Title.Text = Attraction.Name;
                SubTitle.Text = Attraction.Description;

                IsFlighBooked.Hidden = (!Attraction.City.FlightBooked);
                IsFavorite.Hidden = (!Attraction.IsFavorite);
                IsDirections.Hidden = (!Attraction.AddDirections);
                BackgroundImage.Image = UIImage.FromBundle (Attraction.ImageName);
                AttractionImage.Image = BackgroundImage.Image;
            } catch {
                // Since the UI might not be fully loaded, ignore
                // all errors at this point
            }
        }
        #endregion

        #region Override Methods
        public override void ViewWillAppear (bool animated)
        {
            base.ViewWillAppear (animated);

            // Ensure the UI Updates
            UpdateUI ();
        }
        #endregion

        #region Actions
        partial void BookFlight (NSObject sender)
        {
            // Ask user to book flight
            AlertViewController.PresentOKCancelAlert ("Book Flight",
                                                      string.Format ("Would you like to book a flight to {0}?", Attraction.City.Name),
                                                      this,
                                                      (ok) => {
                Attraction.City.FlightBooked = ok;
                IsFlighBooked.Hidden = (!Attraction.City.FlightBooked);
            });
        }

        partial void GetDirections (NSObject sender)
        {
            // Ask user to add directions
            AlertViewController.PresentOKCancelAlert ("Add Directions",
                                                     string.Format ("Would you like to add directions to {0} to you itinerary?", Attraction.Name),
                                                     this,
                                                     (ok) => {
                                                         Attraction.AddDirections = ok;
                                                         IsDirections.Hidden = (!Attraction.AddDirections);
                                                     });
        }

        partial void MarkFavorite (NSObject sender)
        {
            // Flip favorite state
            Attraction.IsFavorite = (!Attraction.IsFavorite);
            IsFavorite.Hidden = (!Attraction.IsFavorite);

            // Reload table
            SplitView.Master.TableController.TableView.ReloadData ();
        }
        #endregion
    }
}

Aquí, se ha proporcionado la Atracción (AttractionInformation) que se muestra como una propiedad y se ha creado un UpdateUI método que rellena los Widgets de interfaz de usuario agregados a la vista en el Diseñador de interfaces.

También hemos definido un acceso directo al controlador de vista dividida (SplitView) que usaremos para comunicar los cambios a la vista de tabla (AcctractionTableView).

Por último, las acciones personalizadas (eventos) se agregaron a las tres UIButton instancias creadas en el Diseñador de interfaces, que permiten al usuario marcar una atracción como Favorita, obtener Indicaciones a una atracción y Reservar un vuelo a una ciudad determinada.

Controlador de vista de navegación

Dado que el controlador de vista de tabla está anidado en un controlador de vista de navegación en el lado izquierdo de la vista dividida, el controlador de vista de navegación asignó una clase personalizada (MasterNavigationController) en el Diseñador de interfaces y se definió de la siguiente manera:

using System;
using Foundation;
using UIKit;

namespace tvTable
{
    public partial class MasterNavigationController : UINavigationController
    {
        #region Computed Properties
        public MasterSplitView SplitView { get; set;}
        public AttractionTableViewController TableController {
            get { return TopViewController as AttractionTableViewController; }
        }
        #endregion

        #region Constructors
        public MasterNavigationController (IntPtr handle) : base (handle)
        {
        }
        #endregion
    }
}

De nuevo, esta clase simplemente define algunos accesos directos para facilitar la comunicación entre los dos lados del controlador de vista dividida:

  • SplitView: Es un vínculo al controlador de vista dividida (MainSpiltViewController) al que pertenece el controlador de vista de navegación.
  • TableController: Obtiene el controlador de vista de tabla (AttractionTableViewController) que se presenta como la vista superior en el controlador de vista de navegación.

Controlador de vista dividida

Dado que el controlador de vista dividida es la base de nuestra aplicación, creamos una clase personalizada (MasterSplitViewController) para ella en el Diseñador de interfaces y la definimos de la siguiente manera:

using System;
using Foundation;
using UIKit;

namespace tvTable
{
    public partial class MasterSplitView : UISplitViewController
    {
        #region Computed Properties
        public AttractionViewController Details {
            get { return ViewControllers [1] as AttractionViewController; }
        }

        public MasterNavigationController Master {
            get { return ViewControllers [0] as MasterNavigationController; }
        }
        #endregion

        #region Constructors
        public MasterSplitView (IntPtr handle) : base (handle)
        {
        }
        #endregion

        #region Override Methods
        public override void ViewDidLoad ()
        {
            base.ViewDidLoad ();

            // Initialize
            Master.SplitView = this;
            Details.SplitView = this;

            // Wire-up events
            Master.TableController.TableDelegate.AttractionHighlighted += (attraction) => {
                // Display new attraction
                Details.Attraction = attraction;
            };
        }
        #endregion
    }
}

En primer lugar, creamos accesos directos al lado Detalles de la vista dividida (AttractionViewController) y al lado del Maestro (MasterNavigationController). De nuevo, esto facilita la comunicación entre los dos lados más adelante.

A continuación, cuando la vista dividida se carga en la memoria, adjuntamos el controlador de vista dividida a ambos lados de la vista dividida y respondemos al usuario resaltando una atracción en la vista de tabla (AttractionHighlighted) mostrando la nueva atracción en el lado Detalles de la vista dividida.

Vistas de tabla en detalle

Dado que tvOS se basa en iOS, las vistas de tabla y los controladores de vista de tabla están diseñados y se comportan de forma similar. Para obtener información más detallada sobre cómo trabajar con la vista de tablas en una aplicación de Xamarin, vea nuestra documentación de iOS Trabajar con tablas y celdas.

Resumen

En este artículo se ha tratado el diseño y el trabajo con vistas de tabla dentro de una aplicación Xamarin.tvOS. Y ha presentado un ejemplo de cómo trabajar con una vista de tabla dentro de una vista dividida, que es el uso típico de una vista de tabla en una aplicación tvOS.