Trabajo con tablas en iOS Designer

Las instancias de Storyboard son una forma WYSIWYG de crear aplicaciones iOS y se admiten dentro de Visual Studio en Mac y Windows. Para obtener más información sobre las instancias de Storyboard, consulte el documento Introducción a los guiones gráficos. Las instancias de Storyboard también permiten editar los diseños de celda en la tabla, lo que simplifica el desarrollo con tablas y celdas.

Al configurar las propiedades de una vista de tabla en iOS Designer, hay dos tipos de contenido de celda entre los que puede elegir: contenido de prototipo dinámico o estático.

Contenido de prototipo dinámico

Normalmente, una UITableView con contenido de prototipo tiene como objetivo mostrar una lista de datos donde la celda de prototipo (o celdas, ya que puede definir más de una) se reutilizan para cada elemento de la lista. No es necesario crear una instancia de las celdas, ya que se obtienen en el método GetView llamando al método DequeueReusableCell de su UITableViewSource.

Contenido estático

Las UITableViews con contenido estático permiten el diseño de las tablas justo en la superficie de diseño. Las celdas pueden arrastrarse a la tabla y personalizarse mediante el cambio de las propiedades y la adición de controles.

Creación de una aplicación controlada por guiones gráficos

El ejemplo de StoryboardTable contiene una sencilla aplicación de patrón y detalle que usa ambos tipos de UITableView en una instancia de Storyboard. En el resto de esta sección se describe cómo crear un pequeño ejemplo de lista de tareas pendientes que tendrá este aspecto cuando se complete:

Pantallas de ejemplo

La interfaz de usuario se creará con un guion gráfico y ambas pantallas usarán UITableView. La pantalla principal usa contenido de prototipo para diseñar la fila y la pantalla de detalles usa contenido estático para crear un formulario de entrada de datos mediante diseños de celda personalizados.

Tutorial

