Использование UIPinchGestureRecognizer для масштабирования uiviews в одном направлении

Я хотел бы знать, как мы можем использовать UIPinchGestureRecognizer для масштабирования UIView в одиночных (x или y) направлениях. Скажем, если пользователь перемещает два пальца жестким жестом только в одном направлении (в горизонтальном направлении), только ширина uiview должна увеличиваться / уменьшаться, и если пальцы перемещаются только по вертикали, высота должна изменяться. Если пальцы движутся по диагонали, то высота и ширина uiview должны увеличиваться / уменьшаться. Я видел пример кода MoveMe от Apple.

 UIPinchGestureRecognizer *pinchGesture = [[UIPinchGestureRecognizer alloc] initWithTarget:self action:@selector(scalePiece:)]; [pinchGesture setDelegate:self]; [piece addGestureRecognizer:pinchGesture]; [pinchGesture release]; 

Масштаб:

 - (void)scalePiece:(UIPinchGestureRecognizer *)gestureRecognizer { UIView *piece = (UIView *) [gestureRecognizer view]; NSLog(@"scalePiece enter"); if ([gestureRecognizer state] == UIGestureRecognizerStateBegan){ NSLog(@"inside if"); lastTouchPosition = [gestureRecognizer locationInView:piece]; } else if ([gestureRecognizer state] == UIGestureRecognizerStateBegan || [gestureRecognizer state] == UIGestureRecognizerStateChanged){ NSLog(@"inside else"); CGPoint currentTouchLocation = [gestureRecognizer locationInView:piece]; NSLog(@"currentTouchLocation = %@ and lastTouchPosition= %@",NSStringFromCGPoint(currentTouchLocation), NSStringFromCGPoint(lastTouchPosition)); CGPoint deltaMove = [self calculatePointDistancewithPoint1:currentTouchLocation andPoint2:lastTouchPosition]; NSLog(@"deltaMove = %@",NSStringFromCGPoint(deltaMove)); float distance = sqrt(deltaMove.x*deltaMove.x + deltaMove.y*deltaMove.y); NSLog(@"distance = %f",distance); float hScale = 1 - deltaMove.x/distance * (1-gestureRecognizer.scale); float vScale = 1 - deltaMove.y/distance * (1-gestureRecognizer.scale); if (distance == 0) { hScale = 1; vScale = 1; } NSLog(@"[gestureRecognizer scale] = %f",[gestureRecognizer scale]); NSLog(@"hScale = %f and vScale = %f",hScale, vScale); piece.transform = CGAffineTransformScale([piece transform], hScale, vScale); [gestureRecognizer setScale:1]; lastTouchPosition = currentTouchLocation; } NSLog(@"scalePiece exit"); } 

Вычислить расстояние:

 - (CGPoint) calculatePointDistancewithPoint1:(CGPoint)point1 andPoint2:(CGPoint) point2 { return CGPointMake(point2.x - point1.x, point2.y - point1.y); } 

