【问题标题】:iOS 11 safe areas vs. UIView animationiOS 11 安全区域与 UIView 动画
【发布时间】:2018-03-22 02:35:05
【问题描述】:

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

太棒了!当内部视图在安全区域内时,它是边到边的,当它挂出安全区域时,它会从底部插入其内容。

现在假设最初视图应该在屏幕外,但是当用户点击我的应用程序中的某个位置时,我希望我的视图动画到屏幕中心,并且它应该在第二次点击时动画出来。让我们像这样实现它:

@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

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

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

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

我们可以通过在视图被动画化的动画块中调用[self.view layoutIfNeeded]来减少效果的突然性,但这并不能消除问题——底部空间只会以动画方式增长而不是突然扩大:

这对我来说仍然是不可接受的。我希望它像滑入一样滑出,四面都有 5pt 填充。

有没有办法在不向我的视图中添加 shouldAlignContentToSafeAreashouldAlignContentToBounds 之类的标志的情况下实现这一目标?

我只想让它自动工作,但正常工作...

【问题讨论】:

  • 100% 同意这是意外行为,并且似乎与 safeAreaLayoutGuide 的文档相矛盾,即“如果视图当前未安装在视图层次结构中,或者尚未在屏幕上可见,则布局指南边缘是等于视图的边缘。”使用您的示例,并且简单地将 _view 放置在视图边界之外且没有动画,我可以看到 safeAreaLayoutGuide 的底部指南仍然是 34。

标签: ios autolayout uikit ios11 iphone-x


【解决方案1】:

解决方案太简单了。试试这个看看(设置内部视图的中心等于动画视图中心 - 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;
        }];
    }
}

结果如下:

【讨论】:

  • 当视图位于屏幕底部时,这不会尊重安全区域。也许我不清楚,但我想总体上尊重安全区域插图。但是,如果我在屏幕外对视图进行动画处理,我不希望安全区域插图影响我的内容,除非动画以与安全区域插图重叠的视图结束。在我的示例中,视图的动画超出了父边界,因此不应应用安全区域插图...
猜你喜欢
  • 2018-03-02
  • 2018-01-06
  • 1970-01-01
  • 1970-01-01
  • 2018-06-26
  • 2018-03-03
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多