垂直的UIScrollView? [英] Vertical UIScrollView?

查看:64
本文介绍了垂直的UIScrollView?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在为iOS的开发而苦苦挣扎,希望有人能够为我提供建议.我想实现一堆看起来像一副纸牌的UIView.用户应该能够通过触摸刷出卡片".我想到了带有pageingEnabled的UIScrollViews,给人的印象是卡是分开的.但是,UIScrollView可以从左侧或右侧出现内容的地方水平滑动.我希望卡片组位于屏幕的中间,以便用户可以从卡片组上刷卡,而不会看到卡出现在左侧或右侧. 另外,我还在考虑使用触摸方法"(touchesBegan,touchesMoved等)来移动视图.它可以工作...但是我担心我无法重现卡片的正确机制(摩擦,滑动短时的弹跳效果等等).

Im struggling with some iOS development and I hope someone will be able to help me with an advice. I want to implement a stack of UIViews that will look like a deck of cards. User should be able to swipe out 'cards' with touch. I thought of UIScrollViews with pagingEnabled to give an impression that cards are separate. However, UIScrollView can swipe from horizontally where something appears from left or right side. I want my deck of cards to be in the middle of the screen so the user can swipe cards from the deck without seeing the card appearing on the left or right side. Also, I was thinking of using Touch Methods ( touchesBegan, touchesMoved, etc.) to move views. It could work... but Im worried that I wont be able to reproduce proper mechanics of the card ( friction, bouncing effect when the swipe is to short and so on..).

有人可以向我指出适当的技术或为一些教程提供建议吗?我已经做过一些研究,但找不到任何有用的东西.

Can someone please point me to a proper technique or advice some tutorials? I did some research already but I couldn't find anything that would be helpful.

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

Here is an image of the effect that I would like to achieve.

我想要实现的是从卡组中刷卡.

And what I want to achieve is to swipe cards out of the deck.

非常感谢!

推荐答案

我想您想通过滑动将堆栈顶部的卡牌洗牌"到堆栈底部,以显示堆栈中的第二张卡,就像这样:

I guess you want a swipe to take the top card of the stack and "shuffle" it to the bottom of the stack, revealing the second card on the stack, like this:

动画在现实生活中更加流畅.我必须使用低帧频来使动画GIF变小.

The animation is much smoother in real life. I had to use a low frame rate to make the animated GIF small.

执行此操作的一种方法是创建UIView的子类,该子类管理卡视图的堆栈.让我们将经理视图称为BoardView.我们将为它提供两种公共方法:一种用于将顶部卡改组到底部,另一个用于将底部卡改组到顶部.

One way to do this is to create a subclass of UIView that manages the stack of card views. Let's call the manager view a BoardView. We'll give it two public methods: one for shuffling the top card to the bottom, and one for shuffling the bottom card to the top.

@interface BoardView : UIView

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

@end

@implementation BoardView {
    BOOL _isRestacking;
}

我们将使用_isRestacking变量来跟踪棋盘视图是否使一张牌向侧面移动的动画化.

We'll use the _isRestacking variable to track whether the board view is animating the movement of a card off to the side.

A BoardView会将其所有子视图视为卡片视图.它负责将它们堆叠在一起,并使顶部卡居中.在屏幕截图中,您将较低的卡片偏移了一些随机的数量.通过随机旋转较低的卡片,我们可以使它看起来更性感.此方法对视图应用较小的随机旋转:

A BoardView treats all of its subviews as card views. It takes care of stacking them up, with the top card centered. In your screen shot, you offset the lower cards by slightly randomized amounts. We can make it look a little sexier by rotating the lower cards randomly. This method applies a small random rotation to a view:

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

我们希望将其应用于添加的每个子视图:

We'll want to apply that to each subview as it's added:

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

每当视图的大小更改或给视图赋予新的子视图时,系统都会发送layoutSubviews.我们将利用它的优势,将所有卡堆叠在板视图边界的中间.但是,如果视图当前正在对卡片进行动画处理,则我们不希望进行布局,因为它会杀死动画.

The system sends layoutSubviews whenever a view's size changes, or when a view has been given new subviews. We'll take advantage of that to lay out all of the cards in a stack in the middle of the board view's bounds. But if the view is currently animating a card out of the way, we don't want to do the layout because it would kill the 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;
    }
}

现在,我们已经准备好应对改组.要转到下一张卡片",我们需要设置动画,将顶部的卡片移到侧面,然后将其移到子视图堆叠顺序的底部,然后再将其设置回中间.我们还需要轻推所有其他卡的位置,因为它们都移到了堆栈顶部附近.

Now we're ready to handle the shuffling. To "go to the next card", we need to animate moving the top card off to the side, then move it to the bottom of the subview stacking order, and then animate it back to the middle. We also need to nudge the positions of all of the other cards because they've all moved closer to the top of the stack.

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

首先,我们对顶卡向侧面的移动进行动画处理.为了使其看起来更性感,我们在移动卡片时会旋转卡片.

First, we animate the movement of the top card off to the side. To make it look sexy, we rotate the card as we move it.

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

在完成区中,我们将卡片移到堆栈的底部.

In the completion block, we move the card to the bottom of the stack.

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

然后要将现在底端的卡移回堆栈中,并轻推所有其他卡,我们只需调用layoutSubviews.但是我们不应该直接调用layoutSubviews,所以我们使用正确的API:setNeedsLayout,后跟layoutIfNeeded.我们在动画块内调用layoutIfNeeded,以便将牌动画化到新位置.

And to move the now-bottom card back into the stack, and nudge all of the other cards, we'll just call layoutSubviews. But we're not supposed to call layoutSubviews directly, so instead we use the proper APIs: setNeedsLayout followed by layoutIfNeeded. We call layoutIfNeeded inside an animation block so the cards will be animated into their new positions.

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

这是goToNextCard的结尾.我们可以类似地执行goToPriorCard:

That's the end of goToNextCard. We can do goToPriorCard similarly:

- (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消息的另一个滑动手势识别器.并且您需要添加一些子视图以用作卡片.

Once you have BoardView, you just need to attach a swipe gesture recognizer that sends it the goToNextCard message, and another swipe gesture recognizer that sends it the goToPriorCard message. And you need to add some subviews to act as cards.

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

Another detail: to get the edges of the cards to look smooth when they're jostled, you need to set UIViewEdgeAntialiasing to YES in your Info.plist.

您可以在这里找到我的测试项目: http://dl.dropbox.com/u/26919672/cardstack.zip

You can find my test project here: http://dl.dropbox.com/u/26919672/cardstack.zip

这篇关于垂直的UIScrollView?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