Это выход журнала, когда я пытаюсь ущипнуть (увеличить) вид, только перемещая пальцы в вертикальном направлении. Высота элемента не увеличивается.

 2011-07-21 13:06:56.245 New[8169:707] scalePiece enter 2011-07-21 13:06:56.248 New[8169:707] inside if 2011-07-21 13:06:56.251 New[8169:707] scalePiece exit 2011-07-21 13:06:56.259 New[8169:707] scalePiece enter 2011-07-21 13:06:56.262 New[8169:707] inside else 2011-07-21 13:06:56.264 New[8169:707] currentTouchLocation = {88, 87} and lastTouchPosition= {87, 86} 2011-07-21 13:06:56.265 New[8169:707] deltaMove = {-1, -1} 2011-07-21 13:06:56.267 New[8169:707] distance = 1.414214 2011-07-21 13:06:56.268 New[8169:707] [gestureRecognizer scale] = 1.102590 2011-07-21 13:06:56.271 New[8169:707] hScale = 0.927458 and vScale = 0.927458 2011-07-21 13:06:56.272 New[8169:707] scalePiece exit 2011-07-21 13:06:56.281 New[8169:707] scalePiece enter 2011-07-21 13:06:56.283 New[8169:707] inside else 2011-07-21 13:06:56.284 New[8169:707] currentTouchLocation = {87, 89} and lastTouchPosition= {88, 87} 2011-07-21 13:06:56.286 New[8169:707] deltaMove = {1, -2} 2011-07-21 13:06:56.287 New[8169:707] distance = 2.236068 2011-07-21 13:06:56.296 New[8169:707] [gestureRecognizer scale] = 1.096172 2011-07-21 13:06:56.298 New[8169:707] hScale = 1.043009 and vScale = 0.913981 2011-07-21 13:06:56.299 New[8169:707] scalePiece exit 2011-07-21 13:06:56.302 New[8169:707] scalePiece enter 2011-07-21 13:06:56.303 New[8169:707] inside else 2011-07-21 13:06:56.305 New[8169:707] currentTouchLocation = {88, 89} and lastTouchPosition= {87, 89} 2011-07-21 13:06:56.309 New[8169:707] deltaMove = {-1, 0} 2011-07-21 13:06:56.311 New[8169:707] distance = 1.000000 2011-07-21 13:06:56.313 New[8169:707] [gestureRecognizer scale] = 1.066320 2011-07-21 13:06:56.314 New[8169:707] hScale = 0.933680 and vScale = 1.000000 2011-07-21 13:06:56.316 New[8169:707] scalePiece exit 2011-07-21 13:06:56.318 New[8169:707] scalePiece enter 2011-07-21 13:06:56.320 New[8169:707] inside else 2011-07-21 13:06:56.329 New[8169:707] currentTouchLocation = {88, 90} and lastTouchPosition= {88, 89} 2011-07-21 13:06:56.331 New[8169:707] deltaMove = {0, -1} 2011-07-21 13:06:56.333 New[8169:707] distance = 1.000000 2011-07-21 13:06:56.334 New[8169:707] [gestureRecognizer scale] = 1.061696 2011-07-21 13:06:56.335 New[8169:707] hScale = 1.000000 and vScale = 0.938304 2011-07-21 13:06:56.338 New[8169:707] scalePiece exit 2011-07-21 13:06:56.343 New[8169:707] scalePiece enter 2011-07-21 13:06:56.346 New[8169:707] inside else 2011-07-21 13:06:56.347 New[8169:707] currentTouchLocation = {88, 92} and lastTouchPosition= {88, 90} 2011-07-21 13:06:56.349 New[8169:707] deltaMove = {0, -2} 2011-07-21 13:06:56.350 New[8169:707] distance = 2.000000 2011-07-21 13:06:56.351 New[8169:707] [gestureRecognizer scale] = 1.096869 2011-07-21 13:06:56.353 New[8169:707] hScale = 1.000000 and vScale = 0.903131 2011-07-21 13:06:56.362 New[8169:707] scalePiece exit 2011-07-21 13:06:56.366 New[8169:707] scalePiece enter 2011-07-21 13:06:56.370 New[8169:707] inside else 2011-07-21 13:06:56.373 New[8169:707] currentTouchLocation = {88, 92} and lastTouchPosition= {88, 92} 2011-07-21 13:06:56.376 New[8169:707] deltaMove = {0, 0} 2011-07-21 13:06:56.380 New[8169:707] distance = 0.000000 2011-07-21 13:06:56.383 New[8169:707] [gestureRecognizer scale] = 1.035330 2011-07-21 13:06:56.387 New[8169:707] hScale = 1.000000 and vScale = 1.000000 2011-07-21 13:06:56.389 New[8169:707] scalePiece exit 2011-07-21 13:06:56.393 New[8169:707] scalePiece enter 2011-07-21 13:06:56.397 New[8169:707] inside else 2011-07-21 13:06:56.399 New[8169:707] currentTouchLocation = {88, 93} and lastTouchPosition= {88, 92} 2011-07-21 13:06:56.403 New[8169:707] deltaMove = {0, -1} 2011-07-21 13:06:56.406 New[8169:707] distance = 1.000000 2011-07-21 13:06:56.409 New[8169:707] [gestureRecognizer scale] = 1.042659 2011-07-21 13:06:56.412 New[8169:707] hScale = 1.000000 and vScale = 0.957341 2011-07-21 13:06:56.414 New[8169:707] scalePiece exit 2011-07-21 13:06:56.419 New[8169:707] scalePiece enter 2011-07-21 13:06:56.422 New[8169:707] inside else 2011-07-21 13:06:56.425 New[8169:707] currentTouchLocation = {88, 92} and lastTouchPosition= {88, 93} 2011-07-21 13:06:56.427 New[8169:707] deltaMove = {0, 1} 2011-07-21 13:06:56.430 New[8169:707] distance = 1.000000 2011-07-21 13:06:56.432 New[8169:707] [gestureRecognizer scale] = 1.024549 2011-07-21 13:06:56.436 New[8169:707] hScale = 1.000000 and vScale = 1.024549 2011-07-21 13:06:56.439 New[8169:707] scalePiece exit 2011-07-21 13:06:56.442 New[8169:707] scalePiece enter 2011-07-21 13:06:56.447 New[8169:707] inside else 2011-07-21 13:06:56.450 New[8169:707] currentTouchLocation = {88, 92} and lastTouchPosition= {88, 92} 2011-07-21 13:06:56.453 New[8169:707] deltaMove = {0, 0} 2011-07-21 13:06:56.455 New[8169:707] distance = 0.000000 2011-07-21 13:06:56.458 New[8169:707] [gestureRecognizer scale] = 1.007702 2011-07-21 13:06:56.460 New[8169:707] hScale = 1.000000 and vScale = 1.000000 2011-07-21 13:06:56.464 New[8169:707] scalePiece exit 2011-07-21 13:06:56.501 New[8169:707] scalePiece enter 2011-07-21 13:06:56.504 New[8169:707] inside else 2011-07-21 13:06:56.507 New[8169:707] currentTouchLocation = {89, 92} and lastTouchPosition= {88, 92} 2011-07-21 13:06:56.509 New[8169:707] deltaMove = {-1, 0} 2011-07-21 13:06:56.510 New[8169:707] distance = 1.000000 2011-07-21 13:06:56.511 New[8169:707] [gestureRecognizer scale] = 1.000283 2011-07-21 13:06:56.513 New[8169:707] hScale = 0.999717 and vScale = 1.000000 2011-07-21 13:06:56.517 New[8169:707] scalePiece exit 2011-07-21 13:06:56.566 New[8169:707] scalePiece enter 2011-07-21 13:06:56.570 New[8169:707] inside else 2011-07-21 13:06:56.572 New[8169:707] currentTouchLocation = {89, 91} and lastTouchPosition= {89, 92} 2011-07-21 13:06:56.573 New[8169:707] deltaMove = {0, 1} 2011-07-21 13:06:56.575 New[8169:707] distance = 1.000000 2011-07-21 13:06:56.576 New[8169:707] [gestureRecognizer scale] = 1.008267 2011-07-21 13:06:56.579 New[8169:707] hScale = 1.000000 and vScale = 1.008267 2011-07-21 13:06:56.582 New[8169:707] scalePiece exit 2011-07-21 13:06:56.585 New[8169:707] scalePiece enter 2011-07-21 13:06:56.586 New[8169:707] inside else 2011-07-21 13:06:56.588 New[8169:707] currentTouchLocation = {89, 91} and lastTouchPosition= {89, 91} 2011-07-21 13:06:56.589 New[8169:707] deltaMove = {0, 0} 2011-07-21 13:06:56.591 New[8169:707] distance = 0.000000 2011-07-21 13:06:56.597 New[8169:707] [gestureRecognizer scale] = 1.000000 2011-07-21 13:06:56.599 New[8169:707] hScale = 1.000000 and vScale = 1.000000 2011-07-21 13:06:56.600 New[8169:707] scalePiece exit 2011-07-21 13:06:56.603 New[8169:707] scalePiece enter 2011-07-21 13:06:56.604 New[8169:707] inside else 2011-07-21 13:06:56.606 New[8169:707] currentTouchLocation = {89, 182} and lastTouchPosition= {89, 91} 2011-07-21 13:06:56.607 New[8169:707] deltaMove = {0, -91} 2011-07-21 13:06:56.617 New[8169:707] distance = 91.000000 2011-07-21 13:06:56.620 New[8169:707] [gestureRecognizer scale] = 1.000000 2011-07-21 13:06:56.623 New[8169:707] hScale = 1.000000 and vScale = 1.000000 2011-07-21 13:06:56.626 New[8169:707] scalePiece exit 2011-07-21 13:06:56.630 New[8169:707] scalePiece enter 2011-07-21 13:06:56.632 New[8169:707] scalePiece exit 

3 Solutions collect form web for “Использование UIPinchGestureRecognizer для масштабирования uiviews в одном направлении”

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

  piece.transform = CGAffineTransformScale([piece transform], hScale, vScale); 

с различными коэффициентами масштабирования.

Один из способов их расчета состоит в следующем:

  1. определите ivar в своем классе, чтобы сохранить lastTouchPosition ;

  2. в вашем жестовом дескрипторе вы сделаете что-то вроде этого:

     if ([gestureRecognizer state] == UIGestureRecognizerStateBegan){ lastTouchPosition = [gestureRecognize locationInView:yourViewHere]; hScale = 1; vScale = 1; } else if ([gestureRecognizer state] == UIGestureRecognizerStateBegan || [gestureRecognizer state] == UIGestureRecognizerStateChanged){ CGPoint currentTouchLocation = [gestureRecognize locationInView:yourViewHere]; CGPoint deltaMove = CGPointDistance(currentTouchLocation, lastTouchPosition); float distance = sqrt(deltaMove.x*deltaMove.x + deltaMove.y*deltaMove.y); hScale -= abs(deltaMove.x)/distance * (1-gestureRecognizer.scale); vScale -= abs(deltaMove.y)/distance * (1-gestureRecognizer.scale); piece.transform = CGAffineTransformScale([piece transform], hScale, vScale); [gestureRecognizer setScale:1]; lastTouchPosition = currentTouchLocation; } 

