类似于iOS7打开应用程序的动画效果

10

我想创建一种类似于iOS7中iPhone应用程序打开的动画。在这个动画中,它只显示应用程序从哪个点打开并在同一点关闭。

有人能帮忙吗?


你找到任何解决方案了吗? - OzBoz
4个回答

18
@property (weak, nonatomic) IBOutlet UIImageView *bg;
@property (weak, nonatomic) IBOutlet UIImageView *cal;
…

bool nowZoomed = NO;
CGRect iconPosition = {16,113,60,60}; // customize icon position

- (CGRect)zoomedRect // just a helper function, to get the new background screen size
{
    float screenWidth = UIScreen.mainScreen.bounds.size.width;
    float screenHeight = UIScreen.mainScreen.bounds.size.height;

    float size = screenWidth / iconPosition.size.width;
    float x = screenWidth/2 - (CGRectGetMidX(iconPosition) * size);
    float y = screenHeight/2 - (CGRectGetMidY(iconPosition) * size);

    return CGRectMake(x, y, screenWidth * size, screenHeight * size);
}

- (IBAction)test
{
    float animationDuration = 0.3f; //default
    if (nowZoomed) // zoom OUT
    {
        [UIView animateWithDuration:animationDuration animations:^{ // animate to original frame
            _cal.frame = iconPosition;
            _bg.frame = UIScreen.mainScreen.bounds;
        } completion:^(BOOL finished) {
            [UIView animateWithDuration:animationDuration/2.0f animations:^{ // then fade out
                _cal.alpha = 0.0f;
            } completion:^(BOOL finished) {
                _cal.hidden = YES;
            }];
        }];
    }
    else // zoom IN
    {
        _cal.alpha = 0.0f;
        _cal.hidden = NO;
        [UIView animateWithDuration:animationDuration/2.0f animations:^{ // fade in faster
            _cal.alpha = 1.0f;
        }];
        [UIView animateWithDuration:animationDuration animations:^{ // while expanding view
            _cal.frame = UIScreen.mainScreen.bounds;
            _bg.frame = [self zoomedRect];
        }];
    }
    nowZoomed = !nowZoomed;
}

你可以通过创建一个类似这样的示例项目来测试它:

  • 像我一样从模拟器中制作两个截图(主屏幕和日历视图),或者获取这两个链接:homescreen / calendar
  • 在Storyboard中添加2个ImageView和1个Button
  • 将背景ImageView设置为整个屏幕大小
  • 将另一个ImageView设置为{16,113,60,60}的尺寸
  • 为两个ImageView创建一个IBOutlet(代码的前两行)
  • 将按钮动作目标设置为-(void)test

storyboard animation Storyboard图片(左)和动画转换(右)


看看这个答案,了解如何获取当前视图的图像,您可以用它来进行缩放 ;)。 - user207616
你如何保持imageView左侧锚定? - Ahmed Z.

4
我个人更喜欢在这种情况下使用 CGAffineTransformMakeScale() 并设置 -[CALayer affineTransform]
affineTransform 很容易使用,而且有一些来自核心动画的不错的隐式优点。例如,它会隐式地处理更改框架原点的操作,并使重置回初始大小变得非常容易 - 你从未失去过它!
[UIView animateWithDuration:0.3 animations:^{
    view.layer.affineTransform = CGAffineTransformMakeScale(10.0, 10.0); // To make a view larger:
    otherView.layer.affineTransform = CGAffineTransformMakeScale(0.0, 0.0); // to make a view smaller
}];

并且

// To reset views back to their initial size after changing their sizes:
[UIView animateWithDuration:0.3 animations:^{
    view.layer.affineTransform = CGAffineTransformIdentity;
    otherView.layer.affineTransform = CGAffineTransformIdentity;
}];

在你做了一段时间后,你可能会认为通过框架和中心属性来移动物体非常有限。我建议在UIView上创建一个小分类(如果你喜欢直接绘制到CALayer上,则也可以在CALayer上创建),并添加一个-(void)setTransform:(CGAffineTransform)transform animated:(BOOL)animated;的方法。我离不开它。 - Jef

2
据我所知,该动画是使用屏幕截图制作的。它更新了视图的帧,并同时使应用程序标志向应用程序的屏幕截图平滑过渡。我已经模仿了从设备右下角打开iPod(音乐)应用程序到屏幕大小的过程。
UIView * v = [[UIView alloc]init];
CGSize size = self.view.bounds.size;
CGRect frameInitial = CGRectMake(size.width - 30, size.height - 30, 20, 20);
CGRect frameFinal = CGRectMake(0,0, size.width, size.height);
[v setFrame:frameInitial];

当你想要动画框架大小时,请使用以下行:

[UIView animateWithDuration:0.3f
                      delay:0.0f
                    options:UIViewAnimationOptionBeginFromCurrentState
                 animations:^{

    [v setFrame:frameFinal];

} completion:nil];

编辑:没有意识到缩放也包括背景。下面的代码未经过测试(我不在工作岗位上),因此请预期会有一些缺陷和打字错误。

想象一下,您在视图控制器的视图上有两个层。直接在vc上有您想要打开的应用程序,让我们称其为finalView。在顶层上有一个窗口,其中包含所有应用程序,它将缩放并褪色为您的应用程序,这是一个在其后面的视图。让我们称其为firstView。

