Trouble with Autolayout on Uitableviewcell

Trouble with AutoLayout on UITableViewCell

A few things to cover here:

  1. The NSIBPrototypingLayoutConstraint constraints that you're running into (and that are causing exceptions) are auto-generated by Interface Builder in order to make your Storyboard or XIB view layout non-ambiguous. It's pretty sneaky about doing this, but it's automatically adding the minimum constraints required so that the position and size of each ambiguous view becomes fully specified. This is a change from Xcode 4, because in Xcode 4 you could not have ambiguous layouts in Interface Builder. With Xcode 5 and later you can, however IB will auto-generate these constraints for you if your layout is ambiguous at compile time.

    The way to fix this issue is to add the minimum required constraints in Interface Builder so that each view's position & size is fully specified, then select each of these unwanted constraints, go to the right sidebar Attributes inspector, and check the box next to Placeholder - Remove at build time.

    Screenshot of the constraint Placeholder checkbox in Xcode 6.

    Not only does this checkbox remove the constraint you added, but most importantly it will prevent the auto-generated IB constraint from taking its place! (As you can imagine, this is quite tedious when you have a number of views in IB and want to manage all your constraints in code. For this reason you may want to avoid using IB entirely for view hierarchies in which you intend to implement Auto Layout programmatically.)

    What is the difference between a Placeholder constraint and an Uninstalled constraint? Here's a slide from my Adaptive Auto Layout talk (video) (PDF slides) comparing the two:

    Comparison between Placeholder constraints and Uninstalled constraints.

  2. In updateConstraints, you don't want to remove constraints and re-add them like you have there. Why not? Essentially, it's terrible for performance, and I have confirmed with Apple engineers that this is not a good idea. See the question/answer I have posted here for some more details, as well as this answer. In order to prevent constraints being added more than once, use a boolean flag (e.g. hasSetupConstraints) that you set to YES once you have set up your constraints the first time, and if updateConstraints is called again you can just return immediately if you have no new constraints to add. See this question for further discussion.

  3. The code you're using to remove constraints may not work completely. This is because [view removeConstraints:view.constraints] will only remove constraints that have been added to view -- remember that constraints can be added to any common superview of the views they constrain -- and the constraints added to view may not be the only ones affecting the layout of view! If you need to remove a number of constraints, you should store a reference to each of those constraints in a property (e.g. an NSArray property containing NSLayoutConstraint instances), and then deactivate/remove those constraints using the API on NSLayoutConstraint or the PureLayout open-source library. You should only deactivate/remove as few constraints as possible because it is computationally expensive to do so. On the other hand, changing the constant of any constraint is very efficient and encouraged, and you don't need to remove or re-add the constraint to do that.

Autolayout is ignored in Custom UITableViewCell

Auto-layout was ignored because both the prototype cell AND the UIView of the cell had been given the custom cell class in IB.

Setting the UIView back to UIView class solved the problem.

just to be über clear

UITableViewCell Autolayout issues (iOS 11, Xcode 9.2)

That height makes sense, because you've set the ImageView to a static height and then bound its top and bottom to the content view. This stops the cell from growing any taller.

You'll need to allow the image height to grow or remove the top or bottom constraint so the cell's height isn't limited by the image view.

Try these constraints:

  • Image View Height/Width
  • Image View Leading = Cell Leading
  • Image View Top = Cell Top

    • Or center vertically or whatever you'd like.
    • Basically, just set the Y position for the image view somehow
  • Label Leading = Image View Trailing
  • Label Top = Cell Top
  • Label Bottom = Cell Bottom
  • Label Trailing = Cell Trailing
  • Label Height >= Image View Height

    • To stop the label (and therefore, the cell) from collapsing smaller than the image view

UITableViewCell height auto layout not working on iOS 10

This configuration from your viewDidLoad:

tableView.estimatedRowHeight = UITableViewAutomaticDimension
tableView.rowHeight = UITableViewAutomaticDimension

