Вертикальный UIScrollView?

Я борюсь с некоторыми разработками iOS, и я надеюсь, что кто-то сможет помочь мне с советом. Я хочу реализовать стек UIViews, который будет выглядеть как колода карт. Пользователь должен уметь вытаскивать «карточки» с прикосновением. Я думал о UIScrollViews с pagingEnabled, чтобы создать впечатление, что карты являются отдельными. Однако UIScrollView может перемещаться по горизонтали, где что-то появляется с левой или с правой стороны. Я хочу, чтобы моя колода карт была посередине экрана, чтобы пользователь мог пронести карты из колоды, не видя карты, появляющейся с левой или с правой стороны. Кроме того, я думал об использовании Touch Method (touchhesBegan, touchhesMoved и т. Д.) Для перемещения представлений. Это может сработать … но Im беспокоился, что я не смогу воспроизвести правильную механику карты (трение, эффект отскока, когда салфетка будет коротка и т. Д.).

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

Вот изображение того эффекта, который я бы хотел достичь.

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

И я хочу, чтобы вытащить карты из колоды.

Большое спасибо!

Я предполагаю, что вы хотите, чтобы салфетка взяла верхнюю карту стека и «перетасовала» ее на дно стека, открыв вторую карту в стеке, например:

карта, перемещающаяся сверху вниз

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

Один из способов сделать это – создать подкласс UIView который управляет стеком представлений карт. Давайте позвоним менеджеру BoardView . Мы дадим ему два общедоступных метода: один для перетасовки верхней карты на дно и один для перетасовки нижней карты вверх.

 @interface BoardView : UIView - (IBAction)goToNextCard; - (IBAction)goToPriorCard; @end @implementation BoardView { BOOL _isRestacking; } 

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

BoardView рассматривает все его подзоны как виды карт. Он заботится о том, чтобы уложить их вверх, при этом верхняя карта центрирована. На вашем снимке экрана вы компенсируете низкие карты небольшими рандомизированными суммами. Мы можем заставить его выглядеть немного сексуальнее, вращая нижние карты случайным образом. Этот метод применяет небольшое случайное вращение к виду:

 - (void)jostleSubview:(UIView *)subview { subview.transform = CGAffineTransformMakeRotation((((double)arc4random() / UINT32_MAX) - .5) * .2); } 

Мы хотим применить это к каждому подвью, поскольку оно добавлено:

 - (void)didAddSubview:(UIView *)subview { [self jostleSubview:subview]; } 

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

 - (void)layoutSubviews { if (_isRestacking) return; CGRect bounds = self.bounds; CGPoint center = CGPointMake(CGRectGetMidX(bounds), CGRectGetMidY(bounds)); UIView *topView = self.subviews.lastObject; CGFloat offset = 10.0f / self.subviews.count; for (UIView *view in self.subviews.reverseObjectEnumerator) { view.center = center; if (view == topView) { // Make the top card be square to the edges of the screen. view.transform = CGAffineTransformIdentity; } center.x -= offset; center.y -= offset; } } 

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

 - (void)goToNextCard { if (self.subviews.count < 2) return; 

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

  UIView *movingView = self.subviews.lastObject; [UIView animateWithDuration:1 delay:0 options:UIViewAnimationCurveEaseInOut animations:^{ _isRestacking = YES; CGPoint center = movingView.center; center.x = -hypotf(movingView.frame.size.width / 2, movingView.frame.size.height / 2); movingView.center = center; movingView.transform = CGAffineTransformMakeRotation(-M_PI_4); } 

В блоке завершения мы переносим карту в нижнюю часть стека.

  completion:^(BOOL finished) { _isRestacking = NO; [self sendSubviewToBack:movingView]; 

И, чтобы переместить теперь нижнюю карту обратно в стек и подтолкнуть все остальные карты, мы просто вызываем layoutSubviews . Но мы не должны напрямую layoutSubviews на layoutSubviews , поэтому вместо этого мы используем соответствующие API: setNeedsLayout за которым следует layoutIfNeeded . Мы называем layoutIfNeeded внутри блока анимации, чтобы карты были анимированы в их новые позиции.

  [self setNeedsLayout]; [UIView animateWithDuration:1 delay:0 options:UIViewAnimationCurveEaseInOut | UIViewAnimationOptionAllowUserInteraction animations:^{ [self jostleSubview:movingView]; [self layoutIfNeeded]; } completion:nil]; }]; } 

Это конец goToNextCard . goToPriorCard образом мы можем сделать goToPriorCard :

 - (void)goToPriorCard { if (self.subviews.count < 2) return; UIView *movingView = [self.subviews objectAtIndex:0]; [UIView animateWithDuration:1 delay:0 options:UIViewAnimationOptionCurveEaseInOut animations:^{ _isRestacking = YES; CGPoint center = movingView.center; center.x = -movingView.frame.size.height / 2; movingView.center = center; movingView.transform = CGAffineTransformMakeRotation(-M_PI_4); } completion:^(BOOL finished) { _isRestacking = NO; UIView *priorTopView = self.subviews.lastObject; [self bringSubviewToFront:movingView]; [self setNeedsLayout]; [UIView animateWithDuration:1 delay:0 options:UIViewAnimationOptionCurveEaseInOut | UIViewAnimationOptionAllowUserInteraction animations:^{ [self jostleSubview:priorTopView]; [self layoutIfNeeded]; } completion:nil]; }]; } 

После того, как у вас есть BoardView , вам просто нужно подключить распознаватель жестов, который отправляет ему сообщение goToNextCard , а также другой распознаватель жестов, который отправляет ему сообщение goToPriorCard . И вам нужно добавить некоторые подпункты, чтобы действовать как карты.

Другая деталь: чтобы края карт выглядели гладкими, когда они толкались, вам нужно установить UIViewEdgeAntialiasing в YES в вашем Info.plist .

Вы можете найти мой тестовый проект здесь: http://dl.dropbox.com/u/26919672/cardstack.zip

У Icarousel есть точная встроенная прокрутка с использованием UIImageViews.

https://github.com/nicklockwood/iCarousel . Там есть несколько разных эффектов, я забыл название того, что вы описываете.

Interesting Posts
Давайте будем гением компьютера.