Expand Tableview and Increase Scrollview Content Size by an Appropriate Difference on Clicking a Button Inside a Table Cell

contentView with UITableView not scrolling within UIScrollView

Here is a basic example, using a "self-sizing" table view. No need for heightForRowAt or explicit setting of .contentSize -- it's all handled by auto-layout and constraints.

With a couple rows (nothing scrolls):

Sample Image

With a couple more rows (still, nothing scrolls):

Sample Image

And now with enough rows the we need scrolling:

Sample Image

This is how it's setup in IB / Storyboard:

Sample Image

Here is the source code:

//
// DaveViewController.swift
//
// Created by Don Mag on 7/1/19.
//

import UIKit

final class ContentSizedTableView: UITableView {
override var contentSize:CGSize {
didSet {
invalidateIntrinsicContentSize()
}
}
override var intrinsicContentSize: CGSize {
layoutIfNeeded()
return CGSize(width: UIView.noIntrinsicMetric, height: contentSize.height)
}
}

class DaveCell: UITableViewCell {
@IBOutlet var theLabel: UILabel!
@IBOutlet var theTextField: UITextField!
}

class DaveViewController: UIViewController {

@IBOutlet var theTableView: ContentSizedTableView!
@IBOutlet var theScrollView: UIScrollView!

let theLabels: [String] = [
"NAME",
"COMPANY",
"POSITION",
"CITY, STATE",
"EMAIL ADDRESS",
"ADDTL EMAIL\nADDRESS",
"WORK NUMBER",
"CELL NUMBER",
]

let thePlaceholders: [String] = [
"your name",
"e.g. Bizee Inc.",
"e.g. Regional Manager",
"e.g. Denver, Colorado",
"name@email.com",
"name@email.com",
"(XXX) XXX-XXXX",
"(XXX) XXX-XXXX",
]

override func viewDidLoad() {
super.viewDidLoad()

theTableView.dataSource = self
theTableView.delegate = self

theTableView.isScrollEnabled = false

NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow), name: UIResponder.keyboardWillShowNotification, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide), name: UIResponder.keyboardWillHideNotification, object: nil)

// add a "Done" button to dismiss the keyboard
let doneBtn = UIBarButtonItem(barButtonSystemItem: .done, target: self, action: #selector(doneTapped))
self.navigationItem.rightBarButtonItem = doneBtn
}

@objc private func doneTapped() {
view.endEditing(true)
}

@objc private func keyboardWillShow(notification: NSNotification){
guard let keyboardFrame = notification.userInfo![UIResponder.keyboardFrameEndUserInfoKey] as? NSValue else { return }
theScrollView.contentInset.bottom = view.convert(keyboardFrame.cgRectValue, from: nil).size.height
}

@objc private func keyboardWillHide(notification: NSNotification){
theScrollView.contentInset.bottom = 0
}

}

extension DaveViewController: UITableViewDataSource, UITableViewDelegate {

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

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

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

cell.theLabel.text = theLabels[indexPath.row]
cell.theTextField.placeholder = thePlaceholders[indexPath.row]

cell.selectionStyle = .none

return cell
}

}

and here is the Storyboard source:

