垂直的UIScrollView?

我努力与一些iOS开发,我希望有人能够帮助我的build议。 我想实现一堆看起来像一副牌的UIViews。 用户应该能够触摸刷卡。 我想到了使用pagingEnabled的UIScrollViews给人一种印象是分开的印象。 但是,UIScrollView可以从左侧或右侧出现某些东西。 我希望我的一副牌位于屏幕的中间,这样用户就可以从甲板上刷卡,而不会看到左侧或右侧出现的牌。 此外,我正在考虑使用触摸方法(touchesBegan,touchesMoved等)来移动视图。 它可以工作…但我担心,我将无法再现卡的适当机制(摩擦,刷卡短路时的弹跳效果等)。

有人可以指点我一个正确的技术或build议一些教程? 我已经做了一些研究,但是我找不到任何有用的东西。

这是我想达到的效果的图像。

在这里输入图像说明

而我想要达到的目的就是将卡片从甲板上划出。

非常感谢!

我想你想要一个滑动,拿到堆栈顶部的卡,并“洗牌”到堆栈的底部,揭示堆栈中的第二张牌,如下所示:

卡从甲板的顶部移动到底部

animation在现实生活中更加顺畅。 我不得不使用较低的帧速率使animationGIF变小。

一种方法是创buildUIView的子类来pipe理卡片视图的堆栈。 让我们打电话给经理查看BoardView 。 我们会给出两种公开的方法:一种是将顶部牌洗牌到底部,另一种是将底牌洗牌到顶部。

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

我们将使用_isRestackingvariables来跟踪棋盘视图是否将卡片的移动animation化。

BoardView将其所有子视图视为卡片视图。 它需要把它们堆叠起来,以顶部卡片为中心。 在你的屏幕截图中,你用稍微随机的数量抵消了较低的牌。 我们可以通过随机旋转较低的牌来使它看起来更性感。 该方法将一个小的随机旋转应用于视图:

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

我们将要添加到每个子视图中:

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

只要视图的大小发生变化,或视图被赋予新的子视图,系统就会发送layoutSubviews 。 我们将利用这个优势,在棋盘视图边界的中间放置所有牌。 但是,如果视图目前正在animation卡片,我们不想做布局,因为它会杀死animation。

 - (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; } } 

现在我们准备好处理洗牌了。 为了“下一张牌”,我们需要animation将顶牌移到侧面,然后将其移动到子视图堆叠顺序的底部,然后将其移动到中间。 我们还需要推动所有其他牌的位置,因为他们已经全部靠近堆叠顶部。

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

首先,我们将顶牌的移动animation化。 为了使它看起来性感,我们旋转卡片,当我们移动它。

  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 ,所以我们使用适当的API: setNeedsLayoutlayoutIfNeeded 。 我们在animation块内部调用layoutIfNeeded这样卡片就会变成新的位置。

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

这是goToNextCard的结尾。 我们同样可以做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时看起来平滑,您需要在Info.plist中将UIViewEdgeAntialiasing设置为YES

你可以在这里find我的testing项目: http : //dl.dropbox.com/u/26919672/cardstack.zip

Icarousel具有精确的内置使用UIImageViews滚动。

https://github.com/nicklockwood/iCarousel 。 那里有几个不同的效果,我忘了你描述的名字。