1. ホーム
  2. ios

[解決済み] プログラムによるCenterX/CenterY制約の追加

2023-03-03 07:58:34

質問

UITableViewControllerを使用していますが、表示するものがない場合、セクションを表示しません。このコードで表示するものがないことをユーザーに示すためのラベルを追加しています。

label = UILabel(frame: CGRectMake(20, 20, 250, 100))
label.text = "Nothing to show"
self.tableView.addSubview(label)

しかし今度は、水平方向と垂直方向の中央揃えにしたいのです。通常、私はスクリーンショットで強調表示されている 2 つのオプション (高さと幅のオプション) を選択します。

以下のコードで制約を追加してみましたが、アプリがエラーでクラッシュしてしまいます。

label = UILabel(frame: CGRectMake(20, 20, 250, 100))
label.text = "Nothing to show"

let xConstraint = NSLayoutConstraint(item: label, attribute: .CenterX, relatedBy: .Equal, toItem: self.tableView, attribute: .CenterX, multiplier: 1, constant: 0)
let yConstraint = NSLayoutConstraint(item: label, attribute: .CenterY, relatedBy: .Equal, toItem: self.tableView, attribute: .CenterY, multiplier: 1, constant: 0)

label.addConstraint(xConstraint)
label.addConstraint(yConstraint)

のエラーが発生しました。

When added to a view, the constraint's items must be descendants of that view (or the view itself). This will crash if the constraint needs to be resolved before the view hierarchy is assembled. Break on -[UIView _viewHierarchyUnpreparedForConstraint:] to debug.
2014-12-23 08:17:36.755 [982:227877] *** Assertion failure in -[UILabel _layoutEngine_didAddLayoutConstraint:roundingAdjustment:mutuallyExclusiveConstraints:], /SourceCache/UIKit/UIKit-3318.16.21/NSLayoutConstraint_UIKitAdditions.m:560

デバイスの回転に対応しているため、ラベルは常に水平方向と垂直方向の中央に表示される必要があります。

何が間違っているのでしょうか。どうすればこれらの制約をうまく追加できますか。

ありがとうございます。

どのように解決するのですか?

Swift 3/Swift 4に対応したアップデートが必要です。

iOS 8 では、制約を有効にするには、制約の isActive プロパティを true . これにより、制約が適切なビューに追加されるようになります。 複数の制約を一度にアクティブにするには、制約を含む配列を NSLayoutConstraint.activate()

let label = UILabel(frame: CGRect.zero)
label.text = "Nothing to show"
label.textAlignment = .center
label.backgroundColor = .red  // Set background color to see if label is centered
label.translatesAutoresizingMaskIntoConstraints = false
self.tableView.addSubview(label)

let widthConstraint = NSLayoutConstraint(item: label, attribute: .width, relatedBy: .equal,
                                         toItem: nil, attribute: .notAnAttribute, multiplier: 1.0, constant: 250)

let heightConstraint = NSLayoutConstraint(item: label, attribute: .height, relatedBy: .equal,
                                          toItem: nil, attribute: .notAnAttribute, multiplier: 1.0, constant: 100)

let xConstraint = NSLayoutConstraint(item: label, attribute: .centerX, relatedBy: .equal, toItem: self.tableView, attribute: .centerX, multiplier: 1, constant: 0)

let yConstraint = NSLayoutConstraint(item: label, attribute: .centerY, relatedBy: .equal, toItem: self.tableView, attribute: .centerY, multiplier: 1, constant: 0)

NSLayoutConstraint.activate([widthConstraint, heightConstraint, xConstraint, yConstraint])

より良い解決策を

この質問が最初に回答されて以来、レイアウトアンカーが導入され、制約を作成するのがより簡単になりました。 この例では、私は制約を作成し、すぐにそれを有効にします。

label.widthAnchor.constraint(equalToConstant: 250).isActive = true
label.heightAnchor.constraint(equalToConstant: 100).isActive = true
label.centerXAnchor.constraint(equalTo: self.tableView.centerXAnchor).isActive = true
label.centerYAnchor.constraint(equalTo: self.tableView.centerYAnchor).isActive = true

あるいは,同じように NSLayoutConstraint.activate() :

NSLayoutConstraint.activate([
    label.widthAnchor.constraint(equalToConstant: 250),
    label.heightAnchor.constraint(equalToConstant: 100),
    label.centerXAnchor.constraint(equalTo: self.tableView.centerXAnchor),
    label.centerYAnchor.constraint(equalTo: self.tableView.centerYAnchor)
])

注意: サブビューは常にビュー階層に追加してください。 の前に を作成し、制約をアクティブにします。


オリジナルの回答です。

制約が参照するのは self.tableView . のサブビューとしてラベルを追加しているので、この制約は self.tableView のサブビューとしてラベルを追加しているので、制約は "共通の祖先" に追加される必要があります。

   self.tableView.addConstraint(xConstraint)
   self.tableView.addConstraint(yConstraint)


コメントで@mustafaさんや@kcstricksさんが指摘されているように、このような場合は label.translatesAutoresizingMaskIntoConstraintsfalse . これを行う場合、さらに widthheight は、フレームが使用されなくなったので、制約を持つラベルの 最後に textAlignment.Center に変更し、テキストがラベルの中央に配置されるようにします。

    var  label = UILabel(frame: CGRectZero)
    label.text = "Nothing to show"
    label.textAlignment = .Center
    label.backgroundColor = UIColor.redColor()  // Set background color to see if label is centered
    label.translatesAutoresizingMaskIntoConstraints = false
    self.tableView.addSubview(label)

    let widthConstraint = NSLayoutConstraint(item: label, attribute: .Width, relatedBy: .Equal,
        toItem: nil, attribute: .NotAnAttribute, multiplier: 1.0, constant: 250)
    label.addConstraint(widthConstraint)

    let heightConstraint = NSLayoutConstraint(item: label, attribute: .Height, relatedBy: .Equal,
        toItem: nil, attribute: .NotAnAttribute, multiplier: 1.0, constant: 100)
    label.addConstraint(heightConstraint)

    let xConstraint = NSLayoutConstraint(item: label, attribute: .CenterX, relatedBy: .Equal, toItem: self.tableView, attribute: .CenterX, multiplier: 1, constant: 0)

    let yConstraint = NSLayoutConstraint(item: label, attribute: .CenterY, relatedBy: .Equal, toItem: self.tableView, attribute: .CenterY, multiplier: 1, constant: 0)

    self.tableView.addConstraint(xConstraint)
    self.tableView.addConstraint(yConstraint)