<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="14460.31" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="OCG-fk-O07">
<device id="retina4_7" orientation="portrait">
<adaptation id="fullscreen"/>
</device>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14460.20"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<scenes>
<!--Dave View Controller-->
<scene sceneID="gYy-6C-lIo">
<objects>
<viewController id="ByF-jo-q34" customClass="DaveViewController" customModule="LaunchTest2" customModuleProvider="target" sceneMemberID="viewController">
<view key="view" contentMode="scaleToFill" id="KzY-ir-ZNp">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<scrollView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="sfU-bN-guh">
<rect key="frame" x="0.0" y="64" width="375" height="603"/>
<subviews>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="SCY-zE-Vif">
<rect key="frame" x="0.0" y="0.0" width="375" height="603"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Import Using LinkedIn" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="kg2-26-RDd">
<rect key="frame" x="104" y="12" width="167.5" height="20.5"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="d56-0u-ihe">
<rect key="frame" x="0.0" y="44.5" width="375" height="102.5"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Choose Profile Photo" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="8zb-Kb-NJY">
<rect key="frame" x="108" y="20" width="159.5" height="20.5"/>
<fontDescription key="fontDescription" type="system" weight="thin" pointSize="17"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
<stackView opaque="NO" contentMode="scaleToFill" distribution="fillEqually" spacing="6" translatesAutoresizingMaskIntoConstraints="NO" id="KiU-vK-XXr">
<rect key="frame" x="12" y="50.5" width="351" height="32"/>
<subviews>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="7Ri-fC-xIB">
<rect key="frame" x="0.0" y="0.0" width="172.5" height="32"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<fontDescription key="fontDescription" type="system" weight="thin" pointSize="16"/>
<state key="normal" title="Use Camera">
<color key="titleColor" white="0.0" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
</state>
</button>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="RYr-md-Xbc">
<rect key="frame" x="178.5" y="0.0" width="172.5" height="32"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<fontDescription key="fontDescription" type="system" weight="thin" pointSize="16"/>
<state key="normal" title="Use Photo Library">
<color key="titleColor" white="0.0" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
</state>
</button>
</subviews>
</stackView>
</subviews>
<color key="backgroundColor" red="0.91764705882352937" green="0.91764705882352937" blue="0.91764705882352937" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstItem="8zb-Kb-NJY" firstAttribute="centerX" secondItem="d56-0u-ihe" secondAttribute="centerX" id="Ipm-mu-u52"/>
<constraint firstAttribute="trailing" secondItem="KiU-vK-XXr" secondAttribute="trailing" constant="12" id="M6p-kS-2Wj"/>
<constraint firstItem="8zb-Kb-NJY" firstAttribute="top" secondItem="d56-0u-ihe" secondAttribute="top" constant="20" id="R3e-cc-Fer"/>
<constraint firstAttribute="bottom" secondItem="KiU-vK-XXr" secondAttribute="bottom" constant="20" id="gX4-Zs-QVl"/>
<constraint firstItem="KiU-vK-XXr" firstAttribute="top" secondItem="8zb-Kb-NJY" secondAttribute="bottom" constant="10" id="inN-ct-lOI"/>
<constraint firstItem="KiU-vK-XXr" firstAttribute="leading" secondItem="d56-0u-ihe" secondAttribute="leading" constant="12" id="sFN-WJ-e2x"/>
</constraints>
</view>
<tableView clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="default" rowHeight="-1" estimatedRowHeight="-1" sectionHeaderHeight="28" sectionFooterHeight="28" translatesAutoresizingMaskIntoConstraints="NO" id="lnj-TZ-tdQ" customClass="ContentSizedTableView" customModule="LaunchTest2" customModuleProvider="target">
<rect key="frame" x="20" y="159" width="335" height="160"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstAttribute="height" priority="250" constant="160" id="OWa-SK-1bb"/>
</constraints>
<prototypes>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" reuseIdentifier="DaveCell" rowHeight="67" id="UZ0-mW-z3R" customClass="DaveCell" customModule="LaunchTest2" customModuleProvider="target">
<rect key="frame" x="0.0" y="28" width="335" height="67"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="UZ0-mW-z3R" id="Bpu-ZK-jmH">
<rect key="frame" x="0.0" y="0.0" width="335" height="66.5"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="natural" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="cta-dh-NKD">
<rect key="frame" x="15" y="23" width="42" height="21"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
<textField opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" borderStyle="roundedRect" textAlignment="right" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="CgS-ib-w4y">
<rect key="frame" x="69" y="18.5" width="251" height="30"/>
<nil key="textColor"/>
<fontDescription key="fontDescription" type="system" pointSize="14"/>
<textInputTraits key="textInputTraits"/>
</textField>
</subviews>
<constraints>
<constraint firstItem="cta-dh-NKD" firstAttribute="top" secondItem="Bpu-ZK-jmH" secondAttribute="topMargin" constant="12" id="We1-kz-q2C"/>
<constraint firstAttribute="bottomMargin" secondItem="cta-dh-NKD" secondAttribute="bottom" constant="12" id="Xrk-31-tpM"/>
<constraint firstItem="cta-dh-NKD" firstAttribute="leading" secondItem="Bpu-ZK-jmH" secondAttribute="leadingMargin" id="gWG-0p-rAe"/>
<constraint firstItem="CgS-ib-w4y" firstAttribute="centerY" secondItem="Bpu-ZK-jmH" secondAttribute="centerY" id="lQV-0f-plQ"/>
<constraint firstItem="CgS-ib-w4y" firstAttribute="leading" secondItem="cta-dh-NKD" secondAttribute="trailing" constant="12" id="t9H-NP-Nun"/>
<constraint firstAttribute="trailingMargin" secondItem="CgS-ib-w4y" secondAttribute="trailing" id="zfb-h1-T31"/>
</constraints>
</tableViewCellContentView>
<connections>
<outlet property="theLabel" destination="cta-dh-NKD" id="E47-0o-OD8"/>
<outlet property="theTextField" destination="CgS-ib-w4y" id="pNN-td-M2T"/>
</connections>
</tableViewCell>
</prototypes>
</tableView>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Please put in a profile photo." textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="rAu-zB-NyR">
<rect key="frame" x="74.5" y="573.5" width="226.5" height="21.5"/>
<color key="backgroundColor" red="1" green="0.14913141730000001" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<fontDescription key="fontDescription" type="system" weight="thin" pointSize="18"/>
<color key="textColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<nil key="highlightedColor"/>
</label>
</subviews>
<color key="backgroundColor" red="0.45138680930000002" green="0.99309605359999997" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstItem="kg2-26-RDd" firstAttribute="top" secondItem="SCY-zE-Vif" secondAttribute="top" constant="12" id="80C-f1-Inf"/>
<constraint firstItem="rAu-zB-NyR" firstAttribute="top" relation="greaterThanOrEqual" secondItem="lnj-TZ-tdQ" secondAttribute="bottom" constant="8" id="9Sg-Aa-wir"/>
<constraint firstItem="lnj-TZ-tdQ" firstAttribute="top" secondItem="d56-0u-ihe" secondAttribute="bottom" constant="12" id="EhF-Gu-8vx"/>
<constraint firstAttribute="trailing" secondItem="d56-0u-ihe" secondAttribute="trailing" id="NuV-lh-WRd"/>
<constraint firstItem="d56-0u-ihe" firstAttribute="top" secondItem="kg2-26-RDd" secondAttribute="bottom" constant="12" id="Ppo-X8-gdk"/>
<constraint firstItem="lnj-TZ-tdQ" firstAttribute="leading" secondItem="SCY-zE-Vif" secondAttribute="leading" constant="20" id="QBd-ca-Itt"/>
<constraint firstItem="kg2-26-RDd" firstAttribute="centerX" secondItem="SCY-zE-Vif" secondAttribute="centerX" id="TLP-ZG-cWf"/>
<constraint firstItem="rAu-zB-NyR" firstAttribute="centerX" secondItem="SCY-zE-Vif" secondAttribute="centerX" id="Zat-D4-CeV"/>
<constraint firstAttribute="bottom" secondItem="rAu-zB-NyR" secondAttribute="bottom" constant="8" id="jdI-I6-eub"/>
<constraint firstAttribute="trailing" secondItem="lnj-TZ-tdQ" secondAttribute="trailing" constant="20" id="qls-uL-RxI"/>
<constraint firstItem="d56-0u-ihe" firstAttribute="leading" secondItem="SCY-zE-Vif" secondAttribute="leading" id="yBB-ls-1fU"/>
</constraints>
</view>
</subviews>
<color key="backgroundColor" red="0.99942404029999998" green="0.98555368190000003" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstItem="SCY-zE-Vif" firstAttribute="width" secondItem="sfU-bN-guh" secondAttribute="width" id="0AS-Bw-vgM"/>
<constraint firstItem="SCY-zE-Vif" firstAttribute="height" secondItem="sfU-bN-guh" secondAttribute="height" priority="250" id="1nY-0L-LLo"/>
<constraint firstItem="SCY-zE-Vif" firstAttribute="top" secondItem="sfU-bN-guh" secondAttribute="top" id="Rqy-JP-jge"/>
<constraint firstAttribute="bottom" secondItem="SCY-zE-Vif" secondAttribute="bottom" id="S3L-Zg-fgS"/>
<constraint firstItem="SCY-zE-Vif" firstAttribute="leading" secondItem="sfU-bN-guh" secondAttribute="leading" id="fON-cd-chM"/>
<constraint firstAttribute="trailing" secondItem="SCY-zE-Vif" secondAttribute="trailing" id="vYb-7j-GxU"/>
</constraints>
</scrollView>
</subviews>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstItem="6HN-hq-UwM" firstAttribute="bottom" secondItem="sfU-bN-guh" secondAttribute="bottom" id="1QS-4N-gEW"/>
<constraint firstItem="sfU-bN-guh" firstAttribute="leading" secondItem="6HN-hq-UwM" secondAttribute="leading" id="5Ur-Gf-8pP"/>
<constraint firstItem="sfU-bN-guh" firstAttribute="top" secondItem="6HN-hq-UwM" secondAttribute="top" id="7DE-le-6vP"/>
<constraint firstItem="6HN-hq-UwM" firstAttribute="trailing" secondItem="sfU-bN-guh" secondAttribute="trailing" id="N4k-MG-Uef"/>
</constraints>
<viewLayoutGuide key="safeArea" id="6HN-hq-UwM"/>
</view>
<navigationItem key="navigationItem" id="Wwb-5l-bvB"/>
<connections>
<outlet property="theScrollView" destination="sfU-bN-guh" id="Mtz-hh-9i3"/>
<outlet property="theTableView" destination="lnj-TZ-tdQ" id="Rqn-pk-icA"/>
</connections>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="mX1-qt-jnP" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="928.79999999999995" y="132.68365817091455"/>
</scene>
<!--Navigation Controller-->
<scene sceneID="1J1-9A-mRF">
<objects>
<navigationController automaticallyAdjustsScrollViewInsets="NO" id="OCG-fk-O07" sceneMemberID="viewController">
<toolbarItems/>
<navigationBar key="navigationBar" contentMode="scaleToFill" insetsLayoutMarginsFromSafeArea="NO" id="RAe-Db-aHt">
<rect key="frame" x="0.0" y="20" width="375" height="44"/>
<autoresizingMask key="autoresizingMask"/>
</navigationBar>
<nil name="viewControllers"/>
<connections>
<segue destination="ByF-jo-q34" kind="relationship" relationship="rootViewController" id="9V8-EB-duR"/>
</connections>
</navigationController>
<placeholder placeholderIdentifier="IBFirstResponder" id="Asf-IX-RlV" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="-10.4" y="132.68365817091455"/>
</scene>
</scenes>
</document>

