2014-10-15 10 views
17

Istnieje wiele wątków o prawidłowo doborze tableHeaderView z auto-układ (one such thread), ale mają tendencję do pre-date iOS 8.-systemLayoutSizeFittingSize: powrót nieprawidłową wysokość dla tableHeaderView pod iOS 8

Mam sytuacji, z licznymi widoki tabelaryczne, wszystkie z nagłówkami, o takim rozmiarze poprawnie pod iOS 7, ale niepoprawnie pod iOS 8 za pomocą kodu, który zawiera większość wspomnianych wcześniej wątków. W sterownikach dla tabel, mam następujące metody:

- (void)rejiggerTableHeaderView 
{ 
    self.tableView.tableHeaderView = nil; 

    UIView *header = self.headerView; 

    [header setNeedsLayout]; 
    [header layoutIfNeeded]; 

    CGFloat height = [header systemLayoutSizeFittingSize:UILayoutFittingCompressedSize].height; 

    CGRect headerFrame = header.frame; 
    headerFrame.size.height = height; 

    header.frame = headerFrame; 

    self.tableView.tableHeaderView = header; 
} 

z etykietą multi-line pod iOS 7, to poprawnie rozmiarów nagłówek widoku tabeli jest tak:

But ten sam kod uruchomić pod iOS 8 produkuje następujące:

Co trick do -sys coraz temLayoutSizeFittingSize: aby zwrócić prawidłowy rozmiar w systemie iOS 8? Here's a sample project, który demonstruje problem.

Odpowiedz

14

Zmiana funkcji headerview do następujących utworów dla mnie:

- (void)rejiggerTableHeaderView 
{ 
    self.tableView.tableHeaderView = nil; 

    UIView *header = self.headerView; 
    CGRect frame = header.frame; 
    frame.size.width = self.tableView.frame.size.width; 
    header.frame = frame; 

    [header setNeedsLayout]; 
    [header layoutIfNeeded]; 

    CGFloat height = [header systemLayoutSizeFittingSize:UILayoutFittingCompressedSize].height; 

    CGRect headerFrame = header.frame; 
    headerFrame.size.height = height; 

    header.frame = headerFrame; 

    self.tableView.tableHeaderView = header; 
} 
+1

Tak, to naprawia. Dziękuję Ci bardzo. Na ile warto, system iOS 8.1 naprawiał wszystko, aby działało tak jak w wersji 7.1 (powyższy zrzut ekranu pochodzi z wersji 8.0.2). Ale po wykonaniu dodatkowego szturchania w moim przykładowym projekcie zdałem sobie sprawę, że oba powyższe zrzuty ekranu są i tak nieprawidłowe. Wysokość widoku została ustawiona, aby odpowiednio zamknąć ciąg, jeśli został obrócony do trybu poziomego, więc poprawka wyraźnie określająca, jaka jest prawdziwa szerokość widoku. –

+1

To nie działa dla mnie. Mam dwie etykiety wewnątrz nagłówka, jedna z nich nie jest poprawnie zmieniana. Pokazano tylko trzy linie. –

+5

Stwierdziłem, że winowajcą było brakujące ograniczenie: konieczne jest posiadanie podpórki z "UILabel" we wszystkich czterech kierunkach przeciwko superview. Pojedyncze brakujące ograniczenie uniemożliwi działanie "systemLayoutSizeFittingSize: UILayoutFittingCompressedSize". – SwiftArchitect

9

Problem może być prowadzona w niewyspecjalizowanych ustawić preferredMaxLayoutWidth. Jeśli ustawisz poprawną szerokość UILabel, to będzie ona poprawnie określać wiązania.

Możesz przejść przez wszystkie UILabel w nagłówku i ustawić preferredMaxLayoutWidth na szerokość etykiety.

Swift 3 Przykład:

extension UITableView { 
    public func relayoutTableHeaderView() { 
     if let tableHeaderView = tableHeaderView { 
      let labels = tableHeaderView.findViewsOfClass(viewClass: UILabel.self) 
      for label in labels { 
       label.preferredMaxLayoutWidth = label.frame.width 
      } 
      tableHeaderView.setNeedsLayout() 
      tableHeaderView.layoutIfNeeded() 
      tableHeaderView.frame.height = tableHeaderView.systemLayoutSizeFitting(UILayoutFittingCompressedSize).height 
      self.tableHeaderView = tableHeaderView 
     } 
    } 

    public func findViewsOfClass<T:UIView>(viewClass: T.Type) -> [T] { 
     var views: [T] = [] 
     for subview in subviews { 
      if subview is T { 
       views.append(subview as! T) 
      } 
      views.append(contentsOf: subview.findViewsOfClass(viewClass: T.self)) 
     } 
     return views 
    } 
} 

UPDATE 2:

Ponadto można mieć problem z nieprawidłowego obliczenia wysokości jeśli masz podrzędny z proporcji przymusu i jednocześnie proporcjonalny do szerokości Superview ograniczenie

2

Ponieważ to pytanie ma półtora roku, oto wersja zaktualizowana i kompletna w języku Swift. Część kodu z zaakceptowanej odpowiedzi jest błędna lub nieaktualna.

func fixHeaderHeight() { 
    // Set your label text if needed 
    // ... 
    // 

    guard let header = tableView.tableHeaderView else { 
     return 
    }  
    let height = header.systemLayoutSizeFittingSize(UILayoutFittingCompressedSize).height 
    header.frame.height = height    
    tableView.tableHeaderView = header 
} 

Gdzieś indziej w kodzie, musisz ustawić preferredMaxLayoutWidth etykiety (i) w nagłówku. Powinno to być równe tableView (lub szerokości ekranu) minus dowolne wypełnienie. didSet metoda gniazdka etykiet jest dobrym miejscem:

@IBOutlet weak var headerMessageLabel: UILabel! { 
     didSet { 
      headerMessageLabel.preferredMaxLayoutWidth = UIScreen.mainScreen().bounds.width - headerMessageLabelPadding 
     } 
    } 

Uwaga: Jeśli zaakceptowane odpowiedź pracował dla ciebie, nie są prawidłowo za pomocą klas wielkości.

0

Jeśli nagłówek zawiera tylko jedną etykietę następnie używam UILabel rozszerzenie znaleźć wysokość etykiety multiline daną szerokość:

public extension UILabel { 
    public class func size(withText text: String, forWidth width: CGFloat) -> CGSize { 
     let measurementLabel = UILabel() 
     measurementLabel.text = text 
     measurementLabel.numberOfLines = 0 
     measurementLabel.lineBreakMode = .byWordWrapping 
     measurementLabel.translatesAutoresizingMaskIntoConstraints = false 
     measurementLabel.widthAnchor.constraint(equalToConstant: width).isActive = true 
     let size = measurementLabel.systemLayoutSizeFitting(UILayoutFittingCompressedSize) 
     return size 
    } 
} 

Uwaga: powyższe jest w Swift 3 składni.

Z size obliczonej powyżej można przywrócić prawidłową wysokość w sposobie UITableViewDelegate:

func tableView(tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat 
0

Prawidłowe rozwiązania tego problemu w Swift 3 jest za pomocą tej klasy zamiast standardowej UILabel:

class UILabelPreferedWidth : UILabel { 
    override var bounds: CGRect { 
     didSet { 
      if (bounds.size.width != oldValue.size.width) { 
       self.setNeedsUpdateConstraints() 
      } 
     } 
    } 

    override func updateConstraints() { 
     if(preferredMaxLayoutWidth != bounds.size.width) { 
      preferredMaxLayoutWidth = bounds.size.width 
     } 
     super.updateConstraints() 
    } 
} 

Upewnij się również, że nie wyłączono tych dwóch w klasie Komórka:

translatesAutoresizingMaskIntoConstraints = false 
contentView.translatesAutoresizingMaskIntoConstraints = false 
0

Miałem ten sam problem. To działa dobrze dla mnie na iOS 8.4.

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { 
    [self.myLabel sizeToFit]; 
    [self.tableView.tableHeaderView layoutIfNeeded]; 
    return UITableViewAutomaticDimension; 
} 
Powiązane problemy