2015-04-15 3 views
0

Я работаю над набором классов, которые позволяют использовать UITableView и связанные с ними классы для использования автоматического макета и динамического типа. Он основан на an answer on Stack Overflow, который направлен на добавление поддержки автоматического макета.Вычислить высоту экрана UITableViewCell с размерами классов

До сих пор он хорошо работает, но я столкнулся с несколькими проблемами при использовании классов размеров. Первая непосредственно связана с таблицей расчета высоты:

Когда я создаю новый UITableViewCell, но не добавлять его в любые мнения, класс размера является Any х Any, поэтому, когда у меня есть несколько подвидов или ограничения, которые изменяются в зависимости от класса размера, они всегда работают так, как если бы они находились в ситуации Any x Any. До сих пор моя очень Hacky решение создать новый UIWindow, что я добавляю клетки путем:

UIWindow(frame: UIScreen.mainScreen().applicationFrame)

Эта функция правильно, но у меня есть несколько вопросов с ним:

  • Я сейчас создает весь новый UIWindow объект, который кажется неэффективным
  • Каждая ячейка должна быть добавлена ​​в том же окне
  • Когда экран вращается, класс размер может меняться (например, iPhone 6 Plus), так что мне нужно слушать изменения в кадре приложения и обновления кадра моего окна (пока не реализовано)

есть простой/более эффективный способ обеспечить UITableViewCell знает свой класс размеров, не имея создать новый UIWindow или сделать это более эффективно? Может быть, я могу добавить

Большая часть текущего кода может быть найден через GitHub page, но наиболее значимые методы:

DynamicTableViewController

private var cachedClassesForCellReuseIdentifiers = [String : UITableViewCell.Type]() 
private var cachedNibsForCellReuseIdentifiers = [String : UINib]() 
private var offscreenCellRowsForReuseIdentifiers = [String : UITableViewCell]() 

private var offScreenWindow: UIWindow = { 
    return UIWindow(frame: UIScreen.mainScreen().applicationFrame) 
}() 

override public func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat { 
    // This method is called with an NSMutableIndexPath, which is not compatible with an imutable NSIndexPath, 
    // so we create an imutable NSIndexPath to be passed to the following methods 
    let imutableIndexPath = NSIndexPath(forRow: indexPath.row, inSection: indexPath.section) 

    if let reuseIdentifier = self.cellReuseIdentifierForIndexPath(imutableIndexPath) { 
     if let cell = self.cellForReuseIdentifier(reuseIdentifier) { 
      self.configureCell(cell, forIndexPath: indexPath) 

      if let dynamicCell = cell as? DynamicTableViewCell { 
       let height = dynamicCell.heightInTableView(tableView) 
       return height 
      } else { 
       // Fallback for non-DynamicTableViewCell cells 
       let size = cell.contentView.systemLayoutSizeFittingSize(UILayoutFittingCompressedSize) 
       let cellBoundsHeight = CGRectGetHeight(cell.bounds) 
       if size.height > 0 && size.height >= cellBoundsHeight { 
        // +1 for the cell separator 
        return size.height + 1 
       } else { 
        // In some situations (such as the content view not having any/enough constraints to get a height), the 
        // size from the systemLayoutSizeFittingSize: will be 0. However, because this can _sometimes_ be intended 
        // (e.g., when adding to a default style; see: DynamicSubtitleTableViewCell), we just return 
        // the height of the cell as-is. This may make some cells look wrong, but overall will also prevent 0 being returned, 
        // hopefully stopping some things from breaking. 
        return cellBoundsHeight + 1 
       } 
      } 
     } 
    } 

    return UITableViewAutomaticDimension 
} 

