2017-10-14 91 views
1

我在TabBarController的中间创建了一个UIButton,但由于iPhone X底部的安全区域,它无法正确显示在iPhone X上。以编程方式在iPhone X上创建UIButton,但安全区域问题

override func viewDidLayoutSubviews() { 
    super.viewDidLayoutSubviews() 
    //Frame mic button 
    micButton.frame = CGRect.init(x: self.tabBar.center.x - 62, y: self.view.bounds.height - 94, width: 124, height: 124) 
    micButton.layer.cornerRadius = 62   
} 

enter image description here

什么是绘制这个UIButton而不触及安全区的正确方法。

+0

您发布不相关的自动布局什么都嘲弄的代码。 (1)你为什么要设置帧值?这可能是最重要的事情。 (2)安全区域通常 - 甚至可能是绝对 - 意味着限制。他们在哪?通过这个我的意思是要求...(3)iPhone X的“安全区域” - 根据定义,iOS 11 - 意味着“safeAreaLayoutGuide”。那么,为什么你展示的代码不使用这个或任何其他*自动布局约束*? – dfd

+0

@dfd这是真的,但我从来没有做过布局编程,如果你知道一个很好的编程约束指南或教程,将是伟大的。另外,我认为会有不同的视图属性,我不知道从安全区域开始计算视图框架。或者这一切都依赖于约束? –

+0

让我发表一个程序化的答案。它可能不完整甚至毫无价值。但希望它既不会,也会有所帮助。 (如果它缺少一些东西,请发表评论,我会编辑。) – dfd

回答

1

安全区域,特别是safeAreaLayoutGuide涉及约束。

有各种方法来编写自动布局约束(视觉格式布局或VFL,显式 - 罗嗦 - NSLayoutConstraints),但我的首选是使用“布局锚点”。

任何布局的基本思路是位置大小。给一些宽度/高度和x/y轴值,你已经得到了它。非常像框架。

因此奠定了基本的 “锚” 的方式是:

micButton.frame = CGRect.init(x: self.tabBar.center.x - 62, y: self.view.bounds.height - 94, width: 124, height: 124) 

会是这样:

let micButton = UIButton() 
micButton.translatesAutoresizingMaskIntoConstraints = false 

micButton.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: -94).isActive = true 
micButton.widthAnchor.constraint(equalToConstant: 124).isActive = true 
micButton.heightAnchor.constraint(equalToConstant: 124).isActive = true 
micButton.centerXAnchor.constraint(equalTo: view.centerXAnchor, constant: -62).isActive = true 

一些注意事项:

  • 是的,你没有规定一个帧。事实上,你只是在可能的情况下初始化事物。
  • 由于您未使用IB,因此需要将自动调整大小掩码标志设置为false。即使是最有经验的开发人员有时会忘记这件事。 (这样做通常意味着你有“意外”的结果,从看不到东西到错误放置。)
  • 我已经设置了底部或Y轴,宽度和高度,最后是X轴。

虽然它比使用框架更多的代码,但您获得的是跨屏幕尺寸的一致性。

但您想要更多 - 您需要为iPhone X安全区域编码。你有两个工具苹果给你:layoutMarginsGuidesafeAreaLayoutGuide。前者是在iOS 9中引入的(以及更简单的layoutGuide和布局锚点),后者在iOS 11中引入。

[我的假设,可能是安全的,是所有iPhone X设备都可以运行iOS 11或更高版本。由于“安全区”是真的只需要为这个设备,下面是你需要的。]

边距与工作前/后(或水平)边缘的所有设备。它们也适用于顶部/底部(或垂直)边缘。但对于iPhone X,您需要关注不同的顶部/底部,因此是“安全区域”。上述