...works only on iOS 11. It is an iOS 11 innovation and does not apply to earlier systems.

For iOS 10, you must supply an actual estimatedRowHeight value (such as 60) to turn on automatic variable row height calculation.

UITableViewCell auto-layout issue with centerXAnchor set

I'd have thought the easier way to do this would be to set leading and trailing constraints for the bubble. This would make it easy to decide which side of the screen to align to. You could also use autolayout for the width parameter, using a multiplier based on parent view width to make it cope with any size screen.

I'm not going to work it into your code as it would be too long, but hopefully the below example function will show the principles I'd recommend:

   func addBubble(alignLeft: Bool, offset: CGFloat) {
let bubble = UIView()
bubble.backgroundColor = .systemBlue
let parentView = view.safeAreaLayoutGuide //your parent view may be different
parentView.addSubview(bubble)

bubble.translatesAutoresizingMaskIntoConstraints = false

//quick and dirty top and bottom constraints for the example
bubble.topAnchor.constraint(equalTo: parentView.topAnchor, constant: 10 + offset).isActive = true
bubble.bottomAnchor.constraint(equalTo: parentView.topAnchor, constant: 40 + offset).isActive = true

//set the width of the bubble proportional to the size of the parent view
bubble.widthAnchor.constraint(equalTo: parentView.widthAnchor, multiplier: 2/3).isActive = true

// implement the left or right alignment
if alignLeft {
bubble.leadingAnchor.constraint(equalTo: parentView.leadingAnchor, constant: 4).isActive = true
} else {
bubble.trailingAnchor.constraint(equalTo: parentView.trailingAnchor, constant: -4).isActive = true
}
}

This way all you have to do is anchor the bubble's sub views to the bubbles top/bottom/leading/trailing constraints and they will also resize with the bubble to cope with all screen sizes.

Autolayout of custom UITableViewCell finds conflicting constraints in Swift 5

It seems to be a common issue.

While the constraints may be correct, auto-layout generates that warning while making adjustments to the cell height.

Changing the Priority of your stack view's Height constraint to 999 should resolve the issue.


Edit

Here is an example - layout should be close to what you've shown.

I gave each image view a width of 30 and 1:1 ratio.

I gave the "Outer" stack view a height constraint of 75, but note that instead of setting its priority to 999, I set its bottom constraint to greater than or equal to 8. That also eliminates the run-time layout issues, and also lets me work on the cell design without having to worry about Interface Builder complaining about the cell height.

So, at run-time, the actual cell height will be 75 plus 8-pts top and bottom "padding."

Sample Image

and here's how it looks at run-time:

Sample Image

This is the code I used:

class RegistrationCell: UITableViewCell {

@IBOutlet var lblName: UILabel!
@IBOutlet var lblAge: UILabel!
@IBOutlet var lblGender: UILabel!
@IBOutlet var lblWeight: UILabel!

}

struct Benutzer {
var name: String = ""
var age: Int = 0
var gender: Int = 0
var weight: Float = 0.0
}

class RegistrationTableViewController: UITableViewController {

var myData: [Benutzer] = [
Benutzer(name: "Christian", age: 24, gender: 0, weight: 81.0),
Benutzer(name: "Tobias", age: 25, gender: 0, weight: 83.5),
Benutzer(name: "Astrid", age: 22, gender: 1, weight: 50.0),
Benutzer(name: "Frank", age: 26, gender: 0, weight: 82.0),
Benutzer(name: "Birgit", age: 21, gender: 1, weight: 49.5),
Benutzer(name: "Petra", age: 23, gender: 1, weight: 48.0),
]

override func viewDidLoad() {
super.viewDidLoad()

tableView.register(UINib(nibName: "RegistrationCell", bundle: nil), forCellReuseIdentifier: "Cell")

}

override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}

override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return myData.count
}

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as! RegistrationCell

