0

I have a UITableView with a customized UITableViewCell (to be very specific it's a SwipeTableViewCell). I have a nib file where i layed out the (reuseable) cell. All works as expected and look fine on my devices. As I was finalizing the app, I noticed that I didn't have constraints on the customized view (the constraints in the other views work just fine). So, after adding the missing constraints, I ran the app. All of the fields (4 UITextFields, 2 UIImageViews) get "sqeezed" at the top-left of the cell. I assumed that I did something wrong...deleted all those constraint...re-ran, and again it looked good. Upon re-adding constraints back the same thing happened. I have spent a couple of days trying to discover what I am doing wrong (this is my first customized cell). I found one SO item: Autolayout is ignored in Custom UITableViewCell
that looks and sounded spot on, but it doesn't match what I've got and did not solve my issue. I've also tried not using a nib, but directly adding the textfields and imageviews to the prototype cell...unfortunately with the same results. I've been thru many tutorials, but none address my issue. Help!!

class EducationTableViewController: SwipeTableViewController {
    ...
    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = super.tableView(tableView, cellForRowAt: indexPath) as! EducationTableCell

        let education = educations[indexPath.row]
        cell.configurateTheCell(education)
        
        return cell
    }
    ...
}   

and

class EducationTableCell: SwipeTableViewCell {
    
    @IBOutlet weak var classNameLabel: UILabel!

    override func prepareForReuse() {
        super.prepareForReuse()
        
        classNameLabel.text = nil
    }
    
    // MARK: Cell Configuration
    func configurateTheCell(_ education: Education) {
        Bundle.main.loadNibNamed("Education", owner: self, options: nil)

        backgroundColor = UIColor(hexString: education.color)
        let contrastingBgColor = UIColor.init(contrastingBlackOrWhiteColorOn: backgroundColor, isFlat: false)
        
        classNameLabel.text = education.name
        if (contrastingBgColor == UIColor.init(red: 0, green: 0, blue: 0, alpha: 1)) {
            classNameLabel.textColor = K.Education.titleTextColor
        } else {
            classNameLabel.textColor = UIColor.yellow
        }
        classNameLabel.font = UIFont(name: K.UIConstants.fontNameBold, size: 35)
        contentView.addSubview(classNameLabel)
        ...
      }
}

I added constraints to the nib in Storyboard. If you look at the SO item above, you will see the "squeeze" i mentioned, but I am happy to attach a pic if that helps.

pic https://sites.google.com/view/schoolscheduler/home/junk

iOS: 14.3 Xcode: 12.3 Swift 5.3.2

David M
  • 2,511
  • 1
  • 15
  • 18
  • The little bit of code you've posted looks wrong. If you create a nib/xib file for your cell, there is no reason to be calling `.loadNibNamed` (unless you're loading another nib view there?). Also, if you've designed your cell in IB, why are you adding `classNameLabel` as a subview at run-time? – DonMag Dec 19 '20 at 14:02
  • hmmm. i think this was left over from when i had the views in the prototype cell. lemme make a change and repost the code. – David M Dec 20 '20 at 11:26
  • well, if i omit the .loadNibNamed() then there is nothing in the table. i *had* designed the cell in IB, but removed that to the nib when it didn't work (the views also "squeezed" when constraints were applied). i'll post a pic of what i have in IB, perhaps making it clearer. – David M Dec 20 '20 at 11:50
  • Hmmm... a bit confusing. Do you *want* to design your cell in a xib? Or as a Storyboard Prototype? – DonMag Dec 20 '20 at 13:31
  • well, I just want it to work! ;-). I switched back to IB, have layed out the cell...looks good until i add the first constraint, then everything moves to the upper left of the cell (i.e. squeezed). Googling around i found: https://medium.com/better-programming/how-to-create-custom-uitableviewcell-f4e69193bab, which i cloned and installed....looks good. i'm still trying to see what they do that i don't. – David M Dec 20 '20 at 14:08
  • added a couple more image to https://sites.google.com/view/schoolscheduler/home/junk, one showing the layout (in the prototype cell) and the constraints. – David M Dec 20 '20 at 14:15

1 Answers1

0

Based on the images you've shown, you're doing a few things wrong.

First, for your attempt with a XIB, you've used a UIView in the xib. It should be a UITableViewCell.

Second, the prototype layout... most of it looks correct (ish). You've given Class Name Label leading and trailing constraints and a centerX constraint. The centerX constraint doesn't do anything, because the label will already stretch to the leading and trailing values. Also, your Stack View leading constraint should probably be relative to the trailing edge of the Star Image View, not to the leading of the cell.

Look at the constraints shown here:

enter image description here

The cell shows as "cell" because that's the Reuse Identifier I've given it, but the Custom Class is set to EducationTableCell.

The output looks like this:

enter image description here

Here is example code to produce that output:

import UIKit

class EducationTableCell: UITableViewCell {
    
    @IBOutlet var className: UILabel!
    @IBOutlet var classLocation: UILabel!
    @IBOutlet var classDays: UILabel!
    @IBOutlet var classTime: UILabel!
    
    @IBOutlet var starImageView: UIImageView!
    @IBOutlet var itemImageView: UIImageView!
    
}

class EducationTableViewController: UITableViewController {

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

    // MARK: - Table view data source

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

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

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

        cell.className.text = "Name \(indexPath.row)"
        cell.classLocation.text = "Location \(indexPath.row)"
        cell.classDays.text = "Days \(indexPath.row)"
        cell.classTime.text = "Time \(indexPath.row)"

        return cell
    }

}

and here is the source for the Storyboard so you can inspect the layout constraints:

