使UI适应iPhone X时从设备模型中抽象出来
仅使用“自动布局”使按钮具有自定义外观
我们的设计师最近要求在屏幕底部制作一个如下所示的按钮:
在这篇文章中,我将展示如何在不依赖设备模型查找的情况下实现这种自适应UI。
心态
每年,当新设备问世时,人们一直在问如何以编程方式检测模型的问题(2017年也不例外)。
尽管可以这样做,但该API有点奇怪。 这是因为Apple努力教会我们不要这样做。 取而代之的是,他们要求开发人员在进行功能测试时依赖可用性测试,并依靠自动布局来制作自定义界面。 换句话说,抽象远离特定的设备模型。 好吧,在一个可能可行的理想世界中……从这个角度看事物有时确实会有所帮助。
安全区
我要做的第一件事是更改按钮的约束,以遵守主视图控制器视图的安全区域。
这立即解决了我们在iPhone X Simulator和Xcode 9中首次启动该应用程序时遇到的问题。
NSLayoutConstraint * buttonBottomConstraint = nil;
如果(@available(iOS 11,*)){
buttonBottomConstraint = [self.button.bottomAnchor约束EqualToAnchor:self.view.safeAreaLayoutGuide.bottomAnchor];
}
其他{
buttonBottomConstraint = [self.button.bottomAnchor约束EqualToAnchor:self.bottomLayoutGuide.topAnchor];
}
注意:如果您想知道
bottomLayoutGuide.topAnchor
,这是因为bottomLayoutGuide
具有id
类型。 没有帮助吗? 好吧,这超出了这个故事的范围。 对不起that
然后,我决定重做按钮的所有约束,以坚持安全区域:
NSLayoutConstraint * buttonBottomConstraint = nil;
NSLayoutConstraint * buttonLeadingConstraint = nil;
NSLayoutConstraint * buttonTrailingConstraint = nil;
如果(@available(iOS 11,*)){
buttonBottomConstraint = [self.button.bottomAnchor约束EqualToAnchor:self.view.safeAreaLayoutGuide.bottomAnchor];
buttonLeadingConstraint = [self.button。LeadingAnchor约束EqualToAnchor:self.view.safeAreaLayoutGuide.leadingAnchor];
buttonTrailingConstraint = [self.button.trailingAnchor约束EqualToAnchor:self.view.safeAreaLayoutGuide.trailingAnchor];
}
其他{
buttonBottomConstraint = [self.button.bottomAnchor约束EqualToAnchor:self.bottomLayoutGuide.topAnchor];
buttonLeadingConstraint = [self.button。LeadingAnchor约束EqualToAnchor:self.view。Leading Anchor];
buttonTrailingConstraint = [self.button.trailingAnchor约束条件EqualToAnchor:self.view.trailingAnchor];
}
buttonHeightConstraint = [NSLayoutConstraintconstraintWithItem:self.button属性:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual等于Item:nil属性:NSLayoutAttributeNotAnAttribute乘数:1.f常数:50.f];
//我们稍后将需要引用这些约束
self.buttonConstraints = @ [buttonBottomConstraint,buttonLeadingConstraint,buttonTrailingConstraint,buttonHeightConstraint];
这些约束仅在loadView
例程期间创建一次,并添加到self.view
。
保证金和圆角
如果您仔细考虑一下, 真正使按钮看起来与众不同的是它与屏幕底部的距离,而不是设备型号:当按钮的底部边缘和屏幕之间没有空间时,可以它没有边距和圆角。
为了找出距离,我利用self.view.safeAreaInsets.bottom
值
-(void)adjustButtonAppearanceIfNeeded {
//如果按钮不是非常[visual]
//超级视图的底部(提示:iPhone X)
//然后将圆角
如果(@available(iOS 11,*)){
CGFloat bottomPadding = self.view.safeAreaInsets.bottom;
如果(bottomPadding> 0){
如果(self.button.layer.cornerRadius!= 10.f){
self.button.layer.cornerRadius = 10.f;
self.button.layer.masksToBounds = YES;
self.buttonConstraints [1] .constant = 8; // 领导
self.buttonConstraints [2] .constant = -8; //尾随
[self.button setNeedsDisplay];
[self.view setNeedsLayout];
}
}
其他{
如果(self.button.layer.cornerRadius!= 0.f){
self.button.layer.cornerRadius = 0.f;
self.button.layer.masksToBounds = NO;
self.buttonConstraints [1] .constant = 0; // 领导
self.buttonConstraints [2] .constant = 0; //尾随
[self.button setNeedsDisplay];
[self.view setNeedsLayout];
}
}
}
}
为确保bottomPadding
值正确,应从viewDidLayoutSubviews
调用此方法:
-(void)viewDidLayoutSubviews {
[super viewDidLayoutSubviews];
[self AdjustButtonAppearanceIfNeeded];
}
注意,条件将cornerRadius
值与10.f
或0.f
进行比较。 这是为了防止在[self.view setNeedsLayout]
之后出现无限的布局循环。
结论
安全区域的概念比布局指南要干净得多。