Last active
February 16, 2018 15:29
-
-
Save MilanNosal/e082810b5fdc3b9e320f0e0a81a791e2 to your computer and use it in GitHub Desktop.
Enlarging a cell in UITableView on long press using autolayout and UITableViewAutomaticDimension
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// 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