初始条件:firstView具有320 x 480的框架(它是带有所有应用程序图标的窗口)。它的alpha为1。finalView具有相同的框架和alpha,但它在firstView后面。 最终条件:finalView仍将具有相同的框架和alpha。但是,firstView将缩放到右下角(将具有巨大的框架)并淡出(alpha -> 0)。

// 初始状态:(或更好的方法是使用IB)

CGRect frameInitial = CGRectMake(0,0, self.view.size.width, self.view.size;
CGRect frameFinal = CGRectMake(self.view.size.width * -4 ,self.view.size.height * -5, self.view.size.width * -5,self.view.size.width * -6);
[v setFrame:frameInitial];

当您想要动画帧大小时,请使用以下行:

[UIView animateWithDuration:0.3f
                      delay:0.0f
                    options:UIViewAnimationOptionBeginFromCurrentState
                 animations:^{

                                 [v setFrame:frameFinal];

                              } completion:nil];

Yunus,还有一种方法是将新视图的框架设置为self.view.frame,从而实现背景缩放。我该如何做到这一点? - Alfa
实际上,我编写的代码是用于缩放的(将应用程序标志放在右下角并放入self.view.frame中)。 - Yunus Nedim Mehel
@Alfa 改进了答案。 - Yunus Nedim Mehel

1

我有一个小型库,使用UICollectionViewFloatLayout创建缩放效果,https://github.com/MichaelQuan/ios7ZoomEffect。它仍在不断改进中,但基本思路已经存在。

布局代码如下:

@interface ExpandingCollectionViewLayout ()

@property (nonatomic, assign) CGRect selectedCellFrame;
@property (nonatomic, strong) NSIndexPath *selectedIndexPath;

@end

- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect
{
    NSArray *layoutAttributes = [super layoutAttributesForElementsInRect:rect];

    [layoutAttributes enumerateObjectsUsingBlock:^(UICollectionViewLayoutAttributes *obj, NSUInteger idx, BOOL *stop) {
        [self _transformLayoutAttributes:obj];
    }];

    return layoutAttributes;
}

- (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath
{
    UICollectionViewLayoutAttributes *layoutAttributes = [super layoutAttributesForItemAtIndexPath:indexPath];

    [self _transformLayoutAttributes:layoutAttributes];

    return layoutAttributes;
}

- (void)_transformLayoutAttributes:(UICollectionViewLayoutAttributes *)layoutAttributes
{
    if (self.selectedIndexPath != nil)
    {
        if ([layoutAttributes.indexPath isEqual:self.selectedIndexPath]) {
            // set the frame to be the bounds of the collectionView to expand to the entire collectionView
            layoutAttributes.frame = self.collectionView.bounds;
        } else {
            //scale = collectionView.size / cell_selected.size
            //translate = (scale - 1)(cell_i.center - cell_selected.center) + (collectionView.center - cell_selected.center)

            CGRect collectionViewBounds = self.collectionView.bounds;

            CGRect selectedFrame = self.selectedCellFrame;
            CGRect notSelectedFrame = layoutAttributes.frame;

            // Calculate the scale transform based on the ratio between the selected cell's frame and the collection views bound
            // Scale on that because we want everything to look scaled by the same amount, and the scale is dependent on how much the selected cell has to expand
            CGFloat x_scale = collectionViewBounds.size.width / selectedFrame.size.width;
            CGFloat y_scale = collectionViewBounds.size.height / selectedFrame.size.height;
            CGAffineTransform scaleTransform = CGAffineTransformMakeScale(x_scale, y_scale);

            // Translation based on how much the selected cell has been scaled
            // translate based on the (scale - 1) and delta between the centers
            CGFloat x_zoomTranslate = (x_scale - 1) * (CGRectGetMidX(notSelectedFrame) - CGRectGetMidX(selectedFrame));
            CGFloat y_zoomTranslate = (y_scale - 1) * (CGRectGetMidY(notSelectedFrame) - CGRectGetMidY(selectedFrame));
            CGAffineTransform zoomTranslate = CGAffineTransformMakeTranslation(x_zoomTranslate, y_zoomTranslate); //Translation based on how much the cells are scaled

            // Translation based on where the selected cells center is
            // since we move the center of the selected cell when expanded to full screen, all other cells must move by that amount as well
            CGFloat x_offsetTranslate = CGRectGetMidX(collectionViewBounds) - CGRectGetMidX(selectedFrame);
            CGFloat y_offsetTranslate = CGRectGetMidY(collectionViewBounds) - CGRectGetMidY(selectedFrame);
            CGAffineTransform offsetTranslate = CGAffineTransformMakeTranslation(x_offsetTranslate, y_offsetTranslate);

            // multiply translations first
            CGAffineTransform transform = CGAffineTransformConcat(zoomTranslate, offsetTranslate);
            transform = CGAffineTransformConcat(scaleTransform, transform);

            layoutAttributes.transform = transform;
        }

    }
}

使用此布局代码扩展单元格,将selectedCellFrameselectedIndexPath都设置为要扩展的单元格,并在集合视图上调用performBatchUpdates:completion:。要折叠,请设置selectedCellFrame = CGRectNullselectedIndexPath = nil,并调用performBatchUpdates:completion:

你必须为 iOS7 的较低版本提供支持。 - Alfa

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接