3

起初我认为这不会太难,但结果比我想象的要多一些。

iOS文件夹打开

目前我的代码基于此:https ://github.com/jwilling/JWFolders 。但是,它不是很干净,最大的问题是每次打开文件夹时都会截取屏幕截图(renderInContext: 对 CPU 的负担很大,因此 fps 非常低)。除此之外,这个实现看起来不像 Apple 动画那样干净和优美。

Apple 设法实现了不滞后的像素完美动画。我也想做同样的事!最好的方法是什么/你会怎么做 - 一个干净编码、好看和流畅的动画?目前,我的动画在所有这些方面都缺乏,我对如何才能做得更好(就像 Apple 所做的那样)感到困惑。

-

我不是在乞求代码,只是最好的方法/方法。但是,如果您想继续编写代码,那么我无法拒绝(那绝对值得)!

4

1 回答 1

3

我会将 Springboard 分成几个视图,其中每个视图都是一行图标。
如果单击文件夹图标,我会为所有以下视图设置动画以向下和向上移动以放置文件夹内容。同时,我会添加一个表示文件夹内容的子视图,并在必要时以与其大小和位置相同的速度进行动画处理。

为了支持跨越整个屏幕的背景图像,我会将其切割成碎片并将这些碎片作为背景图像视图添加到每一行的视图中。


我写了一个快速而肮脏的示例代码,动画从任何点击位置开始,也可以在 github 上作为完整项目提供

截屏

@interface ViewController ()

@property (nonatomic, strong) UIView *upperView;
@property (nonatomic, strong) UIView *lowerView;

@property (nonatomic, strong) UIImageView *upperImageView;
@property (nonatomic, strong) UIImageView *lowerImageView;

@property (nonatomic, strong) UIView *folderContentsView;

@property (nonatomic, assign) CGRect startRect;
@end

@implementation ViewController

- (void)viewDidLoad
{
    [super viewDidLoad];

    UIImage *bgImg = [UIImage imageNamed:@"bg.png"];
    self.upperImageView = [[UIImageView alloc] initWithImage:bgImg];
    self.lowerImageView = [[UIImageView alloc] initWithImage:bgImg];
    [self.upperImageView setContentMode:UIViewContentModeTop];
    [self.lowerImageView setContentMode:UIViewContentModeTop];

    self.upperView = [[UIView alloc] initWithFrame:self.upperImageView.frame];
    self.lowerView = [[UIView alloc] initWithFrame:self.lowerImageView.frame];
    [self.upperView addSubview:_upperImageView];
    [self.lowerView addSubview:_lowerImageView];

    [self.view addSubview:_lowerView];
    [self.view addSubview:_upperView];

    UITapGestureRecognizer *upperTapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self
                                                                                         action:@selector(openOverlay:)];
    UITapGestureRecognizer *lowerTapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self
                                                                                         action:@selector(openOverlay:)];

    [self.upperView setUserInteractionEnabled:YES];
    [self.upperView addGestureRecognizer:upperTapRecognizer];
    [self.upperView setClipsToBounds:YES];

    [self.lowerView setUserInteractionEnabled:YES];
    [self.lowerView addGestureRecognizer:lowerTapRecognizer];
    [self.lowerView setClipsToBounds:YES];

    self.folderContentsView = [[UIView alloc] initWithFrame:CGRectZero];
    self.folderContentsView.backgroundColor = [UIColor redColor];
    UITapGestureRecognizer *closeTapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self
                                                                                         action:@selector(closeOverlay:)];
    [self.folderContentsView addGestureRecognizer:closeTapRecognizer];
    [self.view addSubview:self.folderContentsView];

    [self.folderContentsView addSubview:[[UIImageView alloc] initWithImage:[UIImage imageNamed:@"bgFolder.png"]]];
    [self.folderContentsView setClipsToBounds:YES];

    self.startRect = [self.upperView frame];
}

- (void)didReceiveMemoryWarning
{
    [super didReceiveMemoryWarning];
}

-(void)openOverlay:(UITapGestureRecognizer *) sender
{
    [self.upperView setUserInteractionEnabled:NO];
    [self.lowerView setUserInteractionEnabled:NO];
    CGPoint location = [sender locationInView:sender.view];

    self.folderContentsView.frame = CGRectMake(0, location.y,
                                    _lowerView.frame.size.width, 0);
    self.lowerView.frame = CGRectMake(0, location.y,
                                      _lowerView.frame.size.width, _lowerView.frame.size.height);
    self.upperView.frame = CGRectMake(0, 0,
                                      _upperView.frame.size.width, location.y);
    self.lowerImageView.frame = CGRectMake(_lowerImageView.frame.origin.x, -location.y,
                                           _lowerImageView.frame.size.width, _lowerImageView.frame.size.height);

    [UIView animateWithDuration:.5 animations:^{
        self.folderContentsView.frame = CGRectMake(0, location.y,
                                    _lowerView.frame.size.width, 200);
        self.lowerView.frame = CGRectOffset(_lowerView.frame, 0, 200);
    }];    
}

-(void) closeOverlay:(UITapGestureRecognizer*) sender
{
    [UIView animateWithDuration:.5 animations:^{
        self.lowerView.frame = CGRectOffset(_lowerView.frame, 0, -200);
        self.folderContentsView.frame = CGRectMake(0, self.folderContentsView.frame.origin.y,
                                        self.folderContentsView.frame.size.width, 0);
    } completion:^(BOOL finished) {
        [self.upperView setUserInteractionEnabled:YES];
        [self.lowerView setUserInteractionEnabled:YES];
        self.upperView.frame = self.startRect;
    }];
}


@end

两个视图在图层中配备了相同的背景。如果检测到点击,则调整两个视图的大小,以便上视图在点击的 y 坐标处结束,而下视图从那里开始。添加到 lowerView 的 UIImageView 向相反方向移动,以便图像保持在原位。

现在 lowerView 向下滑动,同时添加 contentView 并以相同的速度调整大小。

如您所见,不需要图像渲染或其他艰难的操作。只是 UIView 动画。

在此处输入图像描述

于 2012-12-30T13:45:49.203 回答