Статьи

Создайте простую фотогалерею с UIGestureRecognizer

Класс UIGestureRecognizer позволяет легко обнаруживать и реагировать на сложные жесты в приложении iOS SDK. Из этого туториала вы узнаете, как использовать класс UIGestureRecognizer, демонстрируя, как создать простую библиотеку фотогалереи.

UIGestureRecognizer был доступен с iOS 3.2. Однако вы можете быть удивлены, обнаружив, что редко будете работать с этим классом напрямую. Вместо этого вы реализуете один из нескольких подклассов, предназначенных для реагирования на конкретные сенсорные жесты. Следующие подклассы UIGestureRecognizer поставляются с iOS SDK:

  • UITapGestureRecognizer : ищет один или несколько нажатий. Этот жест будет распознан, если указанное количество пальцев коснется просмотра установленное число раз в течение предварительно определенного периода времени.
  • UIPinchGestureRecognizer : ищет зажимающие жесты. Когда пользователь перемещает два пальца друг к другу, запускается действие «уменьшение», а если пользователь отодвигает два пальца друг от друга, действие «увеличение» запускается.
  • UIRotationGestureRecognizer : ищет жесты вращения. Если пользователи перемещают свои пальцы круговыми движениями, нижележащий вид должен вращаться в том же направлении и скорости.
  • UISwipeGestureRecognizer : ищет жесты в одном или нескольких направлениях. Проведение является дискретным жестом, поэтому связанный метод будет вызываться только один раз за одно касание.
  • UIPanGestureRecognizer : ищет перетаскивающие жесты. Пользователи должны нажимать один или несколько пальцев на вид, пока они его перетаскивают.
  • UILongPressGestureRecognizer : ищет жесты при длинном нажатии. Пользователи должны нажать один или несколько пальцев на виде в течение более длительного периода времени, прежде чем будет вызван метод. Если ваши пальцы переместятся на указанное расстояние, удерживая нажатой, жест не удастся.

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

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


Откройте Xcode и выберите «Создать новый проект Xcode». Выберите приложение Master-Detail и нажмите Next. Введите название для вашего проекта, я назвал мой «Фотогалерея». Введите идентификатор вашей компании и убедитесь, что вы выбрали iPhone для Device Family, потому что мы собираемся сделать приложение для iPhone. Также убедитесь, что установлены все флажки, кроме флажка Use Core Data. Как видите, в этом руководстве мы будем использовать новые функции раскадровки iOS 5 и автоматического подсчета ссылок (ARC). Если вы сделали, нажмите кнопку Далее. Выберите место для сохранения вашего проекта и нажмите «Создать».

Создать проект

Поскольку в этом руководстве мы используем раскадровки вместо файлов перьев, вы не увидите MainWindow.xib, а файл с именем MainStoryboard.storyboard. Когда вы откроете этот файл, вы увидите весь пользовательский интерфейс, который содержит контроллер навигации и два контроллера представления.

Создать проект

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

Также взгляните на файл MasterViewController.m. Вы увидите, что не существует метода dealloc . Это потому, что мы используем ARC, а ARC для нас обрабатывает связанные с памятью методы, такие как retain , release , autorelease и dealloc .

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


Откройте MasterViewController.h и измените код следующим образом:

01
02
03
04
05
06
07
08
09
10
11
12
#import <UIKit/UIKit.h>
 
#import «DetailViewController.h»
 
@interface MasterViewController : UITableViewController
{
    NSArray *list;
}
 
@property (strong, nonatomic) NSArray *list;
 
@end

Здесь мы импортируем класс DetailViewController и создаем массив с именем list.

Теперь перейдите к MasterViewController.m и добавьте следующие строки под @implementation:

1
@synthesize list;

Теперь прокрутите вниз до метода viewDidLoad и измените код следующим образом:

1
2
3
4
5
6
7
8
9
— (void)viewDidLoad
{
    [super viewDidLoad];
     
    self.title = @»Products»;
     
    NSArray *listArray = [[NSArray alloc] initWithObjects:@»iPhone», @»iPad», @»iMac», @»MacBook Air», nil];
    self.list = listArray;
}

Здесь мы устанавливаем заголовок панели навигации на «продукты» и создаем фиктивный массив с продуктами Apple, чтобы заполнить наш массив списков. Нам не нужно выпускать listArray, потому что ARC сделает это за нас.

Теперь перейдите к shouldAutorotateToInterfaceOrientation: и измените код следующим образом: наше приложение будет работать только в портретном режиме:

1
2
3
4
— (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
    return (interfaceOrientation == UIInterfaceOrientationPortrait);
}