Change UIImage's height in UITableViewCell according to it's position to UITableView's center

Here is my sample project with horizontal UITableView which resize images in UITableViewCell while scrolling.

Expanding and Collapsing table view cells in ios

I got the same task on one project with just one thing different: There were no buttons, just tapping on cell will expand or collapse it.

There are several things you should edit in your code. First, the button method code will look something like this:

- (void) collapseExpandButtonTap:(id) sender
{
UIButton* aButton = (UIButton*)sender; //It's actually a button
NSIndexPath* aPath = [self getIndexPathForCellWithButtonByMagic:aButton];
//expandedCells is a mutable set declared in your interface section or private class extensiont
if ([expandedCells containsObject:aPath])
{
[expandedCells removeObject:aPath];
}
else
{
[expandedCells addObject:aPath];
}
[myTableView beginEditing];
[myTableView endEditing]; //Yeah, that old trick to animate cell expand/collapse
}

Now the second thing is UITableViewDelegate method:

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
if ([expandedCells containsObject:indexPath])
{
return kExpandedCellHeight; //It's not necessary a constant, though
}
else
{
return kNormalCellHeigh; //Again not necessary a constant
}
}

Key thing here is to determine if your cell should be expanded/collapsed and return right height in delegate method.

How to use UITableView inside UIScrollView and receive a cell click?

Answer : Don't do this.

UITableview is inherited from ----> UIScrollView : UIView : UIResponder : NSObject

Apple says :

Important: You should not embed UIWebView or UITableView objects in
UIScrollView objects. If you do so, unexpected behavior can result
because touch events for the two objects can be mixed up and wrongly
handled.



Related Topics



Leave a reply



Submit