Альтернативный способ:

  if ([gestureRecognizer state] == UIGestureRecognizerStateBegan){ lastTouchPosition = [gestureRecognize locationInView:yourViewHere]; } else if ([gestureRecognizer state] == UIGestureRecognizerStateBegan || [gestureRecognizer state] == UIGestureRecognizerStateChanged){ CGPoint currentTouchLocation = [gestureRecognize locationInView:yourViewHere]; CGPoint deltaMove = CGPointDistance(currentTouchLocation, lastTouchPosition); float distance = sqrt(deltaMove.x*deltaMove.x + deltaMove.y*deltaMove.y); float hScale = 1 - abs(deltaMove.x)/distance * (1-gestureRecognizer.scale); float vScale = 1 - abs(deltaMove.y)/distance * (1-gestureRecognizer.scale); piece.transform = CGAffineTransformScale([piece transform], hScale, vScale); lastTouchPosition = currentTouchLocation; } 

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

Обратите внимание, что вам нужно также определить CGPointDistance чтобы рассчитать расстояние между двумя касаниями и выбрать, какой вид вы собираетесь использовать для вычисления расстояния ( yourViewHere ).

РЕДАКТИРОВАТЬ:

 CGPoint CGPointDistance(CGPoint point1, CGPoint point2) { return = CGPointMake(point2.x - point1.x, point2.y - point1.y); }; 

EDIT2: о формуле для вычисления масштабирования

Идея вычисляет изменение масштабного коэффициента и применяет его к двум направлениям (x и y) в соответствии с их относительными вариациями.

  1. дельта масштабного коэффициента: 1-gestureRecognizer.scale ;

  2. дельта умножается на коэффициент так, что она каким-то образом пропорциональна смещению вдоль горизонтальной или вертикальной оси; когда смещение равно нулю, дельта-шкала также равна нулю; когда смещение равно вдоль двух осей, дельта шкалы также равна вдоль двух осей; Я решил разделить distance , но есть и другие возможности (например, деление на сумму двух дельта-мобов или макс дельта-мобов и т. Д.).

  3. скорректированная дельта окончательно вычитается из текущего масштаба элемента.

Сегодня я столкнулся с одной и той же проблемой, и я нашел простой и короткий способ сделать это

 - (IBAction)handlePinch:(UIPinchGestureRecognizer *)recognizer { recognizer.view.transform = CGAffineTransformScale(recognizer.view.transform, recognizer.scale,1); recognizer.scale = 1; } 