Cree una nueva solución en Visual Studio mediante (Crear) Nuevo proyecto... > Aplicación de una vista (C#) y llámela StoryboardTables.

Cuadro de diálogo Crear un proyecto

La solución se abrirá con algunos archivos de C# y un archivo Main.storyboard ya creado. Haga doble clic en el archivo Main.storyboard para abrirlo en iOS Designer.

Modificación de la instancia de Storyboard

El guion gráfico se editará en tres pasos:

  • En primer lugar, diseñe los controladores de vista necesarios y establezca sus propiedades.
  • En segundo lugar, cree la interfaz de usuario arrastrando y colocando objetos en la vista.
  • Por último, agregue la clase UIKit necesaria a cada vista y asigne a varios controles un nombre para que se pueda hacer referencia a ellos en el código.

Una vez completado el guion gráfico, se puede agregar código para que todo funcione.

Diseño de los controladores de vista

El primer cambio en el guion gráfico es eliminar la vista de detalles existente y reemplazarla por UITableViewController. Siga estos pasos:

  1. Seleccione la barra situada en la parte inferior del controlador de vista y elimínela.

  2. Arrastre un controlador de navegación y un controlador de vista de tabla a la instancia de Storyboard desde el cuadro de herramientas.

  3. Cree un segue desde el controlador de vista raíz al segundo controlador de vista de tabla agregado recientemente. Para crear el segue, arrastre con la tecla Control desde la celda de detalle hasta el UITableViewController recién agregado. Elija la opción Mostrar en Selección de segue.

  4. Seleccione el nuevo segue que ha creado y asígnele un identificador para hacer referencia a este segue en el código. Haga clic en el segue y escriba TaskSegue para el Identificador en el Panel de propiedades, de la siguiente manera:
    Nomenclatura de segue en el panel de propiedades

  5. A continuación, configure las dos vistas de tabla mediante su selección y el uso del Panel de propiedades. Asegúrese de seleccionar Vista y no Controlador de vista: puede usar el esquema del documento para ayudar con la selección.

  6. Cambie el controlador de vista raíz para que sea Contenido: prototipos dinámicos (la vista en la superficie de diseño se etiquetará como Contenido de prototipo):

    Establecer la propiedad Contenido en prototipos dinámicos

  7. Cambie el nuevo UITableViewController para que sea Contenido: celdas estáticas.

  8. El nuevo UITableViewController debe tener establecidos su nombre de clase e identificador. Seleccione el controlador de vista y escriba TaskDetailViewController para la clase en el Panel de propiedades; este proceso creará un nuevo archivo TaskDetailViewController.cs en el Panel de solución. Escriba StoryboardID como detalle, tal como se muestra en el ejemplo siguiente. Se usará más adelante para cargar esta vista en código de C#:

    Establecimiento del identificador del guión gráfico

  9. La superficie de diseño de guion gráfico ahora debería tener un aspecto similar a este (el título del elemento de navegación del controlador de vista raíz se ha cambiado a "Panel de tareas"):

    Superficie de diseño

Creación de la interfaz de usuario

Ahora que las vistas y los segues están configurados, es necesario agregar los elementos de la interfaz de usuario.

Controlador de vista raíz

En primer lugar, seleccione la celda de prototipo en el controlador de vista maestro y establezca el Identificador como taskcell, tal como se muestra a continuación. Se usará más adelante en el código para recuperar una instancia de esta UITableViewCell:

establecimiento del identificador de celda

A continuación, deberá crear un botón que agregue nuevas tareas, como se muestra a continuación:

elemento de la barra de navegación

Haga lo siguiente:

  • Arrastre un elemento de botón de barra desde el cuadro de herramientas hasta el lado derecho de la barra de navegación.
  • En el Panel de propiedades, en Elemento de botón de barra, seleccione Identificador: Agregar (para convertirlo en un botón más +).
  • Asígnele un nombre para que se pueda identificar en el código en una fase posterior. Tenga en cuenta que tendrá que asignar al controlador de vista raíz un nombre de clase (por ejemplo, ItemViewController) para poder establecer el nombre del elemento de botón de barra.

Controlador de vista TaskDetail

La vista de detalles requiere mucho más trabajo. Las celdas de vista de tabla deben arrastrarse a la vista y, a continuación, rellenarse con etiquetas, vistas de texto y botones. En la captura de pantalla siguiente se muestra la interfaz de usuario finalizada con dos secciones. Una sección tiene tres celdas, tres etiquetas, dos campos de texto y un modificador, mientras que la segunda sección tiene una celda con dos botones:

diseño de la vista de detalles

Los pasos para crear el diseño completo son:

Seleccione la vista de tabla y abra el Panel de propiedades. Actualice las siguientes propiedades:

  • Secciones: 2
  • Estilo: agrupado
  • Separador: ninguno
  • Selección: ninguna selección

Seleccione la sección superior y, en Propiedades > Sección Vista de tabla, cambie Filas a 3, tal como se muestra a continuación:

establecimiento de la sección superior en tres filas

Para cada celda, abra el Panel de propiedades y establezca:

  • Estilo: personalizado
  • Identificador: elija un identificador único para cada celda (p. ej. “título”, “notas”, “listo”).
  • Arrastre los controles necesarios para generar el diseño que se muestra en la captura de pantalla (coloque UILabel, UITextField y UISwitch en las celdas correctas y establezca las etiquetas correctamente, es decir, Título, Notas y Listo).

En la segunda sección, establezca Filas en 1 y agarre el controlador de cambio de tamaño inferior de la celda para que sea más alto.

  • Establezca el identificador: en un valor único (por ejemplo, "guardar").

  • Establezca el fondo: color claro.

  • Arrastre dos botones a la celda y establezca sus títulos adecuadamente (es decir, Guardar y Eliminar), tal como se muestra a continuación:

    establecimiento de dos botones en la sección inferior

En este momento, puede que también quiera establecer restricciones en las celdas y controles para garantizar un diseño adaptativo.

Adición de la clase UIKit y controles de nomenclatura

Hay algunos pasos finales para crear nuestra instancia de Storyboard. En primer lugar, debemos asignar un nombre a cada uno de nuestros controles en Identidad > Nombre para que se puedan usar en el código más adelante. Asígneles estos nombres:

  • Title UITextField : TitleText
  • Notes UITextField : NotesText
  • UISwitch : DoneSwitch
  • Delete UIButton : DeleteButton
  • Save UIButton : SaveButton

Adición de código

El resto del trabajo se realizará en Visual Studio en Mac o Windows con C#. Tenga en cuenta que los nombres de propiedad usados en el código reflejan los establecidos en el tutorial anterior.

En primer lugar, queremos crear una clase Chores, que proporcionará una manera de obtener y establecer el valor de Id., Nombre, Notas y Listo (booleano), para que podamos usar esos valores en toda la aplicación.

En la clase Chores, agregue el siguiente código:

public class Chores {
    public int Id { get; set; }
    public string Name { get; set; }
    public string Notes { get; set; }
    public bool Done { get; set; }
  }

A continuación, cree una clase RootTableSource que herede de UITableViewSource.

La diferencia entre esta y una vista de tabla sin guiones gráficos es que el método GetView no necesita crear una instancia de ninguna celda: el método theDequeueReusableCell siempre devolverá una instancia de la celda de prototipo (con un identificador coincidente).

El código siguiente es del archivo RootTableSource.cs:

public class RootTableSource : UITableViewSource
{
// there is NO database or storage of Tasks in this example, just an in-memory List<>
Chores[] tableItems;
string cellIdentifier = "taskcell"; // set in the Storyboard

    public RootTableSource(Chores[] items)
    {
        tableItems = items;
    }

public override nint RowsInSection(UITableView tableview, nint section)
{
  return tableItems.Length;
}

public override UITableViewCell GetCell(UITableView tableView, NSIndexPath indexPath)
{
  // in a Storyboard, Dequeue will ALWAYS return a cell, 
  var cell = tableView.DequeueReusableCell(cellIdentifier);
  // now set the properties as normal
  cell.TextLabel.Text = tableItems[indexPath.Row].Name;
  if (tableItems[indexPath.Row].Done)
    cell.Accessory = UITableViewCellAccessory.Checkmark;
  else
    cell.Accessory = UITableViewCellAccessory.None;
  return cell;
}
public Chores GetItem(int id)
{
  return tableItems[id];
}

Para usar la clase RootTableSource, cree una nueva colección en el constructor del ItemViewController:

chores = new List<Chore> {
      new Chore {Name="Groceries", Notes="Buy bread, cheese, apples", Done=false},
      new Chore {Name="Devices", Notes="Buy Nexus, Galaxy, Droid", Done=false}
    };

En ViewWillAppear, pase la colección al origen y asígnela a la vista de tabla:

public override void ViewWillAppear(bool animated)
{
    base.ViewWillAppear(animated);

    TableView.Source = new RootTableSource(chores.ToArray());
}

Si ejecuta la aplicación ahora, la pantalla principal se cargará y mostrará una lista de dos tareas. Cuando se toca una tarea, el segue definido por el guion gráfico hará que aparezca la pantalla de detalles, pero no mostrará ningún dato en ese momento.

Para "enviar un parámetro" en un segue, invalide el método PrepareForSegue y establezca las propiedades en el DestinationViewController (TaskDetailViewController en este ejemplo). Se ha creado una instancia de la clase de controlador de vista de destino, pero aún no se muestra al usuario: esto significa que puede establecer las propiedades en la clase, pero no modificar ningún control de interfaz de usuario:

public override void PrepareForSegue (UIStoryboardSegue segue, NSObject sender)
    {
      if (segue.Identifier == "TaskSegue") { // set in Storyboard
        var navctlr = segue.DestinationViewController as TaskDetailViewController;
        if (navctlr != null) {
          var source = TableView.Source as RootTableSource;
          var rowPath = TableView.IndexPathForSelectedRow;
          var item = source.GetItem(rowPath.Row);
          navctlr.SetTask (this, item); // to be defined on the TaskDetailViewController
        }
      }
    }

En TaskDetailViewController, el método SetTask asigna sus parámetros a las propiedades para que se les pueda hacer referencia en ViewWillAppear. No se pueden modificar las propiedades del control en SetTask porque puede que no existan cuando se llame a PrepareForSegue:

Chore currentTask {get;set;}
    public ItemViewController Delegate {get;set;} // will be used to Save, Delete later

public override void ViewWillAppear (bool animated)
    {
      base.ViewWillAppear (animated);
      TitleText.Text = currentTask.Name;
      NotesText.Text = currentTask.Notes;
      DoneSwitch.On = currentTask.Done;
    }

    // this will be called before the view is displayed
    public void SetTask (ItemViewController d, Chore task) {
      Delegate = d;
      currentTask = task;
    }

El segue ahora abrirá la pantalla de detalles y mostrará la información de la tarea seleccionada. Desafortunadamente, no hay ninguna implementación para los botones Guardar y Eliminar. Antes de implementar los botones, agregue estos métodos a ItemViewController.cs para actualizar los datos subyacentes y cerrar la pantalla de detalles:

public void SaveTask(Chores chore)
{
  var oldTask = chores.Find(t => t.Id == chore.Id);
        NavigationController.PopViewController(true);
}

public void DeleteTask(Chores chore)
{
  var oldTask = chores.Find(t => t.Id == chore.Id);
  chores.Remove(oldTask);
        NavigationController.PopViewController(true);
}

A continuación, deberá agregar el controlador de eventos TouchUpInside del botón al método ViewDidLoad de TaskDetailViewController.cs. La referencia de la propiedad Delegate a ItemViewController se ha creado específicamente para que podamos llamar a SaveTask y DeleteTask, que cierran esta vista como parte de su operación:

SaveButton.TouchUpInside += (sender, e) => {
        currentTask.Name = TitleText.Text;
        currentTask.Notes = NotesText.Text;
        currentTask.Done = DoneSwitch.On;
        Delegate.SaveTask(currentTask);
      };

DeleteButton.TouchUpInside += (sender, e) => Delegate.DeleteTask(currentTask);

La última parte restante de la funcionalidad que se va a compilar es la creación de nuevas tareas. En ItemViewController.cs, agregue un método que cree nuevas tareas y abra la vista de detalles. Para crear una instancia de una vista desde un guion gráfico, use el método InstantiateViewController con Identifier para esa vista; en este ejemplo, será "detalle":

public void CreateTask () 
    {
      // first, add the task to the underlying data
      var newId = chores[chores.Count - 1].Id + 1;
      var newChore = new Chore{Id = newId};
      chores.Add (newChore);

      // then open the detail view to edit it
      var detail = Storyboard.InstantiateViewController("detail") as TaskDetailViewController;
      detail.SetTask (this, newChore);
      NavigationController.PushViewController (detail, true);
    }

Por último, conecte el botón en la barra de navegación en el método ViewDidLoad de ItemViewController.cs para llamarlo:

AddButton.Clicked += (sender, e) => CreateTask ();

Esto completa el ejemplo de Storyboard: la aplicación finalizada tiene el siguiente aspecto:

Aplicación finalizada

En el ejemplo se muestra lo siguiente:

  • Creación de una tabla con contenido de prototipo donde se definen celdas para su reutilización para mostrar listas de datos.
  • Creación de una tabla con contenido estático para crear un formulario de entrada. Esto incluía cambiar el estilo de tabla y agregar secciones, celdas y controles de interfaz de usuario.
  • Cómo crear un segue e invalidar el método PrepareForSegue para notificar a la vista de destino cualquier parámetro que requiera.
  • Carga de vistas de guion gráfico directamente con el método Storyboard.InstantiateViewController.