How to programmatically increase UITableView cell's height in iPhone?
Solution 1:
First of all take a bool
& int
variable.
BOOL isReadMoreButtonTouched = NO;
int indexOfReadMoreButton = -1;
Then Implement below with your code
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
[[cell btnReadmore] setTag:[indexPath row]];
if(isReadMoreButtonTouched && [indexPath row]== indexOfReadMoreButton)
{
// design your read more label here
}
}
Now implement IBAction
-(IBAction) funReadmore:(id)sender
{
UIButton *readMoreButton = (UIButton *)sender;
indexOfReadMoreButton=[readMoreButton tag];
isReadMoreButtonTouched=YES;
[[self tableView] beginUpdates];
[[self tableView] reloadRowsAtIndexPaths:@[[NSIndexPath indexPathForItem: indexOfReadMoreButton inSection:0]] withRowAnimation:UITableViewRowAnimationAutomatic];
[[self tableView] endUpdates];
}
Now Come to heightForRowAtIndexPath
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
if(isReadMoreButtonTouched && [indexPath row]== indexOfReadMoreButton) return 200.0f;
else return 100.0f;
}
Hope it'll work for you.
Solution 2:
Take a int readMoreAtIndex;
as your class variable. Initialize it with a negative value like -1 in init method
and/or viewDidLoad/viewWillAppear
. Some basic logic would be like this:
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
if(readMoreAtIndex == indexPath.row) {
return 400; //return as per your requirement
}
return 100;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
//same lines as currently you are doing to setup cell.
//important line
[cell.btnReadmore setTag:indexPath.row];
[cell.btnReadmore addTarget:self
action:@selector(funReadmore:)
forControlEvents:UIControlEventTouchUpInside];
if(indexPath.row == readMoreAtIndex) {
//setup your cell according to your logic to show expanded view
}
else {
//you are reusing cells, so provide logic to disappear shown expanded view if you want
}
return cell;
}
- (IBAction)funReadmore:(id)sender
{
UIButton *button = (UIButton *)sender;
readMoreAtIndex = button.tag;
[yourTableView reloadData];
NSLog(@"READ MORE");
}
EDIT: Links for tutorials to implement expandable/collapsable tableview.
- Expanding/Collapsing TableView Sections
- Collapsable Table View for iOS
Solution 3:
I found another solution based on self-sizing table view cells. Instead of updating cell's height (hardcoded) we can update the constraints priority.
fileprivate extension Int {
static let rowHeight = 175
}
class CellArticleData {
var article: Article
var isExpanded: Bool
init(article: Article, isExpanded: Bool) {
self.article = article
self.isExpanded = isExpanded
}
}
enum Article: String {
case medicine, sport
static let allArticles: [Article] = [.medicine, .sport]
var title: String { return self.rawValue.capitalized }
var description: String {
switch self {
case .medicine:
return "Lorem Ipsum is simply dummy text of the printing and
typesetting industry"
case .sport:
return "Contrary to popular belief, Lorem Ipsum is not simply
random text. It has roots in a piece of classical Latin
literature from 45 BC, making it over 2000 years old. Richard
McClintock, a Latin professor at Hampden-Sydney College in
Virginia."
}
}
}
class ViewController: UIViewController {
@IBOutlet weak var tableView: UITableView!
var articles: [CellArticleData] = Article.allArticles.map { CellArticleData(article: $0, isExpanded: false) }
override func viewDidLoad() {
super.viewDidLoad()
tableView.dataSource = self
tableView.delegate = self
tableView.rowHeight = UITableViewAutomaticDimension
tableView.estimatedRowHeight = CGFloat(.rowHeight)
}
extension ViewController: UITableViewDataSource {
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "MyCell", for: indexPath) as! MyCell
let articleData = articles[indexPath.row]
cell.setup(articleData: articleData)
cell.delegate = self
return cell
}
}
extension ViewController: MyCellDelegate {
func handleReadMore() {
tableView.reloadData()
}
}
I have a custom class that represent a cell "MyCell" which handles the protocol and constraints updates:
protocol MyCellDelegate {
func handleReadMore()
}
class MyCell: UITableViewCell {
@IBOutlet weak var topConstraint: NSLayoutConstraint!
@IBOutlet weak var bottomConstraint: NSLayoutConstraint!
@IBOutlet weak var heightConstraint: NSLayoutConstraint!
func setup(articleData: CellArticleData) {
self.articleData = articleData
titleLabel.text = articleData.article.title
descriptionLabel.text = articleData.article.description
readMoreLabel.isUserInteractionEnabled = true
let readMoreTap = UITapGestureRecognizer(target: self, action: #selector(handleReadMore))
readMoreTap.cancelsTouchesInView = false
readMoreLabel.addGestureRecognizer(readMoreTap)
updateCellConstraints()
}
fileprivate func updateCellConstraints() {
if let articleData = self.articleData {
if !articleData.isExpanded {
heightConstraint.priority = 999
topConstraint.priority = 250
bottomConstraint.priority = 250
}else {
heightConstraint.priority = 250
topConstraint.priority = 999
bottomConstraint.priority = 999
}
}
}
func handleReadMore() {
if let articleData = self.articleData {
articleData.isExpanded = !articleData.isExpanded
delegate?.handleReadMore(articleData: articleData)
}
}
}
Here is an example showing how it looks like: My custom cell MyCell
Solution 4:
You need to put some kind of flag mechanism and manage the height in
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
The best and ideal way is to calculate the height according to the text and then return the height
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
if(readMore){
return 500;
}else{
return 100;
}
}
If you are using autolayout then you can calculate the size of each labels manually according to content by using sizeToFit
method