以编程方式在iPhone X上创建UIButton但安全区域问题

时间:2017-10-14 00:17:19

标签: swift uibutton ios11 cgrect iphone-x

我在UIButton的中间创建了一个TabBarController,但由于手机底部的安全区域,它在iPhone X上显示不正确。

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的正确方法是什么。

4 个答案:

答案 0 :(得分:1)

安全区域,特别是safeAreaLayoutGuide,与约束有关。

有各种方法来编码自动布局约束(Visual Format Layout或VFL,explicit - and wordy - NSLayoutConstraints),但我更喜欢使用“layout anchors”。

任何布局的基本思路是位置尺寸。给出宽度/高度和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,因此需要将auto resize mask标志设置为false。即便是最有经验的开发人员有时会忘记这一点。 (这样做通常意味着你有“意想不到的”结果,从看不到东西到看错了。)
  • 我设置了底部或Y轴,宽度和高度,最后是X轴。

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

但是你需要更多 - 你需要为iPhone X安全区域编码。 Apple有两个工具: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)。

答案 1 :(得分: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
            }

答案 2 :(得分: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.
}

答案 3 :(得分:0)

此代码可帮助您解决问题。

micButton.bottomAnchor.constraint(equalTo:view.safeAreaLayoutGuide.bottomAnchor).isActive = true