2016-04-26 1 views
12

Я хотел бы добавить заголовок в мой tableView. Этот заголовок содержит 1 UILabel. Высота заголовка должна рассчитываться в зависимости от количества строк, на которые нанесена метка.Как создать заголовок UITableView, высота которого определяется высотой его метки?

В моем коде я добавляю ограничения со всеми краями метки <>. Это моя попытка:

//Add header to tableView 
    header = UIView() 
    header.backgroundColor = UIColor.yellowColor() 
    tableView!.tableHeaderView = header 

    //Create Label and add it to the header 
    postBody = UILabel() 
    postBody.text = "The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog." 
    postBody.font = UIFont(name: "Lato-Regular", size: 16.0) 
    postBody.numberOfLines = 0 
    postBody.backgroundColor = FlatLime() 
    header.addSubview(postBody) 

    //Enable constraints for each item 
    postBody.translatesAutoresizingMaskIntoConstraints = false 
    header.translatesAutoresizingMaskIntoConstraints = false 

    //Add constraints to the header and post body 
    let postBodyLeadingConstraint = NSLayoutConstraint(item: postBody, attribute: NSLayoutAttribute.Leading, relatedBy: NSLayoutRelation.Equal, toItem: header, attribute: NSLayoutAttribute.Leading, multiplier: 1, constant: 0) 
    postBodyLeadingConstraint.active = true 

    let postBodyTrailingConstraint = NSLayoutConstraint(item: postBody, attribute: NSLayoutAttribute.Trailing, relatedBy: NSLayoutRelation.Equal, toItem: header, attribute: NSLayoutAttribute.Trailing, multiplier: 1, constant: 0) 
    postBodyTrailingConstraint.active = true 


    let postBodyTopConstraint = NSLayoutConstraint(item: postBody, attribute: NSLayoutAttribute.Top, relatedBy: NSLayoutRelation.Equal, toItem: header, attribute: NSLayoutAttribute.Top, multiplier: 1, constant: 0) 
    postBodyTopConstraint.active = true 


    let postBodyBottomConstraint = NSLayoutConstraint(item: postBody, attribute: NSLayoutAttribute.Bottom, relatedBy: NSLayoutRelation.Equal, toItem: header, attribute: NSLayoutAttribute.Bottom, multiplier: 1, constant: 0) 
    postBodyBottomConstraint.active = true 


    //Calculate header size 
    let size = header.systemLayoutSizeFittingSize(UILayoutFittingCompressedSize) 
    var frame = header.frame 
    frame.size.height = size.height 
    header.frame = frame 
    tableView!.tableHeaderView = header 
    header.layoutIfNeeded() 

Это мой стол:

let nib = UINib(nibName: "MessagesTableViewCell", bundle: nil) 
    let nibSimple = UINib(nibName: "SimpleMessagesTableViewCell", bundle: nil) 
    self.tableView!.registerNib(nib, forCellReuseIdentifier: "MessagesTableViewCell") 
    self.tableView!.registerNib(nibSimple, forCellReuseIdentifier: "SimpleMessagesTableViewCell") 
    self.tableView!.dataSource = self 
    self.tableView!.delegate = self 
    self.tableView!.rowHeight = UITableViewAutomaticDimension 
    self.tableView!.estimatedRowHeight = 100.0 
    self.tableView!.separatorStyle = UITableViewCellSeparatorStyle.None 
    self.tableView!.separatorColor = UIColor(hex: 0xf5f5f5) 
    self.tableView!.separatorInset = UIEdgeInsetsMake(0, 0, 0, 0) 
    self.tableView!.clipsToBounds = true 
    self.tableView!.allowsSelection = false 
    self.tableView!.allowsMultipleSelection = false 
    self.tableView!.keyboardDismissMode = .OnDrag 

Как вы можете видеть, заголовок не принимает во внимание высоту метки (что я и сделал numberOfLines = 0)

Header does not auto-height

+0

Можете ли вы опубликовать свой основной код метода просмотра таблицы? –

+0

Если вы установили точку останова, как выглядит кадр, когда вы назначаете его обратно в заголовок? – Joe

+0

Вы не пропустите postBody.translatesAutoresizingMaskIntoConstraints = false? – Terry

ответ

13

UILabel s использовать UIViewintrinsicContentSize(), чтобы сообщить авторам о том, какой размер они должны быть. Однако для многострочной метки внутренний размер содержимого неоднозначен; таблица не знает, должна ли она быть короткой и широкой, высокой и узкой, или что-либо между ними.

Для борьбы с этим UILabel имеет объект под названием preferredMaxLayoutWidth. Установка этого параметра указывает на многострочную метку, которая должна быть не выше этой ширины, и позволяет intrinsicContentSize() выяснить и вернуть соответствующую высоту для соответствия. Не устанавливая preferredMaxLayoutWidth в вашем примере, ярлык оставляет свою ширину неограниченной и, следовательно, вычисляет высоту для длинной отдельной строки текста.

Единственное осложнение с preferredMaxLayoutWidth заключается в том, что вы, как правило, не знаете, какую ширину вы хотите, чтобы метка была до тех пор, пока автомат не рассчитал один для вас. По этой причине место, чтобы установить его в вид контроллера подкласса (который он выглядит как ваш образец кода может быть от) в viewDidLayoutSubviews:

override func viewDidLayoutSubviews() { 
    super.viewDidLayoutSubviews() 
    postBody.preferredMaxLayoutWidth = CGRectGetWidth(postBody.frame) 
    // then update the table header view 
    if let header = tableView?.tableHeaderView { 
     header.frame.size.height = header.systemLayoutSizeFittingSize(UILayoutFittingCompressedSize).height 
     tableView?.tableHeaderView = header 
    } 
} 

Очевидно, что вам нужно добавить свойство для postBody чтобы это работало.

Дайте мне знать, если вы не находитесь в подклассе UIViewController, и я отредактирую свой ответ.

-2

вы можете рассчитать высоту этикетки, используя его строку

let labelWidth = label.frame.width 
let maxLabelSize = CGSize(width: labelWidth, height: CGFloat.max) 
let actualLabelSize = label.text!.boundingRectWithSize(maxLabelSize, options: [.UsesLineFragmentOrigin], attributes: [NSFontAttributeName: label.font], context: nil) 
let labelHeight = actualLabelSize.height 
+1

Ну, это для заголовка раздела, а не для заголовка таблицы. Совсем другая вещь. – Sulthan

9

Первая проблема, которую мы имеем в том, что заголовок не может быть изменен путем autolayout, для получения дополнительной информации см Is it possible to use AutoLayout with UITableView's tableHeaderView?

Таким образом, мы должны вычислить высоту заголовка вручную например:

@IBOutlet var table: UITableView! 

var header: UIView? 
var postBody: UILabel? 

override func viewDidLoad() { 
    super.viewDidLoad() 

    let header = UIView() 
    // don't forget to set this 
    header.translatesAutoresizingMaskIntoConstraints = true 
    header.backgroundColor = UIColor.yellowColor() 

    let postBody = UILabel() 
    postBody.translatesAutoresizingMaskIntoConstraints = false 
    postBody.text = "The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog." 
    postBody.font = UIFont.systemFontOfSize(16.0) 

    // don't forget to set this 
    postBody.lineBreakMode = .ByWordWrapping 
    postBody.numberOfLines = 0 

    header.addSubview(postBody) 

    let leadingConstraint = NSLayoutConstraint(item: postBody, attribute: NSLayoutAttribute.Leading, relatedBy: NSLayoutRelation.Equal, toItem: header, attribute: NSLayoutAttribute.Leading, multiplier: 1, constant: 0) 
    let trailingConstraint = NSLayoutConstraint(item: postBody, attribute: NSLayoutAttribute.Trailing, relatedBy: NSLayoutRelation.Equal, toItem: header, attribute: NSLayoutAttribute.Trailing, multiplier: 1, constant: 0) 
    let topConstraint = NSLayoutConstraint(item: postBody, attribute: NSLayoutAttribute.Top, relatedBy: NSLayoutRelation.Equal, toItem: header, attribute: NSLayoutAttribute.Top, multiplier: 1, constant: 0) 
    let bottomConstraint = NSLayoutConstraint(item: postBody, attribute: NSLayoutAttribute.Bottom, relatedBy: NSLayoutRelation.Equal, toItem: header, attribute: NSLayoutAttribute.Bottom, multiplier: 1, constant: 0) 

    header.addConstraints([leadingConstraint, trailingConstraint, topConstraint, bottomConstraint]) 

    self.table.tableHeaderView = header 

    self.header = header 
    self.postBody = postBody 
} 