<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="17506" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="Rco-aF-G6p">
    <device id="retina4_7" orientation="portrait" appearance="light"/>
    <dependencies>
        <deployment identifier="iOS"/>
        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="17506"/>
        <capability name="System colors in document resources" minToolsVersion="11.0"/>
        <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
    </dependencies>
    <scenes>
        <!--Education Table View Controller-->
        <scene sceneID="0rL-fH-xZI">
            <objects>
                <tableViewController id="Rco-aF-G6p" customClass="EducationTableViewController" customModule="PanZoom" customModuleProvider="target" sceneMemberID="viewController">
                    <tableView key="view" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="default" rowHeight="-1" estimatedRowHeight="-1" sectionHeaderHeight="28" sectionFooterHeight="28" id="Nk0-AL-MEx">
                        <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
                        <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
                        <color key="backgroundColor" systemColor="systemBackgroundColor"/>
                        <prototypes>
                            <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" reuseIdentifier="cell" rowHeight="138" id="SUJ-72-5Po" customClass="EducationTableCell" customModule="PanZoom" customModuleProvider="target">
                                <rect key="frame" x="0.0" y="28" width="375" height="138"/>
                                <autoresizingMask key="autoresizingMask"/>
                                <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="SUJ-72-5Po" id="G9i-wf-fpQ">
                                    <rect key="frame" x="0.0" y="0.0" width="375" height="138"/>
                                    <autoresizingMask key="autoresizingMask"/>
                                    <subviews>
                                        <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="className" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="mVQ-Zs-26O">
                                            <rect key="frame" x="21" y="16" width="333" height="20.5"/>
                                            <color key="backgroundColor" red="0.99953407049999998" green="0.98835557699999999" blue="0.47265523669999998" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
                                            <fontDescription key="fontDescription" type="system" pointSize="17"/>
                                            <nil key="textColor"/>
                                            <nil key="highlightedColor"/>
                                        </label>
                                        <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="3yA-G1-vya">
                                            <rect key="frame" x="21" y="56.5" width="50" height="50"/>
                                            <color key="backgroundColor" red="1" green="0.14913141730000001" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
                                            <constraints>
                                                <constraint firstAttribute="width" constant="50" id="TjC-BK-Udr"/>
                                                <constraint firstAttribute="width" secondItem="3yA-G1-vya" secondAttribute="height" multiplier="1:1" id="vWg-SJ-7vR"/>
                                            </constraints>
                                        </imageView>
                                        <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="cs2-jh-xoS">
                                            <rect key="frame" x="324" y="71.5" width="30" height="30"/>
                                            <color key="backgroundColor" red="1" green="0.14913141730000001" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
                                            <constraints>
                                                <constraint firstAttribute="width" constant="30" id="ndl-Lm-Bz0"/>
                                                <constraint firstAttribute="width" secondItem="cs2-jh-xoS" secondAttribute="height" multiplier="1:1" id="oHy-eo-dLd"/>
                                            </constraints>
                                        </imageView>
                                        <stackView opaque="NO" contentMode="scaleToFill" axis="vertical" spacing="6" translatesAutoresizingMaskIntoConstraints="NO" id="tgj-yg-vqL">
                                            <rect key="frame" x="81" y="46.5" width="233" height="73.5"/>
                                            <subviews>
                                                <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="classLocation" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="axi-2z-HNT">
                                                    <rect key="frame" x="0.0" y="0.0" width="233" height="20.5"/>
                                                    <color key="backgroundColor" red="0.55634254220000001" green="0.97934550050000002" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
                                                    <fontDescription key="fontDescription" type="system" pointSize="17"/>
                                                    <nil key="textColor"/>
                                                    <nil key="highlightedColor"/>
                                                </label>
                                                <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="classDays" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="UK3-x3-XGT">
                                                    <rect key="frame" x="0.0" y="26.5" width="233" height="20.5"/>
                                                    <color key="backgroundColor" red="0.55634254220000001" green="0.97934550050000002" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
                                                    <fontDescription key="fontDescription" type="system" pointSize="17"/>
                                                    <nil key="textColor"/>
                                                    <nil key="highlightedColor"/>
                                                </label>
                                                <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="classTime" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="tqR-li-CIc">
                                                    <rect key="frame" x="0.0" y="53" width="233" height="20.5"/>
                                                    <color key="backgroundColor" red="0.55634254220000001" green="0.97934550050000002" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
                                                    <fontDescription key="fontDescription" type="system" pointSize="17"/>
                                                    <nil key="textColor"/>
                                                    <nil key="highlightedColor"/>
                                                </label>
                                            </subviews>
                                        </stackView>
                                    </subviews>
                                    <constraints>
                                        <constraint firstAttribute="bottomMargin" relation="greaterThanOrEqual" secondItem="tgj-yg-vqL" secondAttribute="bottom" constant="5" id="0xW-En-RuB"/>
                                        <constraint firstItem="3yA-G1-vya" firstAttribute="top" secondItem="mVQ-Zs-26O" secondAttribute="bottom" constant="20" id="38Z-Q2-z0J"/>
                                        <constraint firstItem="mVQ-Zs-26O" firstAttribute="leading" secondItem="G9i-wf-fpQ" secondAttribute="leadingMargin" constant="5" id="3J5-7X-0l3"/>
                                        <constraint firstItem="cs2-jh-xoS" firstAttribute="leading" secondItem="tgj-yg-vqL" secondAttribute="trailing" constant="10" id="7TA-sg-Zod"/>
                                        <constraint firstItem="mVQ-Zs-26O" firstAttribute="top" secondItem="G9i-wf-fpQ" secondAttribute="topMargin" constant="5" id="8Hh-cA-6Se"/>
                                        <constraint firstItem="3yA-G1-vya" firstAttribute="leading" secondItem="G9i-wf-fpQ" secondAttribute="leadingMargin" constant="5" id="R99-Wc-e7A"/>
                                        <constraint firstAttribute="trailingMargin" secondItem="cs2-jh-xoS" secondAttribute="trailing" constant="5" id="TZq-bM-V5Q"/>
                                        <constraint firstAttribute="trailingMargin" secondItem="mVQ-Zs-26O" secondAttribute="trailing" constant="5" id="YaH-eA-zBR"/>
                                        <constraint firstItem="cs2-jh-xoS" firstAttribute="top" secondItem="mVQ-Zs-26O" secondAttribute="bottom" constant="35" id="YcB-tX-G3j"/>
                                        <constraint firstItem="tgj-yg-vqL" firstAttribute="top" secondItem="mVQ-Zs-26O" secondAttribute="bottom" constant="10" id="r6S-UG-b0o"/>
                                        <constraint firstItem="tgj-yg-vqL" firstAttribute="leading" secondItem="3yA-G1-vya" secondAttribute="trailing" constant="10" id="xdc-Jv-acQ"/>
                                    </constraints>
                                </tableViewCellContentView>
                                <connections>
                                    <outlet property="classDays" destination="UK3-x3-XGT" id="3b4-tW-ATv"/>
                                    <outlet property="classLocation" destination="axi-2z-HNT" id="59P-Dm-VIx"/>
                                    <outlet property="className" destination="mVQ-Zs-26O" id="SaH-dm-Gxi"/>
                                    <outlet property="classTime" destination="tqR-li-CIc" id="FNG-WI-vOC"/>
                                    <outlet property="itemImageView" destination="cs2-jh-xoS" id="MKG-Dz-kFh"/>
                                    <outlet property="starImageView" destination="3yA-G1-vya" id="dDq-hC-USx"/>
                                </connections>
                            </tableViewCell>
                        </prototypes>
                        <connections>
                            <outlet property="dataSource" destination="Rco-aF-G6p" id="Ear-AM-DTS"/>
                            <outlet property="delegate" destination="Rco-aF-G6p" id="DsX-fk-NBi"/>
                        </connections>
                    </tableView>
                </tableViewController>
                <placeholder placeholderIdentifier="IBFirstResponder" id="ujd-EG-Zzl" userLabel="First Responder" customClass="UIResponder" sceneMemberID="firstResponder"/>
            </objects>
            <point key="canvasLocation" x="284" y="174.96251874062969"/>
        </scene>
    </scenes>
    <resources>
        <systemColor name="systemBackgroundColor">
            <color white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
        </systemColor>
    </resources>
