Статьи

iOS с нуля с помощью Swift: навигационные контроллеры и иерархии контроллеров представлений

В iOS навигационные контроллеры являются одним из основных инструментов для представления нескольких экранов контента. В этой статье вы узнаете, как использовать навигационные контроллеры, создав приложение для просмотра книг библиотеки.

В предыдущем уроке вы узнали, что класс табличного представления UIKit отлично подходит для представления табличных или столбчатых данных. Однако, когда контент должен быть распределен по нескольким экранам, навигационный контроллер часто является предпочтительным инструментом. Класс UINavigationController реализует этот тип функциональности.

Как и любой другой подкласс UIViewController , контроллер навигации управляет представлением, экземпляром класса UIView . Представление контроллера навигации управляет несколькими подпредставлениями, включая панель навигации вверху, представление, содержащее пользовательский контент, и дополнительную панель инструментов внизу. Что делает контроллер навигации особенным, так это то, что он создает и управляет иерархией контроллеров представления, часто называемой стеком навигации .

В этой статье мы создадим новое приложение для iOS, чтобы ознакомиться с классом UINavigationController . Вы узнаете, что комбинация контроллера навигации и стека контроллеров представления (таблицы) представляет собой элегантное и мощное решение для представления вложенных наборов данных.

В дополнение к UINavigationController вы также встретите UITableViewController в этом учебном пособии, еще UIViewController подкласс UIViewController . UITableViewController управляет экземпляром UITableView вместо экземпляра UIView . Контроллеры табличного представления автоматически принимают протоколы UITableViewDataSource и UITableViewDelegate , и это сэкономит нам некоторое время.

Приложение, которое мы собираемся создать, называется Library . С помощью этого приложения пользователи могут просматривать список авторов и просматривать книги, которые они написали. Список авторов представлен в виде таблицы.

Если пользователь нажимает на имя автора, анимируется список книг, написанных этим автором. Точно так же, когда пользователь выбирает заголовок из списка книг, на экране появляется другой вид, показывающий изображение обложки книги. Давайте создадим новый проект XCode, чтобы начать нас.

Откройте Xcode, создайте новый проект, выбрав New> Project … в меню File , и выберите шаблон Single View Application из списка iOS> Шаблоны приложений .

Выбор шаблона проекта

Назовите библиотеку проекта и назначьте название и идентификатор организации. Установите язык на Swift и устройства на iPhone . Сообщите Xcode, где вы хотите сохранить проект, и нажмите « Создать» .

Конфигурирование проекта

Шаблон приложения Single View содержит класс делегата приложения, AppDelegate , раскадровку, Main.storyboard и подкласс ViewController , ViewController . Откройте AppDelegate.swift и взгляните на реализацию application(_:didFinishLaunchingWithOptions:) . Его реализация коротка и должна выглядеть уже знакомой.

1
2
3
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
    return true
}

Исходные файлы этого руководства содержат данные, которые мы будем использовать. Вы можете найти их в папке « Ресурсы» . Он включает в себя список свойств Books.plist , содержащий информацию об авторах, написанных ими книгах, некоторую информацию о каждой книге и изображение для каждой книги, включенной в список свойств.

Перетащите папку « Ресурсы » в свой проект, чтобы добавить их в проект. Xcode покажет вам несколько вариантов, когда вы добавите папку в проект. Обязательно установите флажок Копировать элементы, если это необходимо, и не забудьте добавить файлы в целевую библиотеку .

Добавить ресурсы в проект
Копирование элементов в целевую папку группы

Прежде чем продолжить, я хочу немного поговорить о списках свойств и о том, что они собой представляют. Список свойств — это не что иное, как представление графа объектов. Как мы видели ранее в этой серии, объектный граф — это группа объектов, образующих сеть через соединения или ссылки, которыми они делятся друг с другом.

Легко читать и записывать списки свойств с диска и на диск, что делает их идеальными для хранения небольших объемов данных. При работе со списками свойств также важно помнить, что в списках свойств могут храниться только определенные типы данных, такие как строки, числа, даты, массивы, словари и двоичные данные.

Xcode делает просмотр списков свойств очень простым. Выберите Books.plist из папки « Ресурсы », которую вы добавили в проект, и просмотрите ее содержимое с помощью встроенного редактора списка свойств XCode. Это будет полезным инструментом позже в этой статье, когда мы начнем работать с содержимым Books.plist .

