昨天用户反馈在 iOS 13
的系统下, 我的一个 App 的部分功能不能够正常工作了:
- 页面返回按钮不见了 (自定义的导航栏动画执行结果出错).
- 底部按钮被挤压了 (自定义的 Bar 动画执行结果出错).
自定义导航栏
和 底部按钮的 Bar
就像平时的 电子书/漫画 App 一样, 通过点击屏幕终于进行 显示/隐藏
.
首先, 自定义导航栏 和 底部按钮的Bar 约束如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 自定义导航栏
// 其实就是个 UIView, 通过动画来显示和隐藏
[_navBar mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.right.mas_equalTo(0.0f);
make.top.mas_equalTo(-height);
make.height.mas_equalTo(height);
}];
// 像 TabBar 一样的 UIView 自定义, 也是通过动画来显示和隐藏
[_actionBar mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.right.mas_equalTo(0.0f);
make.top.equalTo(self.view.mas_bottom);
make.height.mas_equalTo(49.0f);
}];
首先, 显示的动画是有问题的, 代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
- (void)showBars {
// 做一些判断, 方式用户连续点击造成动画出错.
if (_barAnimating == YES || _barShown) {
return;
}
_barShown = YES;
_navBar.hidden = NO;
_actionBar.hidden = NO;
_barAnimating = YES;
// nav frame
CGRect navFrame = _navBar.frame;
navFrame.origin.y = 0.0f;
// action bar frame
CGRect actionFrame = _actionBar.frame;
actionFrame.size.height = 49.0f + self.view.safeAreaInsets.bottom;
actionFrame.origin.y = CGRectGetHeight(self.view.bounds) - CGRectGetHeight(actionFrame);
[UIView animateWithDuration:0.3f animations:^{
self.navBar.frame = navFrame;
self.actionBar.frame = actionFrame;
} completion:^(BOOL finished) {
self.barAnimating = NO;
self.barShown = YES;
}];
}
基本就是通过 UIView
动画让 navBar
和 actionBar
滑动出现/消失
.
在 iOS 11
和 iOS 12
上面一切工作正常, 但是在 iOS 13
上面却出现了问题.
通过调试之后发现问题如下:
navBar
根本没出现 (frame 没有发生变化, 动画结果与预期不符).actionBar
只有一部分出现, 还有一部分处于屏幕之外, 因此看起来像是被挤压了一样.
此时猜测是不是 约束
造成的问题. (因为以前写 自定义键盘扩展
时候遇到过类似的情况, 因为约束的原因, 无论如何修改 frame
结果始终与预期不符).
然后我就尝试的使用约束来做动画, 把动画部分的代码修改如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
[UIView animateWithDuration:0.3f animations:^{
// 修改 navBar 顶部约束
[self.navBar mas_updateConstraints:^(MASConstraintMaker *make) {
make.top.mas_equalTo(0);
}];
// 修改 actionBar 底部约束
[self.actionBar mas_updateConstraints:^(MASConstraintMaker *make) {
make.bottom.mas_equalTo(0);
}];
[self.view layoutIfNeeded];
} completion:^(BOOL finished) {
self.barAnimating = NO;
self.barShown = YES;
}];
actionBar
约束改为对 bottom
进行约束, 因为一开始是对 top
进行的约束:
1
2
3
4
5
6
[_actionBar mas_makeConstraints:^(MASConstraintMaker *make) {
// 其他约束
// ...
// 对 bottom 进行约束
make.bottom.mas_equalTo(CGRectGetHeight(_actionBar.bounds));
}];
代码执行的结果是符合预期了, 但是页面内容会 闪烁
. 显然还是不行.
最后尝试对 navBar
和 actionBar
使用 frame
来进行定位:
1
2
3
4
5
CGFloat height = CGRectGetMaxY(self.navigationController.navigationBar.frame);
// navBar
_navBar.frame = CGRectMake(0, -height, CGRectGetWidth(self.view.bounds), height);
// actionBar
_actionBar.frame = CGRectMake(0, CGRectGetHeight(self.view.bounds), CGRectGetWidth(self.view.bounds), 49);
UIView
动画部分还原成最早修改 frame
的方法.
执行结果达到预期, 页面也不闪烁了.
至此问题就算是解决了.
造成这个问题的原因应该是 iOS 13
更新之 对自动布局
应该有一些变化吧(暂时未深究其原因), 后面再做项目得注意这一点.