Я создал пользовательскую версию UIPinchGestureRecognizer, чтобы сделать именно то, что вы ищете. Он использует наклон линии между двумя пальцами для определения направления шкалы. Он делает 3 типа: Вертикальный; Горизонтальный; и комбинированные (диагональные). Посмотрите мои заметки внизу.

 -(void) scaleTheView:(UIPinchGestureRecognizer *)pinchRecognizer { if ([pinchRecognizer state] == UIGestureRecognizerStateBegan || [pinchRecognizer state] == UIGestureRecognizerStateChanged) { if ([pinchRecognizer numberOfTouches] > 1) { UIView *theView = [pinchRecognizer view]; CGPoint locationOne = [pinchRecognizer locationOfTouch:0 inView:theView]; CGPoint locationTwo = [pinchRecognizer locationOfTouch:1 inView:theView]; NSLog(@"touch ONE = %f, %f", locationOne.x, locationOne.y); NSLog(@"touch TWO = %f, %f", locationTwo.x, locationTwo.y); [scalableView setBackgroundColor:[UIColor redColor]]; if (locationOne.x == locationTwo.x) { // perfect vertical line // not likely, but to avoid dividing by 0 in the slope equation theSlope = 1000.0; }else if (locationOne.y == locationTwo.y) { // perfect horz line // not likely, but to avoid any problems in the slope equation theSlope = 0.0; }else { theSlope = (locationTwo.y - locationOne.y)/(locationTwo.x - locationOne.x); } double abSlope = ABS(theSlope); if (abSlope < 0.5) { // Horizontal pinch - scale in the X [arrows setImage:[UIImage imageNamed:@"HorzArrows.png"]]; arrows.hidden = FALSE; // tranform.a = X-axis NSLog(@"transform.A = %f", scalableView.transform.a); // tranform.d = Y-axis NSLog(@"transform.D = %f", scalableView.transform.d); // if hit scale limit along X-axis then stop scale and show Blocked image if (((pinchRecognizer.scale > 1.0) && (scalableView.transform.a >= 2.0)) || ((pinchRecognizer.scale < 1.0) && (scalableView.transform.a <= 0.1))) { blocked.hidden = FALSE; arrows.hidden = TRUE; } else { // scale along X-axis scalableView.transform = CGAffineTransformScale(scalableView.transform, pinchRecognizer.scale, 1.0); pinchRecognizer.scale = 1.0; blocked.hidden = TRUE; arrows.hidden = FALSE; } }else if (abSlope > 1.7) { // Vertical pinch - scale in the Y [arrows setImage:[UIImage imageNamed:@"VerticalArrows.png"]]; arrows.hidden = FALSE; NSLog(@"transform.A = %f", scalableView.transform.a); NSLog(@"transform.D = %f", scalableView.transform.d); // if hit scale limit along Y-axis then don't scale and show Blocked image if (((pinchRecognizer.scale > 1.0) && (scalableView.transform.d >= 2.0)) || ((pinchRecognizer.scale < 1.0) && (scalableView.transform.d <= 0.1))) { blocked.hidden = FALSE; arrows.hidden = TRUE; } else { // scale along Y-axis scalableView.transform = CGAffineTransformScale(scalableView.transform, 1.0, pinchRecognizer.scale); pinchRecognizer.scale = 1.0; blocked.hidden = TRUE; arrows.hidden = FALSE; } } else { // Diagonal pinch - scale in both directions [arrows setImage:[UIImage imageNamed:@"CrossArrows.png"]]; blocked.hidden = TRUE; arrows.hidden = FALSE; NSLog(@"transform.A = %f", scalableView.transform.a); NSLog(@"transform.D = %f", scalableView.transform.d); // if we have hit any limit don't allow scaling if ((((pinchRecognizer.scale > 1.0) && (scalableView.transform.a >= 2.0)) || ((pinchRecognizer.scale < 1.0) && (scalableView.transform.a <= 0.1))) || (((pinchRecognizer.scale > 1.0) && (scalableView.transform.d >= 2.0)) || ((pinchRecognizer.scale < 1.0) && (scalableView.transform.d <= 0.1)))) { blocked.hidden = FALSE; arrows.hidden = TRUE; } else { // scale in both directions scalableView.transform = CGAffineTransformScale(scalableView.transform, pinchRecognizer.scale, pinchRecognizer.scale); pinchRecognizer.scale = 1.0; blocked.hidden = TRUE; arrows.hidden = FALSE; } } // else for diagonal pinch } // if numberOfTouches } // StateBegan if if ([pinchRecognizer state] == UIGestureRecognizerStateEnded || [pinchRecognizer state] == UIGestureRecognizerStateCancelled) { NSLog(@"StateEnded StateCancelled"); [scalableView setBackgroundColor:[UIColor whiteColor]]; arrows.hidden = TRUE; blocked.hidden = TRUE; } } 

Не забудьте добавить протокол в заголовочный файл контроллера представления:

 @interface WhiteViewController : UIViewController <UIGestureRecognizerDelegate> { IBOutlet UIView *scalableView; IBOutlet UIView *mainView; IBOutlet UIImageView *arrows; IBOutlet UIImageView *blocked; } @property (strong, nonatomic) IBOutlet UIView *scalableView; @property (strong, nonatomic) IBOutlet UIView *mainView; @property (strong, nonatomic)IBOutlet UIImageView *arrows; @property (strong, nonatomic)IBOutlet UIImageView *blocked; -(void) scaleTheView:(UIPinchGestureRecognizer *)pinchRecognizer; @end 

И добавьте распознаватель в viewDidLoad:

 - (void)viewDidLoad { UIPinchGestureRecognizer *pinchGesture = [[UIPinchGestureRecognizer alloc] initWithTarget:self action:@selector(scaleTheView:)]; [pinchGesture setDelegate:self]; [mainView addGestureRecognizer:pinchGesture]; arrows.hidden = TRUE; blocked.hidden = TRUE; [scalableView setBackgroundColor:[UIColor whiteColor]];} 

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

ОГРАНИЧЕНИЯ: Я произвольно выбрал начальный размер моего представления, поэтому предел масштаба 2.0 равнялся бы полному экрану. Моя нижняя шкала установлена ​​в 0,1.

ВЗАИМОДЕЙСТВИЕ ПОЛЬЗОВАТЕЛЯ: я общаюсь с большим количеством пользовательских действий, таких как изменение цвета фона представления и добавление / изменение стрелок над представлением, чтобы показать направление. Очень важно дать им обратную связь во время процесса масштабирования, особенно при смене направлений, как это делают коды.

Ошибка: в UIPinchGestureRecognizer от Apple есть ошибка. Он регистрирует UIGestureRecognizerStateBegan одним нажатием 2 пальцев, как и следовало ожидать. Но как только в StateBegan или StateChanged вы можете поднять один палец, и состояние остается. Он не перемещается в StateEnded или StateCancelled, пока оба пальца не будут подняты. Это создало ошибку в моем коде и много головных болей! Если numberOfTouches> 1 исправляет это.

БУДУЩЕЕ: вы можете изменить настройки наклона на шкалу только в одном направлении или просто 2. Если вы добавите изображения стрелок, вы можете увидеть их изменение при повороте пальцев.

  • iOS Как получить текущую выбранную строку индексного пути в методе cellForRowAtIndexPath?
  • UILongPressGestureRecognizer дважды запускается
  • Как переопределить распознаватель жестов на UIButton, чтобы позволить событиям крана пузыриться для наблюдения?
  • Предел UITableView панорамирования до 1 палец
  • UITapGestureRecognizer не работает на iOS9
  • UITapGestureRecognizer в UIView и его подвью ответят вместе, когда Subview забит
  • Получение действия UIGestureRecognizer в iOS
  • iOS UIActionSheet, представленный с жестов LongPress на кнопке, ошибочно требует двойных щелчков, чтобы отклонить
  • Отключить жестов в UIPageViewController
  • Пользовательский UIGestureRecognizer: селектор не получает UIGestureRecognizerStateBegan
  • Fire UIPanGestureRecognizer с внешней отправной точкой
  • PhoneC: Разработка iOS проста с помощью XCode, Swift3, UITableView, cocatouch, давайте создадим приложения для iPhone, iPad и Macbook.