Просмотр списка свойств в Xcode

Прежде чем мы сможем начать использовать данные, хранящиеся в Books.plist , мы должны сначала заложить некоторые основы. Это включает в себя создание контроллера представления, который управляет представлением таблицы и отображает авторов, перечисленных в списке свойств.

В предыдущей статье мы создали подкласс UIViewController и добавили табличное представление в представление контроллера представления для представления данных пользователю. В этом уроке мы используем ярлык подкласса UITableViewController .

Начните с удаления ViewController.swift из вашего проекта. Создайте новый класс, выбрав New> File … в меню File . Выберите шаблон Cocoa Touch Class в списке iOS> Исходные шаблоны.

Создайте новый класс касания какао

Назовите новый класс AuthorsViewController и сделайте его подклассом UITableViewController . Нет необходимости устанавливать флажок. Также создайте файл XIB для пользовательского интерфейса , потому что мы будем использовать раскадровку для создания пользовательского интерфейса приложения.

Настройте новый класс касания какао

Откройте Main.storyboard, чтобы заменить контроллер представления в раскадровке контроллером представления таблицы. Выберите контроллер представления в раскадровке, нажмите клавишу удаления и перетащите UITableViewController   Экземпляр из библиотеки объектов справа. Выберите новый контроллер представления, откройте Identity Inspector справа и установите для его класса значение AuthorsViewController .

Добавление контроллера табличного представления

В предыдущей статье мы использовали клетки-прототипы для заполнения табличного представления. В этом уроке я покажу вам альтернативный подход. Выберите объект табличного представления в рабочей области или в списке объектов слева, откройте инспектор атрибутов справа и установите ячейки прототипа в 0 .

Удалить прототип клетки

Каждой раскадровке нужен начальный контроллер вида. Это контроллер представления, который создается при загрузке раскадровки. Мы можем пометить контроллер представления авторов как начальный контроллер представления, выбрав слева объект « Контроллер представления авторов» , открыв инспектор атрибутов справа и установив флажок « Начальный контроллер представления» .

Откройте AuthorsViewController.swift и проверьте содержимое файла. Поскольку AuthorsViewController является подклассом UITableViewController , AuthorsViewController уже соответствует протоколам UITableViewDataSource и UITableViewDelegate .

Прежде чем мы сможем отобразить данные в табличном представлении, нам нужны данные для отображения. Как я упоминал ранее, данные, содержащиеся в Books.plist, служат источником данных табличного представления. Чтобы использовать эти данные, нам сначала нужно загрузить их в объект, а точнее в массив.

Мы объявляем authors свойства переменной и устанавливаем ее начальное значение в пустой массив типа [AnyObject] . Помните, что тип AnyObject может представлять любой класс или структуру.

Метод viewDidLoad() контроллера представления является хорошим местом для загрузки данных из Books.plist в свойство authors контроллера представления. Мы делаем это, вызывая init(contentsOfFile:) класса NSArray . Мы [AnyObject] полученный объект к экземпляру типа [AnyObject] .

1
authors = NSArray(contentsOfFile: path) as!

Метод принимает путь к файлу, что означает, что нам нужно выяснить, каков путь к файлу Books.plist . Файл Books.plist находится в комплекте приложений, который представляет собой необычное слово для каталога, который содержит исполняемый файл приложения и ресурсы приложения, такие как изображения и звуки.

Чтобы получить путь к файлу Books.plist , нам сначала понадобится ссылка на основной пакет приложения путем вызова mainBundle() класса NSBundle . Следующий шаг — запросить у пакета приложения путь к одному из его ресурсов, Books.plist . Мы вызываем pathForResource(_:ofType:) в основном комплекте приложения, передавая имя и тип (расширение) интересующего нас файла. Мы сохраняем путь к файлу в константе filePath .

1
let filePath = NSBundle.mainBundle().pathForResource(«Books», ofType: «plist»)

Поскольку возможно, что мы запрашиваем ресурс, которого нет в комплекте приложений, pathForResource(_:ofType:) возвращает необязательный параметр. Как правило, если метод может вернуть nil , следует использовать необязательный параметр. Константа filePath имеет тип String? , Чтобы безопасно развернуть необязательное, мы используем необязательное связывание, которое мы обсуждали ранее в этой серии.

Если мы объединим эти две части, мы получим следующую реализацию viewDidLoad() . Я также добавил оператор print для вывода содержимого свойства authors в консоль. Это позволяет нам взглянуть на его содержание.