</document>
DonMag
  • 69,424
  • 5
  • 50
  • 86
  • Thanks. Will try in a few minutes. Wanted to say that the "classStarImage" doesn't always appear (only when the underlying record changes) therefore the "ClassInfo Stack View" probably cannot be tied to it. I'll try it both ways and let you know. – David M Dec 20 '20 at 15:04
  • You may not believe this, but your simple code doesn't work for me. It's too EZ to fail, but i get all the subViews "squeezed" into the upper left. I've stared at it for awhile, but don't see how i messed this up. https://github.com/davidhmobley/TestSchoolItems. I thought for a second it might have something to do with my new macbook (silicon), so i tried it on my 5-year-old macbook...didn't make a difference (luckily). I'll keep looking. – David M Dec 20 '20 at 21:15
  • A Breakthru!!!! i just noticed on the Github project that the "recommended" rowHeight was 198...i had set it to, i think, 130. When i reset it to 200, it rendered fine. Now back to my "real" project. If it works (which i think it will), i'll ACCEPT your answer. – David M Dec 20 '20 at 21:22
  • @DavidM - the "recommended" row height doesn't matter. I see in your GitHub project that you also have the line `tableView.rowHeight = 150` which is not needed. I also noticed in your project that you have the cell's `Content View` set to the same class as the Cell - which is almost certainly what was causing your problem. – DonMag Dec 20 '20 at 22:56
  • @DavidM - if you are going to only *sometimes* show the star image view, your best approach is probably to put `starImageView`, `classInfoStackView` and `itemImageView` in a horizontal stack view. Then you can set `.isHidden` on the star image view --- unless you want blank space there, in which case leave it as-is (and still use the `.isHidden` property to show/hide it). – DonMag Dec 20 '20 at 22:59
  • Removing the EducationTableCell from the cell's ContentView did the trick!!!! dunno how i ended up specifying that, clearly an error. Thanks a million!! – David M Dec 21 '20 at 11:47