Руководство о том как создать простое приложение на iOS для iPhone: часть 2/3
Логотип www.it-type.ru
24 ноября 2012 в 20:46

Руководство о том как создать простое приложение на iOS для iPhone: часть 2/3

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

В первой части этой серии мы создали приложение которое содержало список жуков в таблице.

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

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

Ну что давайте создадим несколько жуков.

Ох контроллер представления!

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

Большую часть времени в приложении для iPhone, для каждого экрана активного в данный момент есть свой класс “ViewController”. Сейчас наш “MsterViewController ” который появляется при старте приложения содержит таблицу. Мы хотим сделать так, что бы при нажатие на жука, появлялся DetailViewController с некоторой информацией о жуке.

Когда мы впервые запустили шаблон, на самом деле он работал, но когда мы нажимали изменить объекты отображаемые в таблице (наши жуки, а не обьекты Xcode шаблона NSDate), нажатие на строку не посылало правильный объект в детальное представление. Мы скоро это исправим.

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

Скачаем необходимые инструменты.

Кстате говоря мы будем использовать пятизвездочный рейтинг в детальном виде, но в iPhone его нет по умолчанию. Однако я недавно написал руководство на тему Как создать свой UIView в iOS5 : Представление пятизвездочного рейтинга, мы будем использовать это представление в нашей статье снова.

Не волнуйтесь, сейчас мы не будем проходить через все руководство (конечно если вам это не хочется самим) - мы просто загрузим пакет: Инструменты для страшных жуков, собранный для этого проекта.

Если загрузили пакет то:

Планировка нашего детального контроллера представления с помощью Storyboard editor.

Хоршо, теперь у нас все готово что бы начать. Откройте MainStoryboard.storyboard и если вы прокрутите экран в право вы увидите детальный контроллер представления сделанный из шаблона по умолчанию внутри с ярлыком “Detail view content goes here”:

Редактор StoryBoard обеспечивает визуальное создание пользовательского интерфейса в Xcode. Вы можете перемещать UI элементы на представление, устанавливать их свойства, вы даже можете соединять элементы со свойствами в вашем классе контроллера представления.

Самый простой способ понять – это попробовать! Первое, нажмите на котроллере представления и перейдите в Editor\Canvas\Show Bounds Rectangles – это упростит компоновку.

Удалите ярлык “Detail view content goes here” он нам не нужен.

Затем в правой панели, в нижней части, убедитесь, что выбрана третья вкладка Object Library. Переместите UITextField, UIImageView и UIView расположите их в следующем порядке текстовое поле сверху):

Затем выберете UITextField и четвертую вкладку в верхней боковой панели (Attributes inspector), так мы можем изменит некоторые свойства.

Установите шрифт Custom\Helvetica\Bold\Size 18.0, расположение текста в центре, выберем Appears While Editing для Clear Button, а для Capitalization выберем Words. Должно получится как на картинке:

Переключитесь на Size Inspector нажав пятую вкладку и установите Autosizing attributes следующим образом:

Это позволит, текстовому полю находясь в горизонтальном положении растягиваться по всему экрану.

Теперь выберем наш UIImageView. В четвертой вкладке (Attributes Inspector) установите mode в “Aspect Fit” и в четвертой вкладке (Attributes Inspector), и в пятой (Size Inspector) установите Autosizing attributes как на рисунке:

Это позволяет Image View растягиваться или сокращаться заполняя все свободное пространство, сохраняя его края на одинаковом расстоянии от экрана и масштабировать изображение для лучшего отображения на экране сохраняя при этом соотношение сторон.

Для UIView, перейдем на тертью вкладку (Identity Inspector) и установим параметру Class Identity значение RateVIew, исходя из этого наш пятизвездный рейтинг будет отображатся здесь. Затем в пятой вкладеке (Size Inspector) установите Autosizing attributes как на рисунке:

Это позволит растягиваться ему в право и в лево, но всегда оставаться той же высоты.

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