let layoutGuideTop = UILayoutGuide() 
let layoutGuideBottom = UILayoutGuide() 
view.addLayoutGuide(layoutGuideTop) 
view.addLayoutGuide(layoutGuideBottom) 
let margins = view.layoutMarginsGuide 
view.addLayoutGuide(margins) 
if #available(iOS 11, *) { 
    let guide = view.safeAreaLayoutGuide 
    layoutGuideTop.topAnchor.constraintEqualToSystemSpacingBelow(guide.topAnchor, multiplier: 1.0).isActive = true 
    layoutGuideBottom.bottomAnchor.constraintEqualToSystemSpacingBelow(guide.bottomAnchor, multiplier: 1.0).isActive = true 
} else { 
    layoutGuideTop.topAnchor.constraint(equalTo: topLayoutGuide.bottomAnchor).isActive = true 
    layoutGuideBottom.bottomAnchor.constraint(equalTo: bottomLayoutGuide.topAnchor).isActive = true 
} 

该代码段会产生正确的顶部/底部边缘变量基于IOS版本(layoutGuideToplayoutGuideBottom)。从那里,你可以调整你的下锚:

micButton.bottomAnchor.constraint(equalTo: laytouGuideBottom, constant: -94).isActive = true 

哪些应该设置micButton是94点底部安全区域上方。

这里有几个环节,应该帮助你与布局锚和导游:

Layout Anchors

Layout Guides

Safe Area Layout Guides

编辑:

最后一个关于约束的音符。由于您不依赖帧值,所有这些代码最好放置在viewDidLoad中,因为布局引擎将确定所有内容(并且可能会多次调用viewDidLayoutSubviews)。

0

感谢@dfd指导,这是我作为一个解决方法。我刚刚检查了使用该应用的手机是否具有与iPhoneX相同的屏幕尺寸,并且我只是在约束条件中进行了更改。

override func viewDidLoad() { 
    super.viewDidLoad() 

    //Frame mic button 
    micButton.frame = CGRect.init(x: self.tabBar.center.x - 62, y: self.view.bounds.height - 94, width: 124, height: 124) 
    micButton.layer.cornerRadius = 62 
    micButton.translatesAutoresizingMaskIntoConstraints = false 

    micButton.setBackgroundImage(#imageLiteral(resourceName: "micIcon"), for: .normal) 
    //Add to tabbar view 
    self.view.insertSubview(micButton, aboveSubview: self.tabBar) 


    if UIDevice().userInterfaceIdiom == .phone { 
     if UIScreen.main.nativeBounds.height == 2436 { 
      //iPhoneX Device 
      micButton.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: 0).isActive = true 
      micButton.widthAnchor.constraint(equalToConstant: 124).isActive = true 
      micButton.heightAnchor.constraint(equalToConstant: 124).isActive = true 
      micButton.centerXAnchor.constraint(equalTo: self.tabBar.centerXAnchor, constant: 0).isActive = true 
     } else { 
      //Not an iPhoneX Device 
      micButton.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: 25).isActive = true 
      micButton.widthAnchor.constraint(equalToConstant: 124).isActive = true 
      micButton.heightAnchor.constraint(equalToConstant: 124).isActive = true 
      micButton.centerXAnchor.constraint(equalTo: self.tabBar.centerXAnchor, constant: 0).isActive = true 
     } 

    } 

    // Do any additional setup after loading the view. 
} 
1

试试这个:

添加在UITabViewController的类

micButton.translatesAutoresizingMaskIntoConstraints = false 
view.addSubview(micButton) 
    if #available(iOS 11, *) { 
     let guide = view.safeAreaLayoutGuide 
     micButton.centerXAnchor.constraint(equalTo: guide.centerXAnchor).isActive = true 
     micButton.bottomAnchor.constraint(equalTo: guide.bottomAnchor).isActive = true 
     micButton.heightAnchor.constraint(equalToConstant: 64).isActive = true 
     micButton.widthAnchor.constraint(equalToConstant: 64).isActive = true 

    } else { 
     NSLayoutConstraint(item: micButton, attribute: .centerX, relatedBy: .equal, toItem: view, attribute: .centerX, multiplier: 1.0, constant: 0).isActive = true 
     NSLayoutConstraint(item: micButton, attribute: .bottom, relatedBy: .equal, toItem: view, attribute: .bottom, multiplier: 1, constant: 0).isActive = true 
     micButton.heightAnchor.constraint(equalToConstant: 64).isActive = true 
     micButton.widthAnchor.constraint(equalToConstant: 64).isActive = true 
      }