private func cellForReuseIdentifier(reuseIdentifier: String) -> UITableViewCell? { 
    if self.offscreenCellRowsForReuseIdentifiers[reuseIdentifier] == nil { 
     if let cellClass = self.cachedClassesForCellReuseIdentifiers[reuseIdentifier] { 
      let cell = cellClass() 

      self.offScreenWindow.addSubview(cell) 
      self.offscreenCellRowsForReuseIdentifiers[reuseIdentifier] = cell 
     } else if let cellNib = self.cachedNibsForCellReuseIdentifiers[reuseIdentifier] { 
      if let cell = cellNib.instantiateWithOwner(nil, options: nil).first as? UITableViewCell { 
       self.offScreenWindow.addSubview(cell) 
       self.offscreenCellRowsForReuseIdentifiers[reuseIdentifier] = cell 
      } 
     } 
    } 
    return self.offscreenCellRowsForReuseIdentifiers[reuseIdentifier] 
} 

DynamicTableViewCell

public func heightInTableView(tableView: UITableView) -> CGFloat { 
    var height: CGFloat! 
    if self.calculateHeight { 
     self.setNeedsUpdateConstraints() 
     self.updateConstraintsIfNeeded() 

     self.bounds = CGRectMake(0, 0, CGRectGetWidth(tableView.bounds), CGRectGetHeight(self.bounds)) 

     self.setNeedsLayout() 
     self.layoutIfNeeded() 

     let size = self.contentView.systemLayoutSizeFittingSize(UILayoutFittingCompressedSize) 
     let boundsHeight = CGRectGetHeight(self.bounds) 

     if size.height > 0 && size.height >= boundsHeight { 
      // +1 for the cell separator 
      height = size.height + 1 
     } else { 
      // In some situations (such as the content view not having any/enough constraints to get a height), the 
      // size from the systemLayoutSizeFittingSize: will be 0. However, because this can _sometimes_ be intended 
      // (e.g., when adding to a default style; see: DynamicSubtitleTableViewCell), we just return 
      // the height of the cell as-is. This may make some cells look wrong, but overall will also prevent 0 being returned, 
      // hopefully stopping some things from breaking. 
      height = boundsHeight + 1 
     } 
    } else { 
     height = self.cellHeight 
    } 

    if height < self.minimumHeight && self.minimumHeight != nil { 
     return self.minimumHeight! 
    } else { 
     return height 
    } 
} 

Это решение работает для iOS 7 и 8, и поэтому любые будущие решения. Это ограничение также устранило использование UITraitCollection, поэтому я не пошел по этому маршруту (я даже не уверен, что это поможет)

ответ

0

С IOS 8 и Autolayout Вы можете установить предполагаемую высоту строки и установить ограничения для внутренних представлений с представлением контента, чтобы он масштабировался в соответствии с содержимым в нем. Вот мой ответ Which is the best approach among Autolayout or calculating the height using NSAttributedString, to implement dynamic height of an UITableViewCell?

Update: для IOS7 вам нужно вычислить высоту, когда он собирается приехать вы можете сделать это в - (CGFloat)tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(NSIndexPath *)indexPath метод делегата

#define HEIGHT_FOR_ONE_LINE 15; //define it according to your fonts 
#define HEIGHT_FOR_SINGLE_ROWCELL 32; 
#pragma mark - Table view data source 
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath 
{ 
    NSString *textToView= [self.yourDataSourceArray objectAtIndex:indexPath.row]; 
    CGFloat screenWidth=[[UIScreen mainScreen]bounds].size.width; 
    CGFloat characterPerPoint= 10; 
    CGFloat widthTaken= characterPerPoint * textToView.length; 
    NSInteger numberOfLines= ceil(widthTaken/screenWidth); 
    CGFloat height=numberOfLines* HEIGHT_FOR_ONE_LINE; 
    height = height + HEIGHT_FOR_SINGLE_ROWCELL; 

    return height; 
} 
+0

Моя реализация используется для использования IOS автоматического расчета высоты 8 в для ячеек, но у меня было несколько проблем с этим, и мне это нужно для работы с iOS 7, поэтому использование и решение только для iOS 8 невозможно –

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