Dynamic Type and Self-Sizing Cells with Static Table

坚强是说给别人听的谎言 提交于 2019-12-03 10:38:16

Static table views return row height set in Interface Builder. tableView.rowHeight setting seem to be completely ignored. This is apparently a bug in UIKit.

In order to fix that, simply override -(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath and return UITableViewAutomaticDimension.

First add this two function in your class

func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
    return UITableViewAutomaticDimension
}

func tableView(tableView: UITableView, estimatedHeightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
    return UITableViewAutomaticDimension
}

Second in order to make the UITableViewAutomaticDimension work make sure you have added all the left, right, bottom, and top constraints relative to cell container view. Also don't forget to set label's number of line to zero.

Since this is a static table, you can't dequeue the cells, so you will have to create IBOutlets to them, I'd hold them in an array like this:

@IBOutlet var cells: [UITableViewCell]!  

Then you will have to implement heightForRowAtIndexPath and calculate the size:

var rowSizes: [Int: CGFloat] = [:]

override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
    return calculateHeightForCell(indexPath)
}

func calculateHeightForCell(indexPath: NSIndexPath) -> CGFloat {

    // check if we already calculated the height
    if let height = rowSizes[indexPath.row] {
        return height
    }

    // else, calculate it
    let cell = cells[indexPath.row]

    let size = cell.contentView.systemLayoutSizeFittingSize(UILayoutFittingCompressedSize)

    rowSizes[indexPath.row] = size.height

    return size.height
}

rowSizes acts like a cache, it will hold the row heights, so they will only be calculated once. When changing the font size, simply empty rowSizes and refresh the table so they will be calculated again.

I'm grateful for the answers provided to the question I posted yesterday. Unfortunately (and likely because of my own inexperience as an iOS programmer) I was not able to make the systemLayoutSizeFittingSize(UILayoutFittingCompressedSize) approach work. After some trial and error, however, I found a different method that seems to work:

import UIKit

class MasterTVC: UITableViewController {
    @IBOutlet weak var staticCustomCellLabel: UILabel!

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

        self.tableView.estimatedRowHeight = 44.0

        staticCustomCellLabel.text = "This is the text for the static custom cell label; This is the text for the static custom cell label; This is the text for the static custom cell label"

        //Register handleDynamicTypeChange in observer: self
        NSNotificationCenter.defaultCenter().addObserver(self, selector: "handleDynamicTypeChange:", name: UIContentSizeCategoryDidChangeNotification, object: nil)
    }

    //deinit
    deinit {
        NSNotificationCenter.defaultCenter().removeObserver(self)
    }

    //handleDynamicTypeChange
    //called when user changes text size in Settings > General > Accessibility > Larger Text
    //or Settings > Display & Brightness > Text Size
    func handleDynamicTypeChange(notification: NSNotification) {
        staticCustomCellLabel.font = UIFont.preferredFontForTextStyle(UIFontTextStyleBody)

        self.tableView.reloadData()
    }

    //tableView:heightForRowAtIndexPath
    override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
        return UITableViewAutomaticDimension
    }
}

On the Storyboard side of this, the setup begins with a single Table View Controller with the following properties:

  • Class: MasterTVC (my custom class);
  • designated the initial view controller;
  • Content: Static Cells;
  • Style: Grouped
  • Sections: 1.

Section-1:

  • Rows: 1.

Table View Cell:

  • Style: Custom (using Basic here causes the label to disappear when changing text size in Settings);
  • Containing a UILabel.

The UILabel is further configured as:

  • Font: Body (a Dynamic Type style);
  • Lines: 0;
  • Pinned on all four sides to the top, bottom, left, and right edges of the content view (I used the respective constraints 8, 8, 15, 15);
  • with an @IBOutlet in the custom class code.

This worked for me designing for iOS 9 in Xcode 7 and Swift 2 with Auto Layout enabled. The interesting thing is that if you strip away the NSNotificationCenter code that is used to respond immediately to changes in text size, the self-sizing cells code is basically two lines: setting estimatedRowHeight in viewDidLoad, and returning UITableViewAutomaticDimension from tableView:heightForRowAtIndexPath.

Based on these results, I believe the answers to my original question are: 1) yes; and 2) see 1.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!