Есть два пути как это сделать, и один из них легкий. Он состоит в том, что бы создать невидимую кнопку над UIImageView и получить вызов при нажатии кнопки. Так же мы можем добавить UILabel, под изображением, с текстом «Нажмите что бы изменить изображение» если изображение не установлено.

Переместим Round Rect Button из библиотеки и изменим её размер до размеров UIImageView. Для создания невидимости, в четвертой вкладке (Attributes Inspector) установите Type значение Custom. Затем в пятой вкладеке (Size Inspector) установите Autosizing attributes как на рисунке:

И в конце, переместите UILabel из библиотеки, расположите его по середине UIImageView, и двойным нажатием правой кнопки мышки отредактируйте текст следующим образом «Нажмите что бы изменить изображение». Затем установите расположение текста в центре. Еще переместите UILabel в XIB на несколько позиций выше, что он находился за UIImageVIew (список идет снизу вверх):

На пятой вкладеке (Size Inspector) установите Autosizing attributes как на рисунке:

Перед тем как мы двинемся дальше, вы можете проверить установленные Autosizing attributes, выберите Detail View Controller и перейдите в четвертую вкладку (Attributes Inspector) измените ориентацию с вертикальной в горизонтальную:

Если у вас что нибудь пошло не так - не беспокойтесь, измените представление на портрет и проверьте настройки еще раз.

Фуф! Мы добавили все элементы управления, теперь нам нужно добавить ловушки для всех источников в нашем классе.

Для этого, сначала вызовите Assistant Editor (вторая кнопка в пункте меню “Editor”) и убедитесь что установлен Automatic\DetailViewController.h:

Управляя переместите из UITextField в низ на DetailViewController.h перед @end. Появившееся всплывающее окно позволяет подключить свойства UITextField в ваш класс. Connection выберете Outlet и установите имя titleField и нажмите Connect.

Повторите тоже самое для Image View (имя задайте imageView) и Rate View (имя rateView).

Нам также нужно сделать, что бы при нажатии нашей кнопки вызывался метод в нашем классе. Для этого управляя переместите из Button перед @end, как вы делали при подключении других представлений. Однако Connection установите в Action, а имя addPictureTapped и нажмите Connect.

Заметьте, что по умолчанию Event установлен как Touch Up Inside. Этот способ как раз подходит нам потому что это событие происходит когда пользователь отпускает кнопку (то есть нажимает её) и наш метод вызывается.

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

Для этого управляя переместите из UITextField перед @end и также вустановить Connection в Action. По умолчанию Event установлен как Editing Did End, установите его как Editing Changed. Задайте Name метода titleFieldTextChanged и нажмите Connect.

Последнее, что мы должны сделать, это установить наш класс в качестве делегата Text Field. Иногда получение обратного вызова действия от представления недостаточно - могут иметься другие источники вызовов и Text Field яркий тому пример.

Нажмите правой кнопкой мышки на Text Field и перместите удерживая кнопку плюсик напротив delegate на Detail View Controller и отпустите.

На данный момент DetailViewController.h должен выглядеть так:

#import <UIKit/UIKit.h>
 
@interface DetailViewController : UIViewController
 
@property (strong, nonatomic) id detailItem;
 
@property (strong, nonatomic) IBOutlet UILabel *detailDescriptionLabel;
@property (weak, nonatomic) IBOutlet UITextField *titleField;
@property (weak, nonatomic) IBOutlet RateView *rateView;
@property (weak, nonatomic) IBOutlet UIImageView *imageView;
- (IBAction)addPictureTapped:(id)sender;
- (IBAction)titleFieldTextChanged:(id)sender;
 
@end

Вы могли заметить что выше присутствуют необычные типы: IBOutlet и IBAction. Эти «волшебные слова» Storyboard Editor ищет для того что бы связать элементы управления которые мы добавили в Interface Builder со свойствами нашего класса. То есть, если разместить IBOutlet или IBAction и после них свойство/метод, Interface Builder обнаружит это, и мы сможем перехватить событие.

Создавая это с помощью Storyboard editor он делает подключение элементов управления к свойствам автоматически за нас, вы можете это увидеть нажав правой кнопкой мыши на Detail View Controller. Эти точки кстати и называются “outlets”.

Нам нужно сделать несколько маленьких корректировок, что бы отметить в нашем контролере представления реализацию нескольких делегатов, добавить свойство для Image picker и изменить наш detailItem что указать ему на ScaryBugDoc, потому что detailItem будет показан на дисплее. Изменения выглядят так:

#import <UIKit/UIKit.h>
#import "RateView.h"
 
@class ScaryBugDoc;
 
@interface DetailViewController : UIViewController <UITextFieldDelegate, RateViewDelegate, UIImagePickerControllerDelegate, UINavigationControllerDelegate>
 
@property (strong, nonatomic) ScaryBugDoc * detailItem;
@property (strong, nonatomic) IBOutlet UILabel *detailDescriptionLabel;
@property (weak, nonatomic) IBOutlet UITextField *titleField;
@property (weak, nonatomic) IBOutlet RateView *rateView;
@property (weak, nonatomic) IBOutlet UIImageView *imageView;
@property (strong, nonatomic) UIImagePickerController * picker;
 
- (IBAction)addPictureTapped:(id)sender;
- (IBAction)titleFieldTextChanged:(id)sender;
 
@end	

Ух, наконец то закончили с настройкой расположения и заголовочных файлов – перейдем к реализации.

Реализация нашего Detail View

Сейчас мы сделаем кучу изменений в DetailViewController.m. Будет очень много кода, поэтому давайте разделим её на части.

1) Импортируем заголовки

// Начало файла
#import "ScaryBugDoc.h"
#import "ScaryBugData.h"
#import "UIImageExtras.h"
 
// Добавьте в секцию synthesize
@synthesize picker = _picker;

Вы уже должны быть профессионалом в этом деле!

2) Настройка Rate View

// Замените configureView
- (void)configureView
{
    // Обновите интерфейс пользователя detail item.
    self.rateView.notSelectedImage = [UIImage imageNamed:@"shockedface2_empty.png"];
    self.rateView.halfSelectedImage = [UIImage imageNamed:@"shockedface2_half.png"];
    self.rateView.fullSelectedImage = [UIImage imageNamed:@"shockedface2_full.png"];
    self.rateView.editable = YES;
    self.rateView.maxRating = 5;
    self.rateView.delegate = self; 
}

В configureView (который вызывается из viewDidLoad), мы установили свойства нашего RateView. Для уточнения деталей можно посмотреть руководство Как создать свой UIView в iOS5 : Представление пятизвездочного рейтинга.

3) Включение автоориентации

// Замените возврощаемое значение в shouldAutorotateToInterfaceOrientation на:

return YES;

В shouldAutorotateToInterfaceOrientation, мы возвращаем YES так как мы установили все настройки для авто-масштабирования в Interface Builder! Это позволяет пользователям переключатся между ориентациями экрана и наше управление будет повторять ту схему автокалибровки которую мы настроили.

4) Настройка начального вида пользовательского интерфейса.

//Добавьте в конец configureView
if (self.detailItem) {
    self.titleField.text = self.detailItem.data.title;
    self.rateView.rating = self.detailItem.data.rating;    
    self.imageView.image = self.detailItem.fullImage;
}

Здесь мы просто устанавливаем основной GUI жука который был выбран.

5) Управляем Text View и Rating View

- (IBAction)titleFieldTextChanged:(id)sender {
    self.detailItem.data.title = self.titleField.text;
}
 
#pragma mark UITextFieldDelegate
 
- (BOOL)textFieldShouldReturn:(UITextField *)textField {
    [textField resignFirstResponder];
    return YES;
}
 
#pragma mark RateViewDelegate
 
- (void)rateView:(RateView *)rateView ratingDidChange:(float)rating {
    self.detailItem.data.rating = rating;
}

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