01
02
03
04
05
06
07
08
09
10
override func viewDidLoad() {
    super.viewDidLoad()
     
    let filePath = NSBundle.mainBundle().pathForResource(«Books», ofType: «plist»)
     
    if let path = filePath {
        authors = NSArray(contentsOfFile: path) as!
        print(authors)
    }
}

Если вы читали предыдущую статью этой серии, заполнение табличного представления должно быть простым. Поскольку табличное представление содержит только один раздел, реализация numberOfSectionsInTableView(_:) является простой. AuthorsViewController наследуется от UITableViewController , который уже соответствует и реализует протокол UITableViewDataSource . Вот почему нам нужно использовать ключевое слово override . Мы переопределяем метод, который реализован родительским классом.

1
2
3
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
    return 1
}

Количество строк в единственном разделе табличного представления равно количеству авторов в массиве authors поэтому все, что нам нужно сделать, это подсчитать элементы массива.

1
2
3
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return authors.count
}

Реализация tableView(_:cellForRowAtIndexPath:) аналогична той, что мы видели в предыдущей статье. Основное различие заключается в том, как мы выбираем данные, отображаемые в ячейке табличного представления.

Массив авторов содержит упорядоченный список словарей, каждый из которых содержит две пары ключ-значение. Объект для ключа с именем Author имеет тип String , тогда как объект для ключа Books представляет собой массив словарей, каждый из которых представляет книгу, написанную автором. Откройте Books.plist в XCode, чтобы проверить структуру источника данных, если это не совсем ясно.

Прежде чем мы реализуем tableView(_:cellForRowAtIndexPath:) , нам нужно позаботиться о двух вещах. Сначала мы объявляем константу для идентификатора повторного использования ячейки, который мы будем использовать.

01
02
03
04
05
06
07
08
09
10
11
import UIKit
 
class AuthorsViewController: UITableViewController {
 
    let CellIdentifier = «Cell Identifier»
     
    var authors = [AnyObject]()
     
    …
 
}

Во-вторых, мы вызываем registerClass(_:forCellReuseIdentifier:) для табличного представления, передавая UITableViewCell.classForCoder() и идентификатор повторного использования ячейки. Мы вызываем этот метод в viewDidLoad() чтобы убедиться, что он вызывается только один раз.

01
02
03
04
05
06
07
08
09
10
11
12
override func viewDidLoad() {
    super.viewDidLoad()
     
    let filePath = NSBundle.mainBundle().pathForResource(«Books», ofType: «plist»)
     
    if let path = filePath {
        authors = NSArray(contentsOfFile: path) as!
        print(authors)
    }
     
    tableView.registerClass(UITableViewCell.classForCoder(), forCellReuseIdentifier: CellIdentifier)
}

Учитывая вышесказанное, реализация tableView(_:cellForRowAtIndexPath:) становится довольно короткой.

01
02
03
04
05
06
07
08
09
10
11
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
    // Dequeue Resuable Cell
    let cell = tableView.dequeueReusableCellWithIdentifier(CellIdentifier, forIndexPath: indexPath)
     
    if let author = authors[indexPath.row] as?
        // Configure Cell
        cell.textLabel?.text = name
    }
     
    return cell;
}

Обратите внимание, что мы связываем необязательные привязки запятой. Это удобный подход, чтобы избежать вложенных операторов if . Мы запрашиваем у authors элемент indexPath.row и indexPath.row его до [String: AnyObject] . Поскольку нам нужно имя автора, мы запрашиваем у author значение ключа "Author" , понижая результат до String .

Добавить контроллер навигации легко с помощью раскадровки. Однако, прежде чем мы добавим навигационный контроллер, важно понять, как работают навигационные контроллеры на iOS.

Как и любой другой подкласс UIViewController , контроллер навигации управляет экземпляром UIView . Представление контроллера навигации управляет несколькими подпредставлениями, включая панель навигации вверху, представление, содержащее пользовательский контент, и дополнительную панель инструментов внизу. Уникальным контроллером навигации является то, что он управляет стеком контроллеров представления.

Стек навигации

Термин стек практически можно понимать буквально. Когда навигационный контроллер инициализируется, навигационному контроллеру предоставляется корневой контроллер вида. Корневой контроллер представления — это контроллер представления в нижней части стека навигации .