Теперь добавьте следующие методы источника данных табличного представления в shouldAutorotateToInterfaceOrientation: метод:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
— (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
    return 1;
}
 
— (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    return [list count];;
}
 
— (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *CellIdentifier = @»Cell»;
     
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
     
    cell.textLabel.text = [list objectAtIndex:[indexPath row]];
     
    return cell;
}

Здесь мы устанавливаем количество разделов табличного представления равным 1, а количество строк этого раздела равным количеству объектов в нашем массиве списков. Мы устанавливаем текст ячеек в табличном представлении для продуктов в нашем массиве списков.

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

1
2
3
4
— (void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
    [segue.destinationViewController setProductName:[list objectAtIndex:[self.tableView.indexPathForSelectedRow row]]];
}

Здесь мы передаем строку названия нашего продукта в контроллер подробного представления. Мы будем использовать эту строку для заголовка панели навигации и для установки изображения. Вы получите ошибку, потому что мы еще не определили строку productName в DetailViewController. Раскадровка вызывает этот метод во время выполнения, когда вы запускаете переход в текущей сцене.

Последнее, что нам нужно сделать, это обновить наше представление таблицы в раскадровке, поэтому откройте «MainStoryboard.storyboard» и выберите представление таблицы. Откройте инспектор атрибутов и измените содержимое со статических ячеек на динамические прототипы.

содержание

Теперь выберите ячейку табличного представления и установите идентификатор в ячейку. Также установите индикатор принадлежности к раскрытию.

Идентификатор

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


Откройте MainStoryboard.storyboard, выберите метку в последнем контроллере представления и удалите ее. Теперь перетащите UIImageView в представление и заставьте его заполнить все пространство. В Инспекторе Атрибутов установите Режим представления изображения на Аспект.

Теперь нам нужно только подключить вид изображения, поэтому выберите среднюю кнопку редактора, чтобы отобразить «Помощник редактора».

Помощник редактора

Выберите представление изображения и перетащите элемент управления в оператор DetailViewController @interface. Появится всплывающее окно. Введите «productImageView» в поле имени, установите тип хранилища «сильный» и нажмите «Подключиться».

Connect

Откройте DetailViewController.h и измените код следующим образом:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
#import <UIKit/UIKit.h>
 
@interface DetailViewController : UIViewController
{
    NSString *productName;
     
    CGFloat previousScale;
    CGFloat previousRotation;
     
    CGFloat beginX;
    CGFloat beginY;
}
 
@property (strong, nonatomic) IBOutlet UIImageView *productImageView;
@property (strong, nonatomic) NSString *productName;
 
@end

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

Теперь перейдите в файл DetailViewController.m и удалите следующие строки:

1
2
@synthesize detailItem = _detailItem;
@synthesize detailDescriptionLabel = _detailDescriptionLabel;

Также удалите эти строки и setDetailItem: и configureView :

1
2
3
@interface DetailViewController ()
— (void)configureView;
@end

Теперь добавьте следующую строку под @implementation:

1
@synthesize productName;

Перейдите к shouldAutorotateToInterfaceOrientation: и измените код так, чтобы он читался следующим образом, поэтому наше приложение в этом представлении также будет работать только в портретном режиме:

1
2
3
4
— (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
    return (interfaceOrientation == UIInterfaceOrientationPortrait);
}

Сначала нам нужно добавить изображения в наш проект, поэтому загрузите образец кода, прикрепленный к этому проекту, и перетащите изображения iMac, iPad, iPhone и MacBook Air в свой проект. Убедитесь, что установлен флажок «Копировать элементы в папку целевой группы (если необходимо)», а затем нажмите «Готово».

Добавить изображения продукта

Теперь прокрутите вниз до метода viewDidLoad в файле DetailViewController.m и измените код следующим образом:

1
2
3
4
5
6
7
8
9
— (void)viewDidLoad
{
    [super viewDidLoad];
 
    self.title = productName;
     
    NSString *imageName = [NSString stringWithFormat:@»%@.jpg», productName];
    self.productImageView.image = [UIImage imageNamed:imageName];
}

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

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

Приложение

Перейдите к методу viewDidLoad в DetailViewController.m и добавьте следующий код в этот метод:

1
2
UIRotationGestureRecognizer *rotationGesture = [[UIRotationGestureRecognizer alloc] initWithTarget:self action:@selector(rotateImage:)];
   [self.view addGestureRecognizer:rotationGesture];

