Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save MilanNosal/e082810b5fdc3b9e320f0e0a81a791e2 to your computer and use it in GitHub Desktop.
Save MilanNosal/e082810b5fdc3b9e320f0e0a81a791e2 to your computer and use it in GitHub Desktop.
Enlarging a cell in UITableView on long press using autolayout and UITableViewAutomaticDimension
//
// EnlargingCellsOnLongPressAutolayoutController.swift
// EnlargingCellsExample
//
// Created by Milan Nosáľ on 14/02/2018.
// Copyright © 2018 Milan Nosáľ. All rights reserved.
//
import UIKit
class EnlargingCellsOnLongPressAutolayoutController: UITableViewController {
// this will hold the cell we are currently enlarging
var enlargingCell: EnlargingCell?
// dummy data model
var modelItems: [String] = []
// some height limit, I will set it for myself to 200
let limitHeight = CGFloat(200)
// the enlarging itself will be done by a timer
weak var timer: Timer?
override func viewDidLoad() {
super.viewDidLoad()
// nothing special here
tableView.register(EnlargingCell.self, forCellReuseIdentifier: "cell")
tableView.estimatedRowHeight = 100
tableView.rowHeight = UITableViewAutomaticDimension
tableView.allowsSelection = false
// creating some dummy data, 30 items
for index in 0..<30 {
modelItems.append("Item \(index)")
}
let longPressRecognizer = UILongPressGestureRecognizer(target: self, action: #selector(longPress(longPressGestureRecognizer:)))
longPressRecognizer.minimumPressDuration = 1
self.view.addGestureRecognizer(longPressRecognizer)
}
// following three methods should be clear
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return modelItems.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
cell.textLabel?.text = modelItems[indexPath.row]
return cell
}
@objc func longPress(longPressGestureRecognizer: UILongPressGestureRecognizer) {
if longPressGestureRecognizer.state == UIGestureRecognizerState.began {
let touchPoint = longPressGestureRecognizer.location(in: self.tableView)
if let indexPath = tableView.indexPathForRow(at: touchPoint),
let cell = tableView.cellForRow(at: indexPath) as? EnlargingCell {
//when the press starts on a cell, we will keep the indexPath for the cell
self.enlargingCell = cell
// and turn on enlarging
self.startEnlarging()
}
} else if longPressGestureRecognizer.state == .ended {
// when the press is ended, we can stop enlarging
stopEnlarging()
}
}
func startEnlarging() {
// interval 0.1 second seems smooth enough (redraw seems to be animated anyway)
timer = Timer.scheduledTimer(withTimeInterval: 0.1, repeats: true, block: { [weak self] (timer) in
guard let strongSelf = self, let enlargingCell = self?.enlargingCell else { return }
let oldHeight = enlargingCell.heightConstraint.constant
// since the timer repeats every 0.1 second, this will enlarge the cell 20 points per second till limit
// in one cycle I will enlarge the cell by two points
let newHeight = oldHeight + 2
if newHeight < strongSelf.limitHeight {
// if the newHeight did not reach limit,
// update height and redraw tableView
enlargingCell.heightConstraint.constant = newHeight
strongSelf.tableView.beginUpdates()
strongSelf.tableView.setNeedsLayout()
strongSelf.tableView.endUpdates()
} else {
// reached maximum size, just cancel the timer
strongSelf.stopEnlarging()
}
})
}
func stopEnlarging() {
// this just cancels the timer
timer?.invalidate()
}
}
class EnlargingCell: UITableViewCell {
var heightConstraint: NSLayoutConstraint!
override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
super.init(style: .default, reuseIdentifier: reuseIdentifier)
// for the illustration I am using explicit height constraint on contentView, but it could be determined using the content too
heightConstraint = self.contentView.heightAnchor.constraint(equalToConstant: 100)
// priority set to 999 because of https://stackoverflow.com/questions/44651241/expandable-uitableview-cell-using-autolayout-results-in-uiviewalertforunsatisfia
heightConstraint.priority = UILayoutPriority(rawValue: 999)
heightConstraint.isActive = true
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment