【问题标题】:Need to size StackView proportionately to my device size需要根据我的设备大小按比例调整 StackView 的大小
【发布时间】:2018-02-11 17:42:22
【问题描述】:

我正在用代码构建我的屏幕,其中包含一个包含我的文本字段的 stackView。这个 stackView 在 iPhone 8/8Plus/X 设备上看起来很棒,但在 SE 屏幕上太大了。我意识到我需要根据设备大小按比例调整 stackView 的大小,但不确定如何以编程方式进行。我看过的所有教程都展示了如何在 IB 中进行操作。

这是我正在使用的代码:

        let textFieldStackView = UIStackView(arrangedSubviews: [nameTextField, emailTextField, passwordTextField])
        textFieldStackView.translatesAutoresizingMaskIntoConstraints = false
        textFieldStackView.distribution = .fillEqually
        textFieldStackView.axis = .vertical
        textFieldStackView.spacing = 10

        view.addSubview(textFieldStackView)

        textFieldStackView.topAnchor.constraint(equalTo: logoImageView.bottomAnchor, constant: 100).isActive = true
        textFieldStackView.heightAnchor.constraint(equalToConstant: 150).isActive = true
        textFieldStackView.widthAnchor.constraint(equalToConstant: 350).isActive = true
        textFieldStackView.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true

这不仅仅是宽度,还有我需要相应增长的高度。我将如何在代码中执行此操作?

【问题讨论】:

  • 按比例调整大小是什么意思?你能描述一下吗?
  • @MilanNosáľ 我希望高度和宽度增加相同的数量,具体取决于它们所在的屏幕尺寸。
  • 你太模糊了..你希望它是屏幕高度的 1/2 吗?你想让它填满屏幕的其余部分吗?
  • 如果您希望堆栈视图的大小与主视图的大小相关,为什么要使用equalToConstant 来约束?鉴于您声称要做什么,您的代码毫无意义。
  • @matt 这就是我问一个问题的原因。正如我所指出的,我不确定如何做到这一点,因为展示如何做到这一点的教程使用的是 IB,而不是代码。

标签: ios autolayout uistackview


【解决方案1】:

如果您需要将视图剪辑到屏幕的边缘,您应该使用 safeArea 作为顶部/底部约束,并使用前导和尾随边距作为前导和尾随约束。这样,您的视图将在您需要的任何设备上看起来都很棒。
例如:

yourView.topAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.topAnchor).isActive = true
yourView.bottomAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.bottomAnchor).isActive = true
yourView.leadingAnchor.constraint(equalTo: self.view.layoutMarginsGuide.leadingAnchor).isActive = true
yourView.trailingAnchor.constraint(equalTo: self.view.layoutMarginsGuide.trailingAnchor).isActive = true

这是 ios 11 代码。为了支持 iOS 10 布局,控制器的顶部和底部锚点使用 self.topLayoutGuide.bottomAnchor 和 self.bottomLayoutGuide.topAnchor。
在自动布局中使用自动布局是非常正确的,而不是顶评论中的 UISCreenSizes。 https://useyourloaf.com/blog/safe-area-layout-guide/ 学习本指南,帮助不大。

编辑:
如果您想将视图置于中心并根据屏幕尺寸更改其大小,并且同时具有相等的间距前导和尾随,我看到的最佳方法是在视图的左侧和右侧使用支持视图,它们将具有相同的宽度.调整中心(您的)视图的压缩阻力,您将使其变得更薄或更宽。
像这样的:

EDIT2:
根据您的评论和代码:

yourView.centerXAnchor.constraint(equalTo: self.view.centerXAnchor).isActive = true
yourView.centerYAnchor.constraint(equalTo: self.view.centerYAnchor).isActive = true
yourView.leadingAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.leadingAnchor, constant: 10).isActive = true
yourView.trailingAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.trailingAnchor, constant: 10).isActive = true
yourView.bottomAnchor.constraintGreaterThanOrEqualToSystemSpacingBelow(self.view.safeAreaLayoutGuide.bottomAnchor, multiplier: 1.0).isActive = true
yourView.topAnchor.constraintGreaterThanOrEqualToSystemSpacingBelow(self.view.safeAreaLayoutGuide.topAnchor, multiplier: 1.0).isActive = true
yourView.setContentCompressionResistancePriority(.defaultLow, for: .horizontal)
yourView.setContentCompressionResistancePriority(.defaultLow, for: .vertical)

