0

У меня есть UIView, который можно повторно использовать через файл nib/xib. Я хочу загрузить это и заполнить UITableViewCell, который должен использоваться в саморазрушающемся UITableView. Все с автоматической компоновкой.Nib-файл загружен UIView в UITableViewCell не растягивается

Большинство работает хорошо, но похоже, что загруженный UIView использует добавленные ограничения вокруг него, чтобы уменьшить содержимое contentView UITableViewCell. Это хорошо для высоты, но я не хочу этого для ширины.

How the UITableViewCell looks Игнорировать серая ячейка ниже, это только выбранная ячейка.

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) 
    } 

В RowView0002.xib я установить фон rootviews красный, добавил UILabel с 4 ограничениями на это стороны с некоторым запасом, как вы можете видеть. Я попытался установить rootView в класс RowView, а также в качестве владельца файла. Оба «работают».

Любая идея, как получить contentView в соответствии с UITableView?

* Редактировать 1: Зеленый - это фон UILabel. Красный - фон файла nib. После запуска приложения представление выглядит следующим образом: UITableViewCell> ContentView> RowView> NibFileView (красный)> UILabel (зеленый)

Проверка иерархии представлений показывает, что все ограничения настроены так, как ожидалось. Однако UITableViewContentView имеет ограничение, которые соответствуют общему размеру видел (неправильный):

self.width = 156.5 @ 1000 
+0

Почему разделительная линия ТВЦ находятся на разной высоте, чем в конце ваших взглядов? Кажется, что высота, занимаемая вашим видом, в три раза превышает высоту ячейки. Вы уверены, что это не перекрытие? попробуйте проверить размеры с помощью отладочного устройства просмотра. – Andrea

+0

Игнорируйте таблицу влево. Это еще один UITableView. – Sunkas

+0

Есть некоторые вещи, которые я не понимаю, зеленый цвет вашего взгляда от xib? красный контент TVView? – Andrea

ответ

0

Я решил его также добавив ограничение ширины, соответствующий ширине tableViews.Это код из 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. По умолчанию Nibs являются UIViews, удаляют представление в IB и перетаскивают UITableViewCell из библиотеки объектов в нижнем правом углу IB. Затем, если необходимо, установите его подкласс в подкласс UITableViewCell, который вы создали. (Вы также, возможно, потребуется установить reuseIdentifier в IB.)

Тогда в 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. Поэтому я не могу использовать ваше предложение о том, что UITableViewCell является корневым представлением в моем nib-файле. Тем не менее я решил это, добавив дополнительное ограничение ширины, которое растягивает представление при размещении в UITableViewCell. – Sunkas

0

Это правильный 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 должны быть добавлены как подвид перед присоединением к SuperView с помощью этих методов. Кроме того, все участвующие представления должны быть установлены с 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

 Смежные вопросы

  • Нет связанных вопросов^_^