首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >垂直UIScrollView?

垂直UIScrollView?
EN

Stack Overflow用户
提问于 2012-02-21 05:58:31
回答 2查看 1.3K关注 0票数 0

我正在为一些iOS开发而苦苦挣扎,我希望有人能给我一个建议。我想实现一个看起来像一副纸牌的UIViews堆栈。用户应该能够刷出“卡”与触摸。我把UIScrollViews和pagingEnabled结合起来,给人的印象是卡片是分开的。但是,UIScrollView可以从左侧或右侧水平滑动对象。我希望我的卡片组在屏幕的中间,这样用户就可以从卡片组中刷卡,而不会看到卡片出现在左边或右边。此外,我还在考虑使用Touch方法( touchesBegan、touchesMoved等)。移动视图。它可以工作的..。但我担心我不能重现卡片的正确机制(摩擦力,当刷卡太短时的反弹效果等等)。

有没有人能给我指点合适的技巧或建议一些教程?我已经做了一些研究,但我找不到任何有用的东西。

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

我想要实现的是将卡片从卡片组中刷出来。

非常感谢!

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2012-02-21 12:16:02

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

动画在现实生活中要流畅得多。我不得不使用较低的帧速率来使动画GIF变小。

要做到这一点,一种方法是创建一个管理卡片视图堆栈的UIView子类。让我们将管理器视图称为BoardView。我们将为它提供两个公共方法:一个用于将顶部卡片洗牌到底部,另一个用于将底部卡片洗牌到顶部。

代码语言:javascript
运行
复制
@interface BoardView : UIView

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

@end

@implementation BoardView {
    BOOL _isRestacking;
}

我们将使用_isRestacking变量来跟踪棋盘视图是否正在设置卡片向一侧移动的动画。

BoardView将其所有子视图视为卡片视图。它负责将它们堆叠起来,最上面的卡片居中。在您的屏幕截图中,您通过稍微随机的数量来偏移较低的牌。我们可以通过随机旋转下面的牌来让它看起来更性感一点。此方法对视图应用小的随机旋转:

代码语言:javascript
运行
复制
- (void)jostleSubview:(UIView *)subview {
    subview.transform = CGAffineTransformMakeRotation((((double)arc4random() / UINT32_MAX) - .5) * .2);
}

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

代码语言:javascript
运行
复制
- (void)didAddSubview:(UIView *)subview {
    [self jostleSubview:subview];
}

每当视图的大小发生变化时,或者当视图被赋予了新的子视图时,系统都会发送layoutSubviews。我们将利用这一点将所有卡片放在板视图边界中间的堆栈中。但是,如果视图当前正在对一张卡进行动画处理,我们不想进行布局,因为这会扼杀动画。

代码语言:javascript
运行
复制
- (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;
    }
}

现在我们准备好处理洗牌了。要“转到下一张卡片”,我们需要动画将顶部的卡片移到一侧,然后将其移动到子视图堆叠顺序的底部,然后将其动画移回中间。我们还需要轻推所有其他卡片的位置,因为它们都移动到了堆栈的顶部。

代码语言:javascript
运行
复制
- (void)goToNextCard {
    if (self.subviews.count < 2)
        return;

首先,我们动画顶端的卡片移动到一边。为了让它看起来更性感,我们在移动卡片的时候旋转它。

代码语言:javascript
运行
复制
    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);
    }

在完成块中,我们将卡片移动到堆栈的底部。

代码语言:javascript
运行
复制
    completion:^(BOOL finished) {
        _isRestacking = NO;
        [self sendSubviewToBack:movingView];

要将现在最底层的卡片移回到堆栈中,并轻推所有其他卡片,我们只需调用layoutSubviews。但是我们不应该直接调用layoutSubviews,所以我们使用正确的API:setNeedsLayout后跟layoutIfNeeded。我们在动画块中调用layoutIfNeeded,这样卡片就会被动画到它们的新位置。

代码语言:javascript
运行
复制
        [self setNeedsLayout];
        [UIView animateWithDuration:1 delay:0 options:UIViewAnimationCurveEaseInOut | UIViewAnimationOptionAllowUserInteraction animations:^{
            [self jostleSubview:movingView];
            [self layoutIfNeeded];
        } completion:nil];
    }];
}

这就是goToNextCard的终结。我们可以用类似的方法来做goToPriorCard

代码语言:javascript
运行
复制
- (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消息的滑动手势识别器。并且您需要添加一些子视图来充当卡片。

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

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

票数 13
EN

Stack Overflow用户

发布于 2012-02-21 07:08:19

Icarousel使用UIImageViews实现了精确的滚动功能。

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

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/9369034

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档