override func viewDidLayoutSubviews() { 
    super.viewDidLayoutSubviews() 

    let text = postBody!.attributedText! 

    let height = text.boundingRectWithSize(
     CGSizeMake(table.bounds.size.width, CGFloat.max), 
     options: [.UsesLineFragmentOrigin], 
     context: nil 
    ).height 

    header!.frame.size.height = height 
} 

Возможно, вы также захотите использовать код в stefandouganhyde's answer. Неважно, как вы вычисляете высоту. Дело в том, что автоотключение не будет работать автоматически для tableHeaderView.

Результат:

resulting table

10

Реализация с использованием раскадровки

  1. В UItableView добавить на UITableViewCell новый UIView и положил ему UILabel Соединяет их через Autolayout
  2. В UILabel, число строк в 0.
  3. В ViewDidLoad вашего UILabel вызова метода sizeToFit() и указать размер для UIView, и это будет ваш HeaderVew headerView.frame.size.height = headerLabel.frame.size.height

Код

@IBOutlet weak var tableView: UITableView! 
    @IBOutlet weak var headerView: UIView! 
    @IBOutlet weak var headerLabel: UILabel! 

    override func viewDidLoad() { 
     super.viewDidLoad() 

     headerLabel.text = "tableViewdidReceiveMemoryWarningdidReceiveMemoryWarningdidReceiveMemoryWarningdidReceiveMemoryWarningdidReceiveMemoryWarningdidReceiveMemoryWarningdidReceiveMemoryWarningdidReceiveMemoryWarningdidReceiveMemoryWarning" 
     headerLabel.sizeToFit() 
     headerView.frame.size.height = headerLabel.frame.size.height 
    } 

ScreenShot

enter image description here

TestProject

test project link

2

Мы используем NSLayoutManager быстро оценить высоту для элементов, которые необходимо изменить размер на основе текста. Это основная идея:

override class func estimatedHeightForItem(text: String, atWidth width: CGFloat) -> CGFloat { 

    let storage = NSTextStorage(string: text!) 
    let container = NSTextContainer(size: CGSize(width: width, height: CGFloat.max)) 
    let layoutManager = NSLayoutManager() 
    layoutManager.addTextContainer(container) 
    storage.addLayoutManager(layoutManager) 
    storage.addAttribute(NSFontAttributeName, value: UIFont.Body, range: NSRange(location: 0, length: storage.length)) 
    container.lineFragmentPadding = 0.0 

    return layoutManager.usedRectForTextContainer(container).size.height 
} 

Beslan's answer, вероятно, лучше подходит для вашего случая использования, но я считаю, что хорошо иметь больше контроля, как обрабатывается макет.

-1

// Возможно, это поможет вам.

header = UIView(frame: CGRectMake(tableview.frame.origin.x,tableview.frame.origin.y, tableview.frame.size.width, 40)) 
header.backgroundColor = UIColor.yellowColor() 

//Create Label and add it to the header 
postBody = UILabel(frame: header.frame) 
postBody.text = "The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog." 
postBody.font = UIFont(name: "Lato-Regular", size: 16.0) 
postBody.numberOfLines = 0 
postBody.backgroundColor = FlatLime() 
header.addSubview(postBody) 

let maximumLabelSize: CGSize = CGSizeMake(postBody.size.width, CGFloat.max); 

let options: NSStringDrawingOptions = NSStringDrawingOptions.UsesLineFragmentOrigin 
let context: NSStringDrawingContext = NSStringDrawingContext() 
     context.minimumScaleFactor = 0.8 
     let attr: Dictionary = [NSFontAttributeName: postBody.font!] 
     var size: CGSize? = postBody.text?.boundingRectWithSize(maximumLabelSize, options:options, attributes: attr, context: context).size 

let frame = header.frame 
frame.size.height = size?.height 
header.frame = frame 
postBody.frame = frame 
tableView!.tableHeaderView = header 
Смежные вопросы