textFieldShouldReturn вызывается, когда пользователь нажимает клавишу ввода на клавиатуре. Мы вызываем resignFirstResponder когда необходимо убрать клавиатуру с экрана.

rateView:ratingIsChanged вызывается когда пользователь меняет рейтинг так как мы установили делегат RateView, таким образом когда это происходит мы обновляем модель.

В случаем если вам интересно, #pragma mark является специальной строкой которую Xcode может прочитать установив разделители в списке функций редактора для организации:

6) Показываем палитру изображений и обработку результата:

- (IBAction)addPictureTapped:(id)sender {
    if (self.picker == nil) {   
        self.picker = [[UIImagePickerController alloc] init];
        self.picker.delegate = self;
        self.picker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
        self.picker.allowsEditing = NO;    
    } 
    [self.navigationController presentModalViewController:_picker animated:YES];    
}
 
#pragma mark UIImagePickerControllerDelegate
 
- (void)imagePickerControllerDidCancel:(UIImagePickerController *)picker {
    [self dismissModalViewControllerAnimated:YES];
}
 
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info {    
 
    [self dismissModalViewControllerAnimated:YES];
 
    UIImage *fullImage = (UIImage *) [info objectForKey:UIImagePickerControllerOriginalImage]; 
    UIImage *thumbImage = [fullImage imageByScalingAndCroppingForSize:CGSizeMake(44, 44)];
    self.detailItem.fullImage = fullImage;
    self.detailItem.thumbImage = thumbImage;
    self.imageView.image = fullImage;
}

Мы устанавливаем addPictureTapped вызывается каждый раз когда пользователь нажимает невидимую кнопку поверх UIImage, здесь мы создаем UIImagePicker(если он еще не существует) и устанавливаем источник фотографии из библиотеки(еще можно установить другие источники такие как мера). Мы установили наш делегат таким образом мы можем получать вызов когда пользователь заканчивает выбор изображения. Наконец, мы показываем изображение в модальном контролере представления, на весть экран.

Наконец, мы реализуем функцию обратного вызова для выбора изображения, когда пользователь выбирает изображение или отменяет выбор. Тем же способом мы убираем модальный контролер представления. Если пользователь сделал выбор изображения, мы получаем полное изображение, а также его превью (мы изменяем размер с помощью класса UIImageExtras который мы добавили ранее) и обновляем оба в модели и представлении.

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

Интеграция нашего Detail View

Это пройдет достаточно быстро. Сначала откройте MainStoryboard.storyboard и выберете ячейку таблицы в Master View Controller. Управляя переместите из ячейки в Detail View Controller, появится всплывающее окно с возможностью выбрать как вы хотите подключить его - Push, Modal или Custom. Выберете Push и вы должны увидеть стрелку подключения контролера представления.

Сейчас нужно сделать, что бы при выборе строки и переходе в Detail View Controller мы видели жука который был выбран. Что бы сделать это, откройте MasterViewController.m и сделайте следующие изменения:

//Добавьте в начало файла
#import "DetailViewController.h"

//Добавьте в конец viewWillAppear
[self.tableView reloadData];

//А это в конце файла
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
    DetailViewController *detailController =segue.destinationViewController;
    ScaryBugDoc *bug = [self.bugs objectAtIndex:self.tableView.indexPathForSelectedRow.row];
    detailController.detailItem = bug;
}

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

Потом, помните мы настраивали в Storyboard editor действие когда строка была нажата, которая всегда будет получать данные в Detail View Controller. Когда это происходит вызов prepareForSegue, который дает шанс вставить необходимую нам информацию в Ditale View Controller. В нашем случае мы просто передаем жука на экран.

Наконец то мы закончили! ТАк давайте же скомпилируем и запустим проект и если все прошло хорошо мы сможем перейти в ячейку с жуком, измените его имя, изображение, установите рейтинг и проверьте в различных ориентациях экрана!

Что делать дальше?

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


Оригинал статьи взят отсюда How To Create A Simple iPhone App on iOS 5 Tutorial: Part 1/3



Отправить идею!

Отправить