Here I have a TableView with custom cells containing text and images, the main image sits in a stack view which is pinned to the top.
When the image is set to aspect fill
it looks ok - the top of the image is also at the top of its space - level with the text (see screenshot).
However the images are too big - to solve this I tried switching to aspect fit
. The images then are a better size, but there are big gaps the top and bottom of the cell as if the image was still full size. It feels as if the row height is being set based on the image's original size before it gets changed. Aspect fit
looks like this:
The tableview rows are set to expand as needed according to optional text which can be displayed at the foot of the cell, but I don't think this is key to the issue.
e.g. the TableViewController includes:
tableView.estimatedRowHeight = 150
tableView.rowHeight = UITableView.automaticDimension
For completeness here is the structure and accompanying constraints:
A UIStackView
can be used in various ways, but essentially it either:
So, from what you've shown, it looks like you want your horizontal "top section" to be 50% image and 50% headline-time-logo?
So, we start with constraining that stack view's leading and trailing (to define its width) and setting the Distribution for that stack view to "Fill Equally" -- but, because the left-side is a UIImageView
, without an additional constraint it will adjust its height to the height of the image... which we don't want.
We'll likely get images of various sizes and aspect ratios. To get an "overall" good look, we can give that image view an Aspect Ratio constraint of 3:2
and set its Content Mode to either Aspect Fit
- which will end up "letter-boxed" if the image does not have a 3:2
ratio - or Aspect Fill
- which will "clip" the sides or top/bottom. Aspect Fill
will probably be the better choice.
You don't show what's below (buttons and description), but you'll probably want to use a vertical "outer stack view" to arrange those elements as well.
So, here's a sample layout:
The stack views have these properties...
OuterStackView
TopStackView
RightStackView
TimeLogoStackView
Two items that are not obvious:
1 - the OuterStackView has a bottom constraint with a Priority of 999
. That prevents auto-layout complaints at run-time, and
2 - the "Time" label has Content Compression Resistance Priority set to Required (1000)
to prevent it from being "squeezed":
You will probably want to "tweak" some of the values (spacing, etc) to get your exact desired layout, but this should get you close.
Here is the Storyboard source for that layout so you can inspect everything:
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="17701" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
<device id="retina4_7" orientation="portrait" appearance="light"/>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="17703"/>
<capability name="System colors in document resources" minToolsVersion="11.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<scenes>
<!--Table View Controller-->
<scene sceneID="VSk-CA-kDJ">
<objects>
<tableViewController id="kTW-th-aXp" 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="8wi-Zy-dI1">
<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" rowHeight="284" id="cWZ-Hx-Mr4">
<rect key="frame" x="0.0" y="28" width="375" height="284"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="cWZ-Hx-Mr4" id="Npw-Cx-NLg">
<rect key="frame" x="0.0" y="0.0" width="375" height="284"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" spacing="8" translatesAutoresizingMaskIntoConstraints="NO" id="gNf-7h-70l" userLabel="OuterStackView">
<rect key="frame" x="8" y="8" width="359" height="268"/>
<subviews>
<stackView opaque="NO" contentMode="scaleToFill" distribution="fillEqually" alignment="top" spacing="4" translatesAutoresizingMaskIntoConstraints="NO" id="qfh-3q-dxE" userLabel="TopStackView">
<rect key="frame" x="0.0" y="0.0" width="359" height="128.5"/>
<subviews>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="DebHaaland" translatesAutoresizingMaskIntoConstraints="NO" id="6u7-ig-6GL" userLabel="Article Image">
<rect key="frame" x="0.0" y="0.0" width="177.5" height="118.5"/>
<color key="backgroundColor" red="1" green="0.14913141730000001" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstAttribute="width" secondItem="6u7-ig-6GL" secondAttribute="height" multiplier="3:2" id="Jah-9w-tPO"/>
</constraints>
</imageView>
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" spacing="4" translatesAutoresizingMaskIntoConstraints="NO" id="5cg-eC-vi9" userLabel="RightStackView">
<rect key="frame" x="181.5" y="0.0" width="177.5" height="106"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Deb Haaland confirmed as first-ever Native American US cabinet secretary" textAlignment="natural" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Jre-1x-Jqv" userLabel="Headline">
<rect key="frame" x="0.0" y="0.0" width="177.5" height="76.5"/>
<fontDescription key="fontDescription" type="system" weight="light" pointSize="16"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
<stackView opaque="NO" contentMode="scaleToFill" spacing="2" translatesAutoresizingMaskIntoConstraints="NO" id="1rD-Xm-5YT" userLabel="TimeLogoStackView">
<rect key="frame" x="0.0" y="80.5" width="177.5" height="25.5"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" horizontalCompressionResistancePriority="1000" text="30 minutes ago" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="0Rx-2c-SNK" userLabel="Time">
<rect key="frame" x="0.0" y="0.0" width="87" height="25.5"/>
<fontDescription key="fontDescription" type="system" weight="light" pointSize="12"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="f24logo" translatesAutoresizingMaskIntoConstraints="NO" id="lbn-Uc-VHY" userLabel="Logo">
<rect key="frame" x="89" y="0.0" width="88.5" height="25.5"/>
<constraints>
<constraint firstAttribute="width" secondItem="lbn-Uc-VHY" secondAttribute="height" multiplier="420:120" id="nGJ-ou-v3G"/>
</constraints>
</imageView>
</subviews>
</stackView>
</subviews>
</stackView>
</subviews>
</stackView>
<stackView opaque="NO" contentMode="scaleToFill" distribution="fillEqually" spacing="8" translatesAutoresizingMaskIntoConstraints="NO" id="IWg-Gv-dfU" userLabel="Buttons Stack View">
<rect key="frame" x="0.0" y="136.5" width="359" height="30"/>
<subviews>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="ovM-SW-tOX">
<rect key="frame" x="0.0" y="0.0" width="84" height="30"/>
<state key="normal" title="Button"/>
</button>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="BGE-T6-Y7H">
<rect key="frame" x="92" y="0.0" width="83.5" height="30"/>
<state key="normal" title="Button"/>
</button>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="hgu-1h-hdf">
<rect key="frame" x="183.5" y="0.0" width="84" height="30"/>
<state key="normal" title="Button"/>
</button>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="8wq-fU-hTM">
<rect key="frame" x="275.5" y="0.0" width="83.5" height="30"/>
<state key="normal" title="Button"/>
</button>
</subviews>
</stackView>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" textAlignment="natural" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="2hh-vS-zmg" userLabel="Description">
<rect key="frame" x="0.0" y="174.5" width="359" height="93.5"/>
<string key="text">Lorem ipsum dolor sit er elit lamet, consectetaur cillium adipisicing pecu, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.</string>
<fontDescription key="fontDescription" type="system" weight="light" pointSize="13"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
</subviews>
</stackView>
</subviews>
<constraints>
<constraint firstItem="gNf-7h-70l" firstAttribute="leading" secondItem="Npw-Cx-NLg" secondAttribute="leading" constant="8" id="5cg-Qd-M8w"/>
<constraint firstAttribute="trailing" secondItem="gNf-7h-70l" secondAttribute="trailing" constant="8" id="Aru-zO-BJc"/>
<constraint firstItem="gNf-7h-70l" firstAttribute="top" secondItem="Npw-Cx-NLg" secondAttribute="top" constant="8" id="fej-fk-c8x"/>
<constraint firstAttribute="bottom" secondItem="gNf-7h-70l" secondAttribute="bottom" priority="999" constant="8" id="r6d-qb-Wn1"/>
</constraints>
</tableViewCellContentView>
</tableViewCell>
</prototypes>
<connections>
<outlet property="dataSource" destination="kTW-th-aXp" id="nPX-e7-JuK"/>
<outlet property="delegate" destination="kTW-th-aXp" id="hKn-OZ-zAe"/>
</connections>
</tableView>
</tableViewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="k0k-be-VUx" userLabel="First Responder" customClass="UIResponder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="357.60000000000002" y="137.18140929535232"/>
</scene>
</scenes>
<resources>
<image name="DebHaaland" width="512" height="342"/>
<image name="f24logo" width="420" height="120"/>
<systemColor name="systemBackgroundColor">
<color white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
</systemColor>
</resources>
</document>
I used these two images: