Iphone 垂直视图?

Iphone 垂直视图?,iphone,objective-c,ios,uiscrollview,Iphone,Objective C,Ios,Uiscrollview,我正在努力开发iOS,我希望有人能给我一个建议。我想实现一个UIView堆栈,看起来就像一副牌。用户应该能够用触摸刷出“卡片”。我想到了带分页的UIScrollView,它能给人一种卡片是分开的印象。但是,UIScrollView可以从左侧或右侧显示内容的位置水平滑动。我想把我的牌牌放在屏幕中间,这样用户就可以从卡片上刷卡而不看卡出现在左边或右边。 此外,我还考虑使用触摸方法(touchsbegind、touchsmoved等)来移动视图。它可以工作。。。但我担心我无法重现卡的正确机制(摩擦、刷

我正在努力开发iOS,我希望有人能给我一个建议。我想实现一个UIView堆栈,看起来就像一副牌。用户应该能够用触摸刷出“卡片”。我想到了带分页的UIScrollView,它能给人一种卡片是分开的印象。但是,UIScrollView可以从左侧或右侧显示内容的位置水平滑动。我想把我的牌牌放在屏幕中间,这样用户就可以从卡片上刷卡而不看卡出现在左边或右边。 此外,我还考虑使用触摸方法(touchsbegind、touchsmoved等)来移动视图。它可以工作。。。但我担心我无法重现卡的正确机制(摩擦、刷短时的反弹效应等等)

有人能给我指一个合适的技巧或者一些指导吗?我已经做了一些研究,但是我找不到任何有用的东西

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

我想要实现的是把牌从牌堆里刷出来


非常感谢

Icarousel使用UIImageView实现了精确的内置滚动


。这里有几个不同的效果,我忘了你描述的那个的名字

我想你需要一次刷卡,将牌堆顶部的牌“洗牌”到牌堆底部,露出牌堆上的第二张牌,如下所示:

动画在现实生活中要平滑得多。我不得不使用低帧速率使动画GIF变小

一种方法是创建
UIView
的子类来管理卡片视图的堆栈。让我们将经理视图称为一个
BoardView
。我们将给它两种公开的方法:一种用于将顶部的牌洗牌到底部,另一种用于将底部的牌洗牌到底部

@interface BoardView : UIView

- (IBAction)goToNextCard;
- (IBAction)goToPriorCard;

@end

@implementation BoardView {
    BOOL _isRestacking;
}
我们将使用
\u isRestacking
变量跟踪board视图是否正在设置卡向一侧移动的动画

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;
    completion:^(BOOL finished) {
        _isRestacking = NO;
        [self sendSubviewToBack:movingView];
在完成块中,我们将卡移动到堆栈的底部

- (void)goToNextCard {
    if (self.subviews.count < 2)
        return;
    completion:^(BOOL finished) {
        _isRestacking = NO;
        [self sendSubviewToBack:movingView];
要将现在最底部的卡移回堆栈,并轻推所有其他卡,我们只需调用
layoutSubviews
。但是我们不应该直接调用
layoutSubviews
,因此我们使用适当的API:
setNeedsLayout
,后跟
layoutifneed
。我们在动画块中调用
layoutifneedd
,以便将卡片动画化到其新位置

        [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];
    }];
}
-(无效)GoToPriorioCard{
if(self.subviews.count<2)
回来
UIView*movingView=[self.subviews objectAtIndex:0];
[UIView animateWithDuration:1延迟:0选项:UIViewAnimationOptionCurveEaseInOut动画:^{
_isRestacking=是;
CGPoint center=movingView.center;
center.x=-movingView.frame.size.height/2;
movingView.center=中心;
movingView.transform=CGAffineTransformMakeRotation(-M_PI_4);
}完成:^(布尔完成){
_isRestacking=否;
UIView*priorTopView=self.subviews.lastObject;
[self-BringSubview to Front:movingView];
[self-setNeedsLayout];
[UIView animateWithDuration:1延迟:0选项:UIViewAnimationOptionCurveEaseInOut | UIViewAnimationOptionLowUserInteraction动画:^{
[自碰撞子视图:优先级视图];
[需要自行布局];
}完成:无];
}];
}
一旦你有了BoardView,你只需要附加一个滑动手势识别器,它向你发送
goToNextCard
信息,另一个滑动手势识别器向你发送
goToPriorCard
信息。您需要添加一些子视图来充当卡片

另一个细节:要使卡的边缘在碰撞时看起来平滑,需要在
Info.plist
中将
uiviewedgeanialiasing
设置为
YES


你可以在这里找到我的测试项目:

在读了三四遍之后,我仍然不确定你的问题是什么。对我来说,不清楚你想要实现什么(尽管我没有否决你的问题)。也许一个插图可以帮助解释你想看到的效果。当然。。。图示马上就到。抱歉搞混了。那么,有什么问题吗?你有代表一副牌的视图吗?在该视图上放置一个UIImageView,该视图将表示顶部卡。对于您的视图,实现用户交互方法(或UIgestureRecognitor)。用户在视图上滑动后,更改UIImageView(表示顶部卡的imageview)图像。为什么不使用lay