При перемещении другого контроллера представлений в стек навигации представление корневого контроллера представлений заменяется представлением нового контроллера представлений. При работе с контроллерами навигации видимым видом всегда является вид самого верхнего контроллера вида стека навигации.

Когда контроллер представления удален или извлечен из стека навигации, представление контроллера представления ниже этого становится снова видимым. Выдвигая и вставляя контроллеры представления в и из стека навигации контроллера навигации, создается иерархия представления, и, как результат, вложенный набор данных может быть представлен пользователю. Давайте посмотрим, как все это работает на практике.

Пересмотрите раскадровку проекта ( Main.storyboard ) и выберите контроллер представления. Чтобы добавить контроллер навигации в микс, выберите « Встроить»> «Контроллер навигации» в меню « Редактор» . Несколько вещей меняются:

  • контроллер навигации становится контроллером начального представления раскадровки
  • добавлена ​​новая сцена с названием Navigation Control Scene
  • добавлена ​​панель навигации в контроллер навигации и просмотра авторов
  • контроллер навигации и контроллер представления авторов связаны
Добавление контроллера навигации

Сеги распространены в раскадровках, и мы узнаем о них больше позже в этой серии. Существуют различные виды переходов, и переход, соединяющий контроллер навигации и контроллер представления авторов, является переходом отношений .

Каждый контроллер навигации имеет корневой контроллер представления, контроллер представления внизу стека навигации. Он не может быть извлечен из стека навигации, потому что контроллеру навигации всегда нужен контроллер представления, чтобы показать пользователю. Отношения между контроллером навигации и контроллером представления авторов символизируют, что последний является корневым контроллером представления контроллера навигации.

Панель навигации в верхней части контроллера навигации и контроллера представления авторов — это то, что вы получаете бесплатно при работе с контроллерами навигации. Это экземпляр UINavigationBar и помогает перемещаться по стеку навигации.

Хотя контроллер навигации является начальным контроллером представления раскадровки, контроллер представления авторов является первым контроллером представления, который мы увидим при запуске приложения. Как я упоминал ранее, контроллер навигации является не более чем оболочкой, которая помогает перемещаться между иерархией контроллеров представления. Его представление заполняется представлениями контроллеров представления в его стеке навигации.

Чтобы добавить заголовок на панель навигации, добавьте следующую строку в метод viewDidLoad() класса AuthorsViewController .

1
2
// Set Title
title = «Authors»

Каждый контроллер представления имеет свойство title , которое используется в разных местах. Панель навигации является одним из них. Запустите приложение, чтобы увидеть результат этого небольшого изменения.

Давайте теперь добавим возможность видеть список книг, когда пользователь нажимает на имя автора. Это означает, что нам нужно захватить выборку (имя автора), создать новый контроллер представления на основе этого выбора и поместить новый контроллер представления в стек навигации. Это звучит сложно? Это не. Позволь мне показать тебе.

Почему бы не отобразить список книг в другом табличном представлении. Создайте новый подкласс UITableViewController и назовите его BooksViewController .

Создайте класс BooksViewController

Загрузка списка книг проста, как мы видели ранее, но как контроллер представления книг узнает, какого автора коснулся пользователь? Есть несколько способов сообщить новому контроллеру представления о выборе пользователя, но подход, который рекомендует Apple, известен как передача по ссылке . Как это работает?

Контроллер просмотра книг объявляет свойство author которое мы можем установить для настройки контроллера просмотра книг. Контроллер просмотра книг использует свойство author для отображения книг выбранного автора. Откройте BooksViewController.swift и добавьте свойство переменной типа [String: AnyObject]! и назовите его author .

1
2
3
4
5
6
7
8
9
import UIKit
 
class BooksViewController: UIViewController {
 
    var author: [String: AnyObject]!
     
    …
     
}

Почему бы нам не объявить author как [String: AnyObject]? или [String: AnyObject] ? Поскольку переменная должна иметь начальное значение, мы не можем объявить author как [String: AnyObject] . Мы могли бы использовать [String: AnyObject]? , но это будет означать, что нам придется разворачивать опцию каждый раз, когда мы хотим получить доступ к ее значению.

В Swift вы обычно будете использовать принудительно развернутые необязательные параметры, если знаете, что свойство имеет значение, и, что более важно, если оно должно иметь значение, чтобы ваше приложение работало должным образом. Если свойство author не имеет значения, то контроллер представления книг нам мало пригодится, поскольку он не сможет отображать какие-либо данные.

