0

私はnib/xibファイル経由で再利用可能なUIViewを持っています。私はこれをロードし、自己サイズ変更のUITableViewで使用されるUITableViewCellを入力します。すべてが自動レイアウトです。NIBファイルロードされたUIViewは伸びません

ほとんどの場合うまくいきますが、ロードされたUIViewは、その周りに追加された制約を使用して、UITableViewCellのcontentViewを縮小するようです。これは高さには良いですが、私は幅のためにこれをしたくありません。

How the UITableViewCell looks 以下の灰色のセルは無視してください。これは選択されたセルに過ぎません。私は赤にrootviewsの背景を設定しているRowView0002.xibで

public func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell 
{ 
    let cellId = "RowView0002" 
    var cell = tableView.dequeueReusableCell(withIdentifier: cellId) 
    if cell == nil { 
     cell = UITableViewCell(style: UITableViewCellStyle.default, reuseIdentifier: cellId) 

     let subView = RowView(frame: cell!.frame) 

     cell!.contentView.attachViewWithConstraints(subView) 
     let _ = subView.viewLoadedFromNibAttached(name: cellId) 

    } 

    return cell! 
} 

override public func viewDidLoad() { 
    super.viewDidLoad() 

    tableView.delegate = self 
    tableView.dataSource = self 
    tableView.estimatedRowHeight = 40.0 
    tableView.rowHeight = UITableViewAutomaticDimension 
} 

extension UIView 
{ 
    public func attachViewWithConstraints(_ view:UIView) 
    { 
     addSubview(view) 
     view.translatesAutoresizingMaskIntoConstraints = false 
     view.layoutAttachAll(to: self) 
    } 

    @discardableResult 
    public func viewLoadedFromNibAttached<T : UIView>(name:String) -> T? { 
     guard let view = Bundle.main.loadNibNamed(name, owner: self, options: nil)?[0] as? T else { 
      return nil 
     } 
     attachViewWithConstraints(view) 
     return view 
    } 