Здесь мы создали распознаватель жестов вращения. Теперь добавьте метод rotateImage: :

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
— (void)rotateImage:(UIRotationGestureRecognizer *)recognizer
{
     
    if([recognizer state] == UIGestureRecognizerStateEnded) {
         
        previousRotation = 0.0;
        return;
    }
     
    CGFloat newRotation = 0.0 — (previousRotation — [recognizer rotation]);
     
    CGAffineTransform currentTransformation = self.productImageView.transform;
    CGAffineTransform newTransform = CGAffineTransformRotate(currentTransformation, newRotation);
     
    self.productImageView.transform = newTransform;
     
    previousRotation = [recognizer rotation];
}

В этом методе мы сначала проверяем, закончились ли жесты вращения. Если это так, мы устанавливаем значение previousRotation в 0. Затем мы вычисляем новое вращение с предыдущим вращением, а затем устанавливаем текущее вращение. Это сделано, чтобы наше следующее вращение началось с текущего вращения. Мы хотим применить это вращение к текущему преобразованию. Итак, мы получаем наше текущее преобразование и добавляем к нему вращение. Наконец, мы устанавливаем предыдущее вращение для текущего вращения ваших пальцев.


Перейдите к методу viewDidLoad и добавьте в него следующий код:

1
2
UIPinchGestureRecognizer *pinchGesture = [[UIPinchGestureRecognizer alloc] initWithTarget:self action:@selector(scaleImage:)];
 [self.view addGestureRecognizer:pinchGesture];

Здесь мы создаем распознаватель жестов пинч. Теперь добавьте scaleImage: метод:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
— (void)scaleImage:(UIPinchGestureRecognizer *)recognizer
{
     
    if([recognizer state] == UIGestureRecognizerStateEnded) {
         
        previousScale = 1.0;
        return;
    }
     
    CGFloat newScale = 1.0 — (previousScale — [recognizer scale]);
     
    CGAffineTransform currentTransformation = self.productImageView.transform;
    CGAffineTransform newTransform = CGAffineTransformScale(currentTransformation, newScale, newScale);
     
        self.productImageView.transform = newTransform;
     
    previousScale = [recognizer scale];
}

Этот метод очень похож на метод rotateImage, но вместо поворота изображения мы масштабируем изображение.


Перейдите к методу viewDidLoad и добавьте в него следующий код:

1
2
UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(resetImage:)];
[self.view addGestureRecognizer:tapGesture];

Здесь мы создали распознаватель жестов касания. Теперь добавьте scaleImage: метод:

01
02
03
04
05
06
07
08
09
10
11
— (void)resetImage:(UITapGestureRecognizer *)recognizer
{
    [UIView beginAnimations:nil context:nil];
    [UIView setAnimationDuration:0.3];
     
    self.productImageView.transform = CGAffineTransformIdentity;
     
    [self.productImageView setCenter:CGPointMake(self.view.frame.size.width/2, self.view.frame.size.height/2)];
     
    [UIView commitAnimations];
}

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


В последний раз перейдите к методу viewDidLoad и добавьте в него следующий код:

1
2
3
4
UIPanGestureRecognizer *panGesture = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(moveImage:)];
[panGesture setMinimumNumberOfTouches:1];
[panGesture setMaximumNumberOfTouches:1];
[self.view addGestureRecognizer:panGesture];

Здесь мы создали распознаватель жестов панорамирования. Мы установили для свойстваimumNumberOfTouches и MaximumNumberOfTouches значение 1, поэтому этот жест будет работать только одним пальцем. Теперь добавьте moveImage: метод:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
— (void)moveImage:(UIPanGestureRecognizer *)recognizer
{
    CGPoint newCenter = [recognizer translationInView:self.view];
     
    if([recognizer state] == UIGestureRecognizerStateBegan) {
         
        beginX = self.productImageView.center.x;
        beginY = self.productImageView.center.y;
    }
     
    newCenter = CGPointMake(beginX + newCenter.x, beginY + newCenter.y);
     
    [self.productImageView setCenter:newCenter];
     
}

Здесь мы создаем CGPoint и устанавливаем значение для местоположения вашего пальца. Если мы начнем с жеста панорамирования. Мы устанавливаем значение переменных beginX и beginY равными координатам x и y центра изображения. После этого мы вычисляем новые координаты центра вида изображения, поэтому центр вида изображения будет в том же месте, что и наш палец. Наконец, мы устанавливаем центр изображения для нового центра CGPoint, который мы только что рассчитали.

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


Надеюсь, вам понравился этот урок о жестах. Если у вас есть новые идеи для iOS, пожалуйста, оставьте их в разделе комментариев ниже!