Чтобы упростить доступ к книгам автора, мы также объявляем вычисленное свойство. Как следует из названия, вычисляемое свойство не хранит значение. Он определяет метод получения и / или установки для получения и установки значения другого свойства. Взгляните на books компьютерной собственности ниже.

1
2
3
4
5
6
7
8
9
var books: [AnyObject] {
    get {
        if let books = author[«Books»] as?
            return books
        } else {
            return [AnyObject]()
        }
    }
}

Ценность books зависит от ценности author . Мы проверяем, есть ли у автора значение для ключа "Books" и понижаем значение до массива объектов AnyObject . Если у автора нет значения для "Books" мы создаем пустой массив типа [AnyObject] . Поскольку вычисляемое свойство books определяет только геттер, мы можем упростить реализацию следующим образом:

1
2
3
4
5
6
7
var books: [AnyObject] {
    if let books = author[«Books»] as?
        return books
    } else {
        return [AnyObject]()
    }
}

Остальная часть класса BooksViewController проста. Взгляните на реализации трех методов протокола UITableViewDataSource , показанных ниже.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
    return 1
}
 
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return books.count
}
 
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
    // Dequeue Resuable Cell
    let cell = tableView.dequeueReusableCellWithIdentifier(CellIdentifier, forIndexPath: indexPath)
     
    if let book = books[indexPath.row] as?
        // Configure Cell
        cell.textLabel?.text = title
    }
     
    return cell;
}

Это также означает, что нам нужно объявить постоянное свойство для идентификатора повторного использования ячейки и зарегистрировать класс для повторного использования ячейки в viewDidLoad() . Это не что-то новое.

1
2
3
4
5
6
7
8
9
import UIKit
 
class BooksViewController: UITableViewController {
 
    let CellIdentifier = «Cell Identifier»
     
    …
     
}
1
2
3
4
5
override func viewDidLoad() {
    super.viewDidLoad()
     
    tableView.registerClass(UITableViewCell.classForCoder(), forCellReuseIdentifier: CellIdentifier)
}

Когда пользователь нажимает на имя автора в контроллере представления авторов, приложение должно отображать список книг, написанных этим автором. Это означает, что нам нужно создать экземпляр класса BooksViewController , сообщить экземпляру, какой автор был выбран пользователем, и поместить новый контроллер представления в стек навигации.

Раскадровка поможет нам в этом. Откройте Main.storyboard , перетащите другой UITableViewController экземпляр из библиотеки объектов , и установите его класс для BooksViewController в Identity Inspector .

Добавить контроллер просмотра книг в раскадровку

Выберите табличное представление в новом контроллере представления и установите число Ячеек Прототипа равным 0 в Инспекторе Атрибутов . Чтобы поместить контроллер представления книг в навигационный стек контроллера навигации, нам нужно создать еще один переход. На этот раз, однако, мы создаем ручной переход Шоу, если быть точным.

Выберите контроллер представления авторов в раскадровке, удерживайте нажатой клавишу « Control» и перетащите его из контроллера представления авторов в контроллер представления книг. Выберите Manual Segue> Show из меню, которое появляется, чтобы создать переход от контроллера представления авторов к контроллеру представления книг.

Создать руководство Show Segue

Есть еще одна вещь, которую мы должны сделать, прежде чем вернуться к реализации контроллера просмотра книг. Выберите созданный нами переход, откройте инспектор атрибутов справа и установите для идентификатора перехода значение BooksViewController . Задав имя segue, мы можем обратиться к нему позже в коде.

Установка идентификатора Segue

Чтобы использовать результат, нам нужно реализовать tableView(_:didSelectRowAtIndexPath:) в контроллере представления авторов. Этот метод определен в протоколе UITableViewDelegate , как мы видели в предыдущей статье о табличных представлениях. В этом методе мы вызываем performSegueWithIdentifier(_:sender:) для выполнения перехода, который мы создали в раскадровке. Метод performSegueWithIdentifier(_:sender:) принимает два аргумента: идентификатор segue и отправителя сообщения. Теперь должно быть понятно, почему мы дали segue идентификатор в раскадровке? Также обратите внимание, что мы сбрасываем выбор после выполнения перехода.

1
2
3
4
5
6
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
    // Perform Segue
    performSegueWithIdentifier(SegueBooksViewController, sender: self)
     
    tableView.deselectRowAtIndexPath(indexPath, animated: true)
}

