iOS 11 安全区域 vs. UIView 动画

标签 ios autolayout uikit ios11 iphone-x

请考虑以下几点:我制作了一个可重用的 UIView 子类,它有一个背景,一些内容布置在它的 subview 中。作为负责任的开发人员,我已经根据其安全区域对齐 View 的 subview ,以便它会在必要时自动插入其内容(例如在 iPhone X 上):

center vs bottom

太棒了!内部 View 在安全区域内时从边到边移动,当它悬在安全区域外时从底部插入其内容。

现在假设最初 View 应该在屏幕外,但是当用户点击我的应用程序中的某处时,我希望我的 View 以动画方式显示在屏幕中央,并且它应该在第二次点击时以动画方式退出。让我们像这样实现它:

@implementation ViewController {
    UIView* _view;
}

- (void)viewDidLoad {
    [super viewDidLoad];
    [self.view addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(animate:)]];
}

- (void)animate:(UITapGestureRecognizer*)sender {
    if (_view == nil) {
        _view = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 100, 100)];
        _view.backgroundColor = UIColor.redColor;

        UIView* innerView = [[UIView alloc] initWithFrame:CGRectMake(5, 5, 90, 90)];
        innerView.translatesAutoresizingMaskIntoConstraints = NO;
        innerView.backgroundColor = UIColor.blueColor;

        [_view addSubview:innerView];
        [_view addConstraints:@[[_view.safeAreaLayoutGuide.topAnchor constraintEqualToAnchor:innerView.topAnchor constant:-5],
                                [_view.safeAreaLayoutGuide.rightAnchor constraintEqualToAnchor:innerView.rightAnchor constant:5],
                                [_view.safeAreaLayoutGuide.bottomAnchor constraintEqualToAnchor:innerView.bottomAnchor constant:5],
                                [_view.safeAreaLayoutGuide.leftAnchor constraintEqualToAnchor:innerView.leftAnchor constant:-5]]];

        _view.center = CGPointMake(self.view.bounds.size.width / 2,
                                   self.view.bounds.size.height + _view.bounds.size.height / 2);
        [self.view addSubview:_view];
        [UIView animateWithDuration:1 animations:^{
            _view.center = CGPointMake(self.view.bounds.size.width / 2,
                                       self.view.bounds.size.height / 2);
        }];
    } else {
        [UIView animateWithDuration:1 animations:^{
            _view.center = CGPointMake(self.view.bounds.size.width / 2,
                                       self.view.bounds.size.height + _view.bounds.size.height / 2);
        } completion:^(BOOL finished) {
            [_view removeFromSuperview];
            _view = nil;
        }];
    }
}

@end

所以,现在如果我们启动应用程序并点击屏幕,就会发生这种情况:

animate in

到目前为止一切顺利。但是,当我们再次点击它时会发生这种情况:

animate out

如您所见,即使 View 完全超出父 View 的边界,安全区域插图仍然设置为就好像它位于其父 View 的底部一样。

我们可以通过在 View 动画出来的动画 block 中调用[self.view layoutIfNeeded] 来使效果不那么突兀,但这并不能消除问题——底部空间会只是以动画的方式增长而不是突然扩张:

better, but still bad

这对我来说仍然不能接受。我希望它滑出时与滑入时完全一样,四面都有 5pt 填充。

有没有办法在不向我的 View 添加 shouldAlignContentToSafeAreashouldAlignContentToBounds 等标志的情况下实现这一目标?

我只是想让它自动工作,但正确地工作...

最佳答案

太简单的解决方案。试试看(将内部 View 的中心设置为动画 View 中心 - innerView.center = animatingView.center;)

@interface ViewController () {

     UIView* animatingView;
}

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
    [self setupAnimate];
}

- (void)setupAnimate {

    [self.view addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(animate:)]];
}

- (void)animate:(UITapGestureRecognizer*)sender {
    if (animatingView == nil) {
        animatingView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 100, 100)];
        animatingView.backgroundColor = UIColor.redColor;

        UIView* innerView = [[UIView alloc] initWithFrame:CGRectMake(5, 5, 90, 90)];
        innerView.translatesAutoresizingMaskIntoConstraints = NO;
        innerView.backgroundColor = UIColor.blueColor;

        [animatingView addSubview:innerView];
        innerView.center = animatingView.center;

        animatingView.center = CGPointMake(self.view.bounds.size.width / 2,
                                   self.view.bounds.size.height + animatingView.bounds.size.height / 2);
        [self.view addSubview:animatingView];
        [UIView animateWithDuration:1 animations:^{
            animatingView.center = CGPointMake(self.view.bounds.size.width / 2,
                                       self.view.bounds.size.height / 2);
        }];
    } else {
        [UIView animateWithDuration:1 animations:^{
            animatingView.center = CGPointMake(self.view.bounds.size.width / 2,
                                       self.view.bounds.size.height + animatingView.bounds.size.height / 2);
        } completion:^(BOOL finished) {
            [animatingView removeFromSuperview];
            animatingView = nil;
        }];
    }
}

结果如下:

enter image description here

关于iOS 11 安全区域 vs. UIView 动画,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46670921/

相关文章:

objective-c - 什么可以阻止在动画期间遵守自动布局约束?

ios - View Controller 出现后 UINavigationBarAppearance 更新

ios - 如何让我的 UIButton 标题有一些填充?

ios - 在 Xcode 6 中创建通用库

ios - 将选择器传递给扩展

ios - NSKeyedUnarchiver。从 plist 加载自定义对象数组

ios - 表头 View 自动布局问题

ios - 在 UICollectionView 的底部加载额外的单元格

ios - Swift tableviewcell 边界未正确绑定(bind)/固定?

iphone - 为什么我不能向 UITableViewCell 的 contentView 添加 mask ?