指定NSLayoutConstraint的UILayoutPriority好像没有生效
Posted
技术标签:
【中文标题】指定NSLayoutConstraint的UILayoutPriority好像没有生效【英文标题】:Specifying UILayoutPriority of NSLayoutConstraint doesn't seem to take effect 【发布时间】:2019-07-10 20:48:45 【问题描述】:我在 UIScrollView 中有一个表格和一个按钮,我想要以下设计:
按钮至少在表格最后一行下方 40 pts 按钮总是在视图末端上方 83 pts通过以下限制,我设法使按钮始终在表格最后一行下方 40 pts,并且仅当表格足够长时才在视图末尾上方 83 pts。在我看来,bottomConstraint
的优先级没有正确覆盖topConstraint
的约束。我已将滚动视图设置为包含整个屏幕。
/* - Sign Out button is 40 pts tall - */
let heightConstraint = NSLayoutConstraint(item: signOutBtn, attribute: .height, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute, multiplier: 1, constant: 41)
/* - Sign Out button is ALWAYS 83 pts above bottom of screen, when visible - */
let bottomConstraint = NSLayoutConstraint(item: signOutBtn, attribute: .bottom, relatedBy: .equal, toItem: scrollView, attribute: .bottom, multiplier: 1, constant: -83)
bottomConstraint.priority = UILayoutPriority.required
/* - Sign Out button is AT LEAST 40 pts below last row of table - */
let topConstraint = NSLayoutConstraint(item: signOutBtn, attribute: .top, relatedBy: .greaterThanOrEqual, toItem: tableView, attribute: .bottom, multiplier: 1, constant: 40)
topConstraint.priority = UILayoutPriority.defaultLow
/* - Sign Out button stretches across the screen - */
let leadingConstraint = NSLayoutConstraint(item: signOutBtn, attribute: .leading, relatedBy: .equal, toItem: scrollView, attribute: .leading, multiplier: 1, constant: 0)
let trailingConstraint = NSLayoutConstraint(item: signOutBtn, attribute: .trailing, relatedBy: .equal, toItem: scrollView, attribute: .trailing, multiplier: 1, constant: 0)
scrollView.addConstraints([heightConstraint, bottomConstraint, leadingConstraint, trailingConstraint, topConstraint])
截图: (糟糕——这就是我现在所完成的)
(好)
如果表格太长,退出按钮不会出现,用户需要向下滚动到它。
【问题讨论】:
这和你之前的问题一样吗? ***.com/questions/56972736/… @DonMag 我提出了一个新问题,因为这让我感到困惑,为什么我添加的约束优先级似乎没有任何效果,而之前的问题是问我应该采取什么方法来实现这种效果. 这仍然令人困惑...根据您的图像,您希望在表格最后一行下方 40 点处有一个按钮。那么视图底部上方的 83 点是什么?或者,当表格很短时,您是否希望按钮位于视图底部上方 83 分(因此底行和按钮之间的间隙可能为 300 分),直到 tableView 增长到“将其推离屏幕”? @DonMag 我明白你的困惑。我已经更新了这个问题,我希望它能解决问题......第一个屏幕截图是我使用已有的约束看到的。剩下的就是我想看到的了。所以我想要一个总是在视图底部上方 83 pts 的按钮,并且随着 tableView 的增长,按钮被按下,在它和表格的最后一行之间保持 40 pts 的间距。 我在对您之前的问题的评论中发布了一个链接,该链接正是您正在尝试做的事情:“这是一种方法:***.com/a/56134043/6257435 .. . 在该示例中,只需将“页脚视图”(这是一个普通的 UIView)替换为您的按钮。” 【参考方案1】:我创建了以下视图控制器,应该可以解决您的问题 - 我不得不承认我不知道您为什么在布局中使用 scrollView,但我希望我设法重新创建了您的设置。
为了模拟不同的桌子高度,我使用了tableView.heightAnchor.constraint(equalToConstant: 300)
。
Anchors 用于创建约束。
import UIKit
class ViewController: UIViewController
let scrollView = UIScrollView()
let tableView = UITableView()
let signOutBtn = UIButton()
override func viewDidLoad()
super.viewDidLoad()
view.addSubview(scrollView)
scrollView.addSubview(tableView)
scrollView.addSubview(signOutBtn)
tableView.dataSource = self
signOutBtn.setTitle("BUTTON", for: .normal)
signOutBtn.setTitleColor(.blue, for: .normal)
//ScrollView constraints
scrollView.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
scrollView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor),
scrollView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor),
scrollView.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor),
scrollView.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor)
])
//TableView constraints
tableView.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
tableView.topAnchor.constraint(equalTo: scrollView.safeAreaLayoutGuide.topAnchor),
tableView.bottomAnchor.constraint(lessThanOrEqualTo: signOutBtn.topAnchor, constant: -40),
tableView.heightAnchor.constraint(equalToConstant: 300),
tableView.trailingAnchor.constraint(equalTo: scrollView.safeAreaLayoutGuide.trailingAnchor),
tableView.leadingAnchor.constraint(equalTo: scrollView.safeAreaLayoutGuide.leadingAnchor)
])
//SignOutButton constraints
signOutBtn.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
signOutBtn.heightAnchor.constraint(equalToConstant: 41),
signOutBtn.bottomAnchor.constraint(equalTo: scrollView.safeAreaLayoutGuide.bottomAnchor, constant: -83),
signOutBtn.centerXAnchor.constraint(equalTo: view.centerXAnchor)
])
extension ViewController: UITableViewDataSource
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int
return 30
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
let cell = UITableViewCell(style: .default, reuseIdentifier: "")
cell.textLabel?.text = "\(indexPath.row)"
return cell
我还附加了带有结果的屏幕:
Image with table with elements fitting view
Image with table with elements not fitting view
【讨论】:
谢谢。我觉得你可能误解了这个问题,这是我的错,因为我意识到我没有在问题描述中提供足够的细节。我附上了一张新图片,可以说明为什么我需要滚动视图。您在此处的解决方案会将按钮永久固定在一个位置。【参考方案2】:回答您关于约束优先级的具体问题...
您对滚动视图如何使用约束感到困惑。
在此图像中,标签被限制在滚动视图的顶部,按钮被限制在距离优先级为 250 的标签的 40 点和距离优先级为 1000 的滚动视图底部的 83 点。
底部约束决定了滚动视图内容的.contentSize
高度 - 或“可滚动区域”:
【讨论】:
以上是关于指定NSLayoutConstraint的UILayoutPriority好像没有生效的主要内容,如果未能解决你的问题,请参考以下文章