Константа SegueBooksViewController — это еще одно свойство AuthorsViewController класса AuthorsViewController .

01
02
03
04
05
06
07
08
09
10
import UIKit
 
class AuthorsViewController: UITableViewController {
 
    let CellIdentifier = «Cell Identifier»
    let SegueBooksViewController = «BooksViewController»
     
    …
 
}

Перед выполнением перехода контроллер представления имеет возможность подготовиться к prepareForSegue(_:sender:) в prepareForSegue(_:sender:) . В этом методе контроллер представления может сконфигурировать целевой контроллер представления, контроллер представления книг. Давайте реализуем prepareForSegue(_:sender:) чтобы увидеть, как это работает.

1
2
3
4
5
6
7
8
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
    if segue.identifier == SegueBooksViewController {
        if let indexPath = tableView.indexPathForSelectedRow, let author = authors[indexPath.row] as?
            let destinationViewController = segue.destinationViewController as!
            destinationViewController.author = author
        }
    }
}

Этот метод вызывается всякий раз, когда выполняется переход. Сначала мы проверяем, равен ли SegueBooksViewController . Затем мы запрашиваем в табличном представлении индексный путь текущего выделения, используя необязательную привязку. Если выбрана строка, мы просим authors указать автора, который соответствует этому выбору.

В операторе if мы получаем ссылку на контроллер представления книг (контроллер представления назначения в segue) и устанавливаем его свойство author для текущего выбранного автора в табличном представлении.

Вам может быть интересно, когда или где мы инициализируем контроллер просмотра книг? Мы не создаем явно экземпляр экземпляра контроллера представления книг. Раскадровка знает, какой класс ему нужен для создания экземпляра, и инициализирует для нас экземпляр BooksViewController .

Перед запуском приложения откройте BooksViewController.swift и задайте в заголовке контроллера представления имя автора, чтобы обновить заголовок панели навигации.

1
2
3
4
5
6
7
8
9
override func viewDidLoad() {
    super.viewDidLoad()
     
    if let name = author[«Author»] as?
        title = name
    }
     
    tableView.registerClass(UITableViewCell.classForCoder(), forCellReuseIdentifier: CellIdentifier)
}

Запустите приложение. Нажмите на имя автора в табличном представлении и посмотрите, как новый экземпляр BooksViewController в стек навигации и отображается для пользователя. Вы заметили, что мы также получаем кнопку возврата бесплатно при использовании контроллера навигации. Заголовок предыдущего контроллера представления используется в качестве заголовка кнопки возврата.

Когда пользователь нажимает на книгу в контроллере просмотра книг, приложение должно показать обложку книги. Для этого мы не будем использовать контроллер табличного представления. Вместо этого мы используем простой ванильный подкласс UIViewController и отображаем обложку книги в экземпляре класса UIImageView . UIImageView — это подкласс UIView специализирующийся на отображении изображений.

Создайте новый подкласс UIViewController — не UITableViewController — и назовите его BookCoverViewController .

Создание класса BookCoverViewController

Нам нужно объявить два сохраненных свойства в новом контроллере представления. Первое сохраненное свойство — это ссылка на представление изображения, которое мы будем использовать для отображения обложки книги. @IBOutlet слово @IBOutlet указывает, что мы установим соединение в раскадровке. Второе сохраненное свойство, Book , имеет тип [String: String]! , Это свойство представляет книгу, которая отображается в контроллере представления обложки книги.

01
02
03
04
05
06
07
08
09
10
11
import UIKit
 
class BookCoverViewController: UIViewController {
 
    @IBOutlet var bookCoverView: UIImageView!
     
    var book: [String: String]!
     
    …
 
}

Откройте Main.storyboard, чтобы создать пользовательский интерфейс контроллера представления книги. Перетащите экземпляр UIViewController из библиотеки объектов в рабочую область и установите для его класса значение BookCoverViewController в Identity Inspector .

Добавление View Controller в рабочую область

Перетащите экземпляр UIImageView из библиотеки объектов в представление контроллера представления и сделайте так, чтобы он охватывал весь вид контроллера представления. В инспекторе подключений подключите его к bookCoverView контроллера представления.

Добавление представления изображения

Чтобы убедиться, что изображение отображается правильно на каждом устройстве, нам нужно применить необходимые ограничения макета, как показано ниже.