let d = myData[indexPath.row]
cell.lblName.text = d.name
cell.lblAge.text = "\(d.age)"
cell.lblGender.text = d.gender == 0 ? "M" : "F"
cell.lblWeight.text = "\(d.weight)"

return cell
}

}

and here's the source for my RegistrationCell.xib file:

<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="15705" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
<device id="retina6_1" orientation="portrait" appearance="light"/>
<dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="15706"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" rowHeight="123" id="7Ao-kn-tXV" customClass="RegistrationCell" customModule="MiniScratch" customModuleProvider="target">
<rect key="frame" x="0.0" y="0.0" width="414" height="123"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="7Ao-kn-tXV" id="47R-qN-jmt">
<rect key="frame" x="0.0" y="0.0" width="414" height="123"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" distribution="fillEqually" translatesAutoresizingMaskIntoConstraints="NO" id="w3y-Sd-Nos" userLabel="OuterStack">
<rect key="frame" x="8" y="8" width="398" height="75"/>
<subviews>
<stackView opaque="NO" contentMode="scaleToFill" alignment="center" spacing="12" translatesAutoresizingMaskIntoConstraints="NO" id="wyp-v1-tmD" userLabel="NameStack">
<rect key="frame" x="0.0" y="0.0" width="398" height="37.5"/>
<subviews>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="person" catalog="system" translatesAutoresizingMaskIntoConstraints="NO" id="Fjj-yM-fPo" userLabel="img Profile Image">
<rect key="frame" x="0.0" y="5.5" width="30" height="27.5"/>
<color key="tintColor" white="0.0" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstAttribute="width" constant="30" id="GMk-hN-m2Y"/>
<constraint firstAttribute="width" secondItem="Fjj-yM-fPo" secondAttribute="height" multiplier="1:1" id="twh-eK-7fi"/>
</constraints>
</imageView>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Neuer Benutzer" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="7L6-cN-3lF">
<rect key="frame" x="42" y="5.5" width="314" height="26.5"/>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<fontDescription key="fontDescription" type="system" weight="semibold" pointSize="22"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="checkmark.seal.fill" catalog="system" translatesAutoresizingMaskIntoConstraints="NO" id="2LH-yE-mwq" userLabel="img Active">
<rect key="frame" x="368" y="3.5" width="30" height="31.5"/>
<color key="tintColor" white="0.0" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstAttribute="width" constant="30" id="Ar9-oX-QRg"/>
<constraint firstAttribute="width" secondItem="2LH-yE-mwq" secondAttribute="height" multiplier="1:1" id="iIC-xx-qUj"/>
</constraints>
</imageView>
</subviews>
</stackView>
<stackView opaque="NO" contentMode="scaleToFill" distribution="fillEqually" spacing="23" translatesAutoresizingMaskIntoConstraints="NO" id="moe-fr-waY" userLabel="LowerStack">
<rect key="frame" x="0.0" y="37.5" width="398" height="37.5"/>
<subviews>
<stackView opaque="NO" contentMode="scaleToFill" alignment="center" spacing="12" translatesAutoresizingMaskIntoConstraints="NO" id="p9M-2u-yIn" userLabel="AgeStack">
<rect key="frame" x="0.0" y="0.0" width="117.5" height="37.5"/>
<subviews>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="calendar" catalog="system" translatesAutoresizingMaskIntoConstraints="NO" id="JLv-Bq-0aO">
<rect key="frame" x="0.0" y="5" width="30" height="27.5"/>
<color key="tintColor" white="0.0" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstAttribute="width" constant="30" id="329-R5-jp7"/>
<constraint firstAttribute="width" secondItem="JLv-Bq-0aO" secondAttribute="height" multiplier="1:1" id="FCZ-nk-tMN"/>
</constraints>
</imageView>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="WG8-WN-s2X">
<rect key="frame" x="42" y="8.5" width="75.5" height="20.5"/>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
</subviews>
</stackView>
<stackView opaque="NO" contentMode="scaleToFill" alignment="center" spacing="12" translatesAutoresizingMaskIntoConstraints="NO" id="tfc-eV-c24" userLabel="GenderStack">
<rect key="frame" x="140.5" y="0.0" width="117" height="37.5"/>
<subviews>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="person.2.square.stack.fill" catalog="system" translatesAutoresizingMaskIntoConstraints="NO" id="VQ9-tf-mkF">
<rect key="frame" x="0.0" y="3" width="30" height="31.5"/>
<color key="tintColor" white="0.0" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstAttribute="width" constant="30" id="1xw-b0-vZp"/>
<constraint firstAttribute="width" secondItem="VQ9-tf-mkF" secondAttribute="height" multiplier="1:1" id="zmL-Jl-F55"/>
</constraints>
</imageView>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="tg8-Bx-TWD">
<rect key="frame" x="42" y="8.5" width="75" height="20.5"/>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
</subviews>
</stackView>
<stackView opaque="NO" contentMode="scaleToFill" alignment="center" spacing="12" translatesAutoresizingMaskIntoConstraints="NO" id="9bU-4J-00h" userLabel="WeightStack">
<rect key="frame" x="280.5" y="0.0" width="117.5" height="37.5"/>
<subviews>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="gauge" catalog="system" translatesAutoresizingMaskIntoConstraints="NO" id="uXN-UL-NhM">
<rect key="frame" x="0.0" y="4.5" width="30" height="29"/>
<color key="tintColor" white="0.0" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstAttribute="width" constant="30" id="3dU-2L-zOp"/>
<constraint firstAttribute="width" secondItem="uXN-UL-NhM" secondAttribute="height" multiplier="1:1" id="xI1-Qm-Vr5"/>
</constraints>
</imageView>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Wwy-kf-N2Z">
<rect key="frame" x="42" y="8.5" width="75.5" height="20.5"/>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
</subviews>
</stackView>
</subviews>
</stackView>
</subviews>
<constraints>
<constraint firstAttribute="height" constant="75" id="jPs-ix-1GZ"/>
</constraints>
</stackView>
</subviews>
<color key="backgroundColor" red="0.99996358159999998" green="0.77101260419999995" blue="0.16773471240000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstItem="w3y-Sd-Nos" firstAttribute="leading" secondItem="47R-qN-jmt" secondAttribute="leading" constant="8" id="ba9-oa-K7s"/>
<constraint firstItem="w3y-Sd-Nos" firstAttribute="top" secondItem="47R-qN-jmt" secondAttribute="top" constant="8" id="hO0-zC-Vbj"/>
<constraint firstAttribute="trailing" secondItem="w3y-Sd-Nos" secondAttribute="trailing" constant="8" id="s1f-TA-lYa"/>
<constraint firstAttribute="bottom" relation="greaterThanOrEqual" secondItem="w3y-Sd-Nos" secondAttribute="bottom" constant="8" id="ypb-vP-adn"/>
</constraints>
</tableViewCellContentView>
<connections>
<outlet property="lblAge" destination="WG8-WN-s2X" id="WBO-bZ-8SE"/>
<outlet property="lblGender" destination="tg8-Bx-TWD" id="bTQ-bI-zSz"/>
<outlet property="lblName" destination="7L6-cN-3lF" id="scr-s2-IiF"/>
<outlet property="lblWeight" destination="Wwy-kf-N2Z" id="3pY-yL-8Ys"/>
</connections>
<point key="canvasLocation" x="-252.17391304347828" y="53.236607142857139"/>
</tableViewCell>
</objects>
<resources>
<image name="calendar" catalog="system" width="64" height="52"/>
<image name="checkmark.seal.fill" catalog="system" width="64" height="60"/>
<image name="gauge" catalog="system" width="64" height="60"/>
<image name="person" catalog="system" width="64" height="58"/>
<image name="person.2.square.stack.fill" catalog="system" width="56" height="64"/>
</resources>
</document>


Related Topics



Leave a reply



Submit