Этот учебник является продолжением проекта чтения iPad в « Войне миров » и продемонстрирует, как перемещаться по PDF с помощью UISlider при использовании проекта «Листья». Попутно мы сделаем несколько эстетических изменений, чтобы сделать интерфейс немного более захватывающим.
Где мы остановились
В уроке , представленном на прошлой неделе , я познакомил вас с проектом с открытым исходным кодом Leaves и продемонстрировал, как настроить базовый PDF-ридер. Тем не менее, базовая реализация Leaves оставляла желать лучшего с точки зрения пользовательского опыта. В частности, я предложил следующие улучшения:
- Содержание
- UISlider для навигации
- закладки
- Поиск
- Особенности
60% участников опроса проголосовали за просмотр дополнительных руководств по добавлению оглавления или UISlider, так что именно этого мы и добьемся сегодня. В этот пост был включен еще один опрос, поэтому, если вы хотите, чтобы в этот проект были добавлены дополнительные функции или предпочли бы перейти к другой теме iOS SDK, дайте мне знать!
Предварительный просмотр учебника
Это видео демонстрация того, что создаст этот урок:
В конце этого урока вы должны хорошо понимать, как UISlider
объект UISlider
и лучше понимать внутреннее устройство проекта Leaves.
Шаг 1: Добавьте космический фон
Мы начнем с подготовки интерфейса к использованию UISlider
. Я экспериментировал с несколькими различными подходами здесь, но в итоге я решил остановиться на дизайне, которого не видел больше нигде: я сократил показ книги, центрировал ее по центру экрана, а затем добавил фон некоторых далекая галактика для тематического эффекта. Затем я просто сосредоточил UISlider
под книгой. Мне действительно очень нравится, как это получилось, но я охотно признаю, что это не самый практичный подход. При создании приложения для чтения имеет смысл, чтобы текст покрывал весь экран, как это было в нашей последней сборке проекта, но плюсом в добавлении некоторого отступа вокруг книги является то, что вы потенциально можете создать более захватывающий пользовательский интерфейс. Это то, что я пытался сделать здесь.
Чтобы сделать то же самое, откройте файл WOTWViewController.xib . Перетащите UIImage
на представление iPad и UIImage
размер этого изображения на весь экран (убедитесь, что вид установлен в портретный режим). Затем выберите инспектора атрибутов для UIImage
и установите для поля изображения значение «space.png» (вы можете найти этот файл в папке «Ресурсы» для загрузки этого сообщения). Теперь у нас есть намного более прохладное фоновое изображение для проекта. Это можно легко настроить для жанра, отличного от научной фантастики.
Шаг 2: добавьте навигационный слайдер
Затем перетащите объект UISlider
на представление. UISlider
, перейдите в «Инспектор размеров». Установите ширину объекта на 360, позицию X на 204 и позицию Y на 955. Теперь UISlider должен быть расположен в нижней части экрана и чуть ниже того места, где будет отображаться книга.
Шаг 3. Создание IBOutlet для слайдера
На этом этапе нам нужно синхронизировать UISlider
в Интерфейсном UISlider
со свойством в нашем контроллере представления WOTW. Пока XIB-файл открыт, перейдите на вкладку Assistant Editor на панели инструментов Xcode. В результате откроется окно редактора, в котором должен быть файл WOTWViewController.h (если он содержит другой файл, выберите правильный из значка «Связанные файлы» в левом верхнем углу панели редактора). Теперь нажмите CTRL + клик UISlider
в файле XIB и перетащите линию, которая появляется над панелью окна редактора. Отпустите, когда всплывающее окно гласит «Вставить розетку, Действие или Коллекция розеток». Появится диалоговое окно, предлагающее ввести имя для соединения IBOutlet. Назовите розетку pageSlider
и нажмите «Подключиться». Интерфейсный Разработчик теперь добавит код, необходимый для этого выхода, который будет использоваться в вашем проекте.
Шаг 4. Изменение размера отображения книги
Как упоминалось в первом уроке из этой серии, класс LeavesViewController
содержит UIView
именем leavesView
где фактически происходит рисование страницы. Кадр leavesView
настроен для отражения LeavesViewController
в методе loadView
, как показано ниже:
LeavesViewController.m
1
2
3
4
5
6
|
— (void)loadView {
[super loadView];
leavesView.frame = self.view.bounds;
leavesView.autoresizingMask = UIViewAutoresizingFlexibleWidth|UIViewAutoresizingFlexibleHeight;
[self.view addSubview:leavesView];
}
|
В нашем случае мы хотим, leavesView
рамка leavesView
только подмножество контроллера представления, а не весь экран.
У нас есть несколько вариантов здесь. Казалось бы, самое простое решение — это просто вручную изменить размер кадра leavesView
в строке 3 выше в файле LeavesViewController.m . Однако вы помните, что LeavesViewController
является частью официального кода проекта Leaves, и все наши изменения до сих пор были сделаны в WOTWViewController
, который является подклассом LeavesViewController
. Как правило, это гораздо более приемлемый подход, чем альтернативный: взламывание кода основного проекта для нужд, специфичных для вашей ситуации, а затем постоянная борьба с обновлениями проекта путем повторного объединения или переписывания изменений сообщества. В таком сценарии вы будете сознательно пренебрегать последними стабильными сборками проекта. Вы не хотите застревать в этой ситуации.
Итак, что является лучшей альтернативой? Поскольку мы унаследовали объект leavesView
в WOTWViewController
, мы можем просто внести наши изменения в метод -(void)viewDidLoad
.
В WOTWViewController.m добавьте следующие строки кода:
1
2
3
4
5
6
|
— (void)viewDidLoad
{
[super viewDidLoad];
[self->leavesView setFrame:CGRectMake(0.0f, 0.0f, 563.0f, 845.0f)];
[self->leavesView setCenter:self.view.center];
}
|
В строке 3 выше мы вызываем реализацию LeavesViewController
в loadView
, а затем настраиваем фрейм leavesView
самостоятельно. Строка 4 устанавливает ширину и высоту рамки, которые я нашел подходящими, а строка 5 центрирует рамку в центре нашего контроллера просмотра WOTW.
ПРИМЕЧАНИЕ. Вам интересно, почему я использую прикольный синтаксис для доступа к объекту leavesView
? Кажется, есть ошибка в GCC 4.2.1, которая требует этого. Комментарии с дальнейшим пониманием высоко ценится.
Если вы создаете и запускаете проект сейчас, вы должны увидеть программу WOTW в центре экрана с ползунком внизу для навигации. Конечно, слайдер еще не работает, так что давайте продолжим!
Шаг 5: инициализировать ползунок
Когда наше приложение запускается, мы хотим установить минимальные, максимальные и текущие значения ползунка на основе PDF, загруженного для приложения. Нам также нужно указать, что должно происходить при изменении значения ползунка. Мы сделаем это в файле WOTWViewController.m со следующими строками кода:
01
02
03
04
05
06
07
08
09
10
11
12
|
— (void)viewDidLoad
{
[super viewDidLoad];
[self->leavesView setFrame:CGRectMake(0.0f, 0.0f, 563.0f, 845.0f)];
[self->leavesView setCenter:CGPointMake(self.view.center.x, self.view.center.y — 20.0f)];
[self.pageSlider addTarget:self action:@selector(turnPageWithSlider:) forControlEvents:UIControlEventValueChanged];
self.pageSlider.minimumValue = 0.0;
self.pageSlider.maximumValue = (float) ([self numberOfPagesInLeavesView:self->leavesView] — 1);
self.pageSlider.value = self->leavesView.currentPageIndex;
}
|
В строке 8 выше устанавливается селектор, который должен вызываться при изменении значения ползунка. По умолчанию селектор будет вызываться непрерывно при перемещении ползунка. Однако вы можете отключить это, установив continuous
значение ползунка в «NO», что вызовет селектор только после того, как кнопка ползунка отпущена.
Строка 9 выше устанавливает минимальное значение равное 0. Это подходит, потому что PDF-файл в листьях имеет индекс на основе 0.
В строке 10 выше вызывается метод numberOfPagesInLeavesView:
для установки максимального значения ползунка, а также корректируется индекс на основе 0 путем вычитания 1 из результата.
Наконец, строка 11 устанавливает текущее значение ползунка для свойства leavesView
.
Шаг 6: Добавить страницу очистки
Теперь мы напишем логику, которая должна происходить, когда turnPageWithSlider:
селектор turnPageWithSlider:
.
Добавьте следующий код в файл реализации WOTW:
1
2
3
4
5
6
|
— (void)turnPageWithSlider:(id)sender
{
int pageIndex = (int) [self.pageSlider value];
[self.pageSlider setValue:(float)pageIndex];
self->leavesView.currentPageIndex = pageIndex;
}
|
Значение, возвращаемое из UISlider
имеет тип данных float
. В строке 3 выше мы приводим это значение к целому числу и сохраняем его в переменной pageIndex
.
В строке 4 мы делаем обратное: передаем pageIndex
в pageIndex
float, а затем обновляем значение ползунка. В чем смысл? Разве это не избыточно? Нет, потому что когда мы приводим значение ползунка к целому числу, мы обрезаем остаток. Это важно, потому что мы не хотим переходить, например, на страницу 1.23 или 20.56, мы хотим перейти на страницу 1 или 20. Этот шаг вынуждает пользователя просматривать PDF-файл так, как это, вероятно, ожидается.
В строке 5 выше leavesView
свойство leavesView
, которое также автоматически leavesView
обновление отображения книги.
Если вы соберете и запустите проект сейчас, вы сможете просмотреть книгу. Однако отсутствует одна важная деталь: если вы переворачиваете страницы, перетаскивая их вручную, значение ползунка остается прежним. Для этого нам нужно подключиться к делегату LeavesView.
Шаг 7: Синхронизируйте ползунок
Пользовательское представление Leaves предоставляет несколько методов делегата, которые вызываются в ключевых точках анимации. Одним из них является leavesView:didTurnToPageAtIndex:
Добавьте следующую логику, чтобы обновить ползунок при вызове этого метода делегата:
1
2
3
4
5
6
7
|
— (void) leavesView:(LeavesView *)leavesView didTurnToPageAtIndex:(NSUInteger)pageIndex
{
if((int) self.pageSlider.value != pageIndex)
{
self.pageSlider.value = (float) pageIndex;
}
}
|
С приведенным выше кодом наша реализация слайдера должна быть завершена
Должен ли я продолжить эту серию?
Как я уже упоминал в начале этого урока, в этот проект можно добавить еще много функций. Если вы хотите, чтобы я продолжил эту серию, проголосуйте за функцию, которую вы хотели бы видеть ниже. В противном случае вы можете проголосовать за то, чтобы я перешел к совершенно другой теме iOS SDK (не стесняйтесь предлагать ее в разделе комментариев). Опрос закроется в субботу утром, 10 сентября.