Добавление ограничений макета в представление изображения

Прежде, чем мы реализуем контроллер представления, создадим последовательный переход между контроллером представления книг и контроллером представления обложки книги. Выберите переход и установите его идентификатор в BookCoverViewController в Атрибуты инспектора .

Создание перехода к контроллеру представления обложки книги

в Класс BooksViewController , объявляет постоянное свойство для идентификатора segue.

01
02
03
04
05
06
07
08
09
10
import UIKit
 
class BooksViewController: UITableViewController {
 
    let CellIdentifier = «Cell Identifier»
    let SegueBookCoverViewController = «BookCoverViewController»
     
    …
 
}

Мы используем это свойство в tableView(_:didSelectRowAtIndexPath:) чтобы выполнить переход, который мы создали в раскадровке. Не забудьте отменить выбор строки после выполнения перехода.

1
2
3
4
5
6
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
    // Perform Segue
    performSegueWithIdentifier(SegueBookCoverViewController, sender: self)
     
    tableView.deselectRowAtIndexPath(indexPath, animated: true)
}

Реализация prepareForSegue(_:sender:) выглядит очень похоже на BooksViewController класса BooksViewController . Мы проверяем, равен ли идентификатор SegueBookCoverViewController и запрашиваем в табличном представлении путь индекса для текущей выбранной строки. Мы просим books для книги, которая соответствует выбору пользователя, и устанавливаем свойство книги целевого контроллера представления, экземпляра BookCoverViewController .

1
2
3
4
5
6
7
8
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
    if segue.identifier == SegueBookCoverViewController {
        if let indexPath = tableView.indexPathForSelectedRow, let book = books[indexPath.row] as?
            let destinationViewController = segue.destinationViewController as!
            destinationViewController.book = book
        }
    }
}

Мы настраиваем представление изображений класса BookCoverViewController в его viewDidLoad() . Мы запрашиваем у book значение ключа "Cover" и UIImage экземпляр объекта UIImage , вызывая init(named:) , передавая имя файла. Мы присваиваем объект UIImage свойству image bookCoverView .

1
2
3
4
5
6
7
8
override func viewDidLoad() {
    super.viewDidLoad()
     
    if let fileName = book[«Cover»] {
        bookCoverView.image = UIImage(named: fileName)
        bookCoverView.contentMode = .ScaleAspectFit
    }
}

В viewDidLoad() мы также устанавливаем режим содержимого представления изображения на ScaleAspectFit . Свойство contentMode имеет тип UIViewContentMode , перечисление. ScaleAspectFit нами значение, ScaleAspectFit , указывает виду изображения максимально растягивать изображение при соблюдении его пропорций.

Запустите приложение и возьмите его на себя. Теперь вы сможете просматривать книги, хранящиеся в Books.plist .

Ранее в этой статье я объяснил, что контроллеры представления могут быть вставлены и извлечены из стека навигации. До сих пор мы только помещали контроллеры представления в стек навигации. Извлечение контроллера представления из стека навигации происходит, когда пользователь нажимает кнопку «Назад» на панели навигации. Это еще одна функциональность, которую мы получаем бесплатно.

Однако в какой-то момент вы столкнетесь с ситуацией, когда вам нужно вручную извлечь контроллер представления из стека навигации. Вы можете сделать это, вызвав popViewControllerAnimated(_:) на контроллере представления навигации. Это удаляет самый верхний контроллер представления из стека навигации.

Кроме того, вы можете извлечь все контроллеры представления из стека навигации — за исключением корневого контроллера представления — вызвав popToRootViewControllerAnimated(_:) на контроллере навигации.

Как вы получаете доступ к навигационному контроллеру контроллера представления? Класс UIViewController объявляет вычисляемое свойство navigationController типа UINavigationController? , Если контроллер представления находится в стеке навигации, то это свойство ссылается на контроллер навигации, к которому принадлежит стек навигации.

Я надеюсь, вы согласны с тем, что навигационные контроллеры не так сложны. Эта статья могла бы быть намного короче, но я надеюсь, что вы узнали еще несколько вещей на этом пути. В следующей статье мы рассмотрим контроллеры панели вкладок. Несмотря на то, что контроллеры панели вкладок также управляют набором контроллеров представления, они весьма отличаются от контроллеров навигации.

Если у вас есть какие-либо вопросы или комментарии, вы можете оставить их в комментариях ниже или обратиться ко мне в Twitter .