【讨论】:

  • 如果我使用中心约束,我将如何为我的视图应用 safeArea?
  • 安全区域对于顶部/底部约束很有用。如果您想将视图连接到主视图的中心,则必须使用它的中心约束。 yourView.centerXAnchor.constraint(equalTo: self.view.centerXAnchor).isActive = true
  • 好的,我明白了。我推荐的不是你想要的。您需要在屏幕中心有视图,它会根据屏幕的宽度自行调整大小?放置在中心并具有相同的前导和尾随间距?
  • 关闭,我希望它根据屏幕宽度和高度调整自身大小,并放置在中心,并带有前导和尾随空格。
【解决方案2】:

您可以将值从一个设备屏幕(下例中为 6S)缩放到另一个屏幕。

func ScaleWidth(CGFloat value) -> CGFloat {
    return round(value * (UIScreen.main.bounds.size.width / CGFloat(375.0)));
}

func ScaleHeight(CGFloat value) -> CGFloat {
    return round(value * (UIScreen.main.bounds.size.height / CGFloat(667.0)));
}



textFieldStackView.topAnchor.constraint(equalTo: logoImageView.bottomAnchor, constant: ScaleHeight(100.0)).isActive = true
textFieldStackView.heightAnchor.constraint(equalToConstant: ScaleHeight(150.0)).isActive = true
textFieldStackView.widthAnchor.constraint(equalToConstant: ScaleWidth(350.0)).isActive = true
textFieldStackView.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true

另一种选择是使用约束乘数:

func AspectWidth() -> CGFloat {
    return round(UIScreen.main.bounds.size.width / CGFloat(375.0));
}

func AspectHeight() -> CGFloat {
    return round(UIScreen.main.bounds.size.height / CGFloat(667.0));
}



textFieldStackView.topAnchor.constraint(equalTo: logoImageView.bottomAnchor, constant: 100.0, multiplier: AspectHeight()).isActive = true
textFieldStackView.heightAnchor.constraint(equalToConstant: 150.0, multiplier: AspectHeight()).isActive = true
textFieldStackView.widthAnchor.constraint(equalToConstant: 350.0, multiplier: AspectWidth()).isActive = true
textFieldStackView.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true

【讨论】:

    【解决方案3】:

    最简单的解决方案(但不是最漂亮的解决方案)是使用UIScreen.main.frame 来计算约束的常数。 UIScreen.main.frame 代表整个屏幕的边框,每个设备都不同(iPhone SE 为 320x568,iPhone 8 为 375x667)。

    如果您希望堆栈视图在每个设备上看起来都一样,您的代码可能如下所示:

        let textFieldStackView = UIStackView(arrangedSubviews: [nameTextField, emailTextField, passwordTextField])
        textFieldStackView.translatesAutoresizingMaskIntoConstraints = false
        textFieldStackView.distribution = .fillEqually
        textFieldStackView.axis = .vertical
        textFieldStackView.spacing = UIScreen.main.frame.height / 66.7 // will be 10 on iPhone 8
    
        view.addSubview(textFieldStackView)
    
        textFieldStackView.topAnchor.constraint(equalTo: logoImageView.bottomAnchor, constant: UIScreen.main.frame.height / 6.67).isActive = true
        textFieldStackView.heightAnchor.constraint(equalToConstant: UIScreen.main.frame.height / 4.45).isActive = true
        textFieldStackView.widthAnchor.constraint(equalToConstant: UIScreen.main.frame.width / 1.07).isActive = true
        textFieldStackView.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
    

    【讨论】:

      【解决方案4】:

      我无法评论 kiwisip 的答案,所以我必须在这里写 - 使用 UIScreen.main.frame 不是一个好的解决方案,最好依赖于视图的大小,在其中您将堆栈视图添加为子视图。在您的示例中,您必须将 widthAnchor 约束替换为以下内容:

      textFieldStackView.widthAnchor.constraint(equalTo: view.widthAnchor, constant: 0).isActive = true
      

      另一方面 - 使用超级视图大小除以常量而不是仅使用常量值可能是个好主意,但这取决于您的布局。

      【讨论】:

      • 它可能是也可能不是。视情况而定。我认为使用UIScreen.main.frame 更通用,更适合这个问题。
      猜你喜欢
      • 2015-06-20
      • 2011-12-29
      • 2012-01-28
      • 2019-08-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多