Search code examples
iosuitableviewaccessibilitydynamic-type-feature

UITableViewCell don't change layout when iOS larger text is used


I have a UITableView that looks like the following:

enter image description here

When a user changes the iOS text size settings, the layout changes.

enter image description here

Layout gets changed where the detail label gets pushed under the title, and the disclosure indicator gets very large. This happens with standard cell layout and custom cell layout with my own UILabel subviews.

enter image description here

I am not ready to support dynamic type, so is there a way to not allow iOS to change the layout of my UITableViewCells?


Solution

  • Many things have been made for iOS to assist with the Dynamic Type implementation in the table view cells ⟹ automatic cell sizing for instance.

    I reproduced the initial problem in a blank project as follows: enter image description here

    With no extra code and only due to the iOS native implementation, notice that:

    • There's a reordering of the labels when the first accessibility step is reached.
    • The system accessory element size changes according to the Dynamic Type using.
    • There's an automatic row height resizing.

    [...] is there a way to not allow iOS to change the layout of my UITableViewCells?

    A solution may lead to the creation of your own custom table view cell as follows:

    class MyTableViewCell: UITableViewCell {
    
        @IBOutlet weak var myTitle: UILabel!
        @IBOutlet weak var myDetail: UILabel!
    
        static let reuseIdentifier = "myReuseIdentifier"
    
        override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
            super.init(style: style, reuseIdentifier: reuseIdentifier)
            setUpElementsAndConstraints()
        }
    
        required init?(coder aDecoder: NSCoder) {
            super.init(coder: aDecoder)
            setUpElementsAndConstraints()
        }
    
        private func setUpElementsAndConstraints() {
            //Custom your labels and their constraints in here.
            //For the demo, everything is hard coded within the Interface Builder.
        }
    }
    
    1. Add your labels with the property adjustsFontForContentSizeCategory to false in order to keep their initial font size.

    2. Create your own 'chevron image' that won't be resized as the system one:

       override func tableView(_ tableView: UITableView,
                               cellForRowAt indexPath: IndexPath) -> MyTableViewCell {
      
           let cell = tableView.dequeueReusableCell(withIdentifier: MyTableViewCell.reuseIdentifier,
                                                    for: indexPath) as! MyTableViewCell
      
           let accessoryImageFrame = CGRect(x: 0.0, y: 0.0,
                                            width: 40.0, height: 40.0)
           let accessoryImageView = UIImageView(frame: accessoryImageFrame)
           accessoryImageView.image = UIImage(named: "MyChevron")
      
           cell.accessoryView = accessoryImageView
      
           return cell
       }
      
    3. Define a static row height in the table view:

       override func tableView(_ tableView: UITableView,
                               heightForRowAt indexPath: IndexPath) -> CGFloat { return 50.0 }
      
    4. Don't forget to set up your constraints that may be updated according to the text sizes settings thanks to the traitCollectiondidChange method... even if you don't want to use the Dynamic Type feature yet. 😉

    Finally, I get this result that never changes whatever the text sizes in the settings: 🥳 enter image description here

    Following this rationale, your UITableViewCell layout doesn't change when iOS larger text is used. 👍 (I know, my custom chevron isn't really nice 😁)