    public func layoutAttachAll(to childView:UIView) 
    { 
     var constraints = [NSLayoutConstraint]() 

     childView.translatesAutoresizingMaskIntoConstraints = false 
     constraints.append(NSLayoutConstraint(item: childView, attribute: .left, relatedBy: .equal, toItem: self, attribute: .left, multiplier: 1.0, constant: 0)) 
     constraints.append(NSLayoutConstraint(item: childView, attribute: .right, relatedBy: .equal, toItem: self, attribute: .right, multiplier: 1.0, constant: 0)) 
     constraints.append(NSLayoutConstraint(item: childView, attribute: .top, relatedBy: .equal, toItem: self, attribute: .top, multiplier: 1.0, constant: 0)) 
     constraints.append(NSLayoutConstraint(item: childView, attribute: .bottom, relatedBy: .equal, toItem: self, attribute: .bottom, multiplier: 1.0, constant: 0)) 

     childView.addConstraints(constraints) 
    } 

、あなたが見ることができるよう余裕でそれの側面に4つの制約にUILabelを追加しました。私はrootViewクラスをRowViewクラスに設定しようとしましたが、それはFile's Ownerです。両方とも "働く"。

どのようにコンテンツビューを取得するにはどのようなアイデアは、UITableViewに一致する?

*編集1: 緑はUILabelの背景です。赤色は、nibファイルの背景です。アプリケーションを実行すると、次のような情報が表示されます。UITableViewCell> ContentView> RowView> NibFileView(赤色)> UILabel(緑色)

ビュー階層を調べると、すべての制約が期待通りに設定されていることがわかります。 UITableViewContentViewが見合計サイズを一致させる制約(間違った)を持っているしかし:それは自分自身のサイジングですので

それが問題のように見える
self.width = 156.5 @ 1000 
+0

にTVCの区切り線があなたの意見の終わりとは異なる高さであるのはなぜ?あなたの視点が占める高さは、セルの高さの3倍です。重複していないと確信していますか?ビューデバッガを使用してディメンションを確認してください。 – Andrea

+0

左側のtableviewは無視してください。別のUITableViewです。 – Sunkas

+0

私は理解していないいくつかのものがあります、グリーンはxibからのあなたの意見ですか?赤はTVCのcontentViewですか? – Andrea

答えて

0

あります。これはCustomTableViewCellからコードである:

public override func layoutSubviews() { 
    super.layoutSubviews() 

    if let width = tableView()?.frame.width, !haveAddedWidthConstraint { 
     haveAddedWidthConstraint = true 
     rowView.addWidthConstraint(width: width) 
    } 
} 

UIViewExtension:

public func addWidthConstraint(width: CGFloat) { 
    let widthConstraint = NSLayoutConstraint(item: self, attribute: .width, relatedBy: .greaterThanOrEqual, toItem: nil, attribute: .notAnAttribute, multiplier: 1.0, constant: width) 
    widthConstraint.priority = 1000 
    addConstraint(widthConstraint) 
} 

UITableViewCellExtension:

func tableView() -> UITableView? { 
    var currentView: UIView = self 
    while let superView = currentView.superview { 
     if superView is UITableView { 
      return (superView as! UITableView) 
     } 
     currentView = superView 
    } 
    return nil 
} 
0

は、UITableViewCell(style: UITableViewCellStyle.default, reuseIdentifier: cellId)で作成したセルは、テーブルビューの幅に関する情報がありませんということですラベルの幅に基づいています。明らかに、テーブルビュー/セルは、セルのコンテンツビューにその幅を強制しません。

おそらく、このセル処理コードのいくつかを手直ししたいと思うでしょう。

xibからセルをロードする場合は、すべての制約をスキップできます。ただ実装する:

override func viewDidLoad() { 
    //... 
    let nib = UINib(nibName: "RowView0002", bundle: NSBundle.main) 
    tableView.reigsterNib(nib, forCellReuseIdentifier: "RowView0002") 
} 

非常に重要:.xibファイルの最初のトップレベル項目は、UITableViewCellでなければなりません。 NibはデフォルトでUIViewであり、IBでビューを削除し、IBの右下にあるオブジェクトライブラリからUITableViewCellをドラッグします。必要に応じて、作成したUITableViewCellサブクラスにサブクラスを設定します。 (あなたはまた、IBにreuseIdentifierを設定する必要があるかもしれません。)

を次にtableView(_:cellForRowAt IndexPath:)に:

guard let cell = tableView.dequeueResuableCell(withIdentifier: "RowView0002", for: indexPath) as? TheNibUITableViewSubclass else { //something went wrong, probably crash } 
cell.label.text = //... 
return cell 

あなたは、おそらく一定のどこかにいる「RowView0002」を置くことになるでしょう。

"RowView0002"クラスとRowViewクラスの両方をビューにする必要がある場合は、おそらくUITableViewCellのサブクラスを作成する必要があります。上書きするだけでinit(style:resueIdentifier:) and after calling super`上記のコードであなたのサブビューを追加します。お役に立てれば!

+0

問題は、nibファイルをUITableViewCellで使用されていない場所にロードする必要があることです。だからあなたの提案を私のnibファイルのルートビューとしてUITableViewCellを使用することはできません。しかし、UITableViewCellに配置したときにビューを引き伸ばす追加の幅制約を設定することで解決しました。 – Sunkas

0

これは私もtableViews幅と一致する幅の制約を追加することによってそれを解決正しいlayoutAttachAll

public func layoutAttachAll(to parentView:UIView) 
{ 
    var constraints = [NSLayoutConstraint]() 
    self.translatesAutoresizingMaskIntoConstraints = false 
    constraints.append(NSLayoutConstraint(item: self, attribute: .left, relatedBy: .equal, toItem: parentView, attribute: .left, multiplier: 1.0, constant: 0)) 
    constraints.append(NSLayoutConstraint(item: self, attribute: .right, relatedBy: .equal, toItem: parentView, attribute: .right, multiplier: 1.0, constant: 0)) 
    constraints.append(NSLayoutConstraint(item: self, attribute: .top, relatedBy: .equal, toItem: parentView, attribute: .top, multiplier: 1.0, constant: 0)) 
    constraints.append(NSLayoutConstraint(item: self, attribute: .bottom, relatedBy: .equal, toItem: parentView, attribute: .bottom, multiplier: 1.0, constant: 0)) 
    parentView.addConstraints(constraints) 
} 
1

layoutAttachAllの完全な実装は以下です。

最初のいくつかの使用例:

// pin all edge to superview 
myView.layoutAttachAll() 

// pin all edges (to superview) with margin: 
myView.layoutAttachAll(margin: 8.0) 

// for child views: pin leading edge to superview's leading edge: 
myView.layoutAttachLeading() 

// for sibling views: pin leading edge to siblingView's trailing edge: 
myView.layoutAttachLeading(to: siblingView) 

// for sibling views: pin top edge to siblingView's bottom edge: 
myView.layoutAttachTop(to: siblingView) 

注:MYVIEWは、これらの方法を使用してをスーパーする取り付ける前サブビューとして追加されなければなりません。また、参加するすべてのビューはtranslatesAutoresizingMaskIntoConstraints = falseで設定する必要があります。

完全な実装:

import UIKit 

extension UIView { 

    /// attaches all sides of the receiver to its parent view 
    func layoutAttachAll(margin : CGFloat = 0.0) { 
     let view = superview 
     layoutAttachTop(to: view, margin: margin) 
     layoutAttachBottom(to: view, margin: margin) 
     layoutAttachLeading(to: view, margin: margin) 
     layoutAttachTrailing(to: view, margin: margin) 
    } 

    /// attaches the top of the current view to the given view's top if it's a superview of the current view, or to it's bottom if it's not (assuming this is then a sibling view). 
    /// if view is not provided, the current view's super view is used 
    @discardableResult 
    func layoutAttachTop(to: UIView? = nil, margin : CGFloat = 0.0) -> NSLayoutConstraint { 

     let view: UIView? = to ?? superview 
     let isSuperview = view == superview 
     let constraint = NSLayoutConstraint(item: self, attribute: .top, relatedBy: .equal, toItem: view, attribute: isSuperview ? .top : .bottom, multiplier: 1.0, constant: margin) 
     superview?.addConstraint(constraint) 

     return constraint 
    } 

    /// attaches the bottom of the current view to the given view 
    @discardableResult 
    func layoutAttachBottom(to: UIView? = nil, margin : CGFloat = 0.0, priority: UILayoutPriority? = nil) -> NSLayoutConstraint { 

     let view: UIView? = to ?? superview 
     let isSuperview = (view == superview) || false 
     let constraint = NSLayoutConstraint(item: self, attribute: .bottom, relatedBy: .equal, toItem: view, attribute: isSuperview ? .bottom : .top, multiplier: 1.0, constant: -margin) 
     if let priority = priority { 
      constraint.priority = priority 
     } 
     superview?.addConstraint(constraint) 

     return constraint 
    } 

    /// attaches the leading edge of the current view to the given view 
    @discardableResult 
    func layoutAttachLeading(to: UIView? = nil, margin : CGFloat = 0.0) -> NSLayoutConstraint { 

     let view: UIView? = to ?? superview 
     let isSuperview = (view == superview) || false 
     let constraint = NSLayoutConstraint(item: self, attribute: .leading, relatedBy: .equal, toItem: view, attribute: isSuperview ? .leading : .trailing, multiplier: 1.0, constant: margin) 
     superview?.addConstraint(constraint) 

     return constraint 
    } 

    /// attaches the trailing edge of the current view to the given view 
    @discardableResult 
    func layoutAttachTrailing(to: UIView? = nil, margin : CGFloat = 0.0, priority: UILayoutPriority? = nil) -> NSLayoutConstraint { 

     let view: UIView? = to ?? superview 
     let isSuperview = (view == superview) || false 
     let constraint = NSLayoutConstraint(item: self, attribute: .trailing, relatedBy: .equal, toItem: view, attribute: isSuperview ? .trailing : .leading, multiplier: 1.0, constant: -margin) 
     if let priority = priority { 
      constraint.priority = priority 
     } 
     superview?.addConstraint(constraint) 

     return constraint 
    } 
} 
+0

これは、トップ、ボトム、先行および後続の制約を設定するためのヘルプメソッドです。私のlayoutAttachAllはすでにこれをやっています。問題は受け入れられた答えが欠落している幅制約を記述しているためでした。 – Sunkas

関連する問題