UILabels and UICollectionView inside of UITableViewCell - need dynamic height - swift

I have a custom UITableViewCell class that contains various UILabels, UIButtons, and a UITextField in the top and mid-sections, and then a UICollectionView at the bottom.
As a user enters more search terms into the UICollectionView, the collection view grows vertically, but I can't get my TableViewCell to adjust its height dynamically.
I have added constraints for every item in the TableViewCell so AutoLayout should work. I even set the heightForRowAt function to return UITableView.automaticDimension. But I'm apparently still missing something.
When the user adds/subtracts items to the collection view, how can I have the TableViewCell update its height dynamically?
I also tried the following block, but it doesn't work either.
override func systemLayoutSizeFitting(_ targetSize: CGSize, withHorizontalFittingPriority horizontalFittingPriority: UILayoutPriority, verticalFittingPriority: UILayoutPriority) -> CGSize {
collectionView.layoutIfNeeded()
collectionView.frame = CGRect(x: 0, y: 0, width: targetSize.width, height: targetSize.height + titleLabel.frame.height + filterButton.frame.height + collectionView.frame.height)
return collectionView.frame.size
}

Related

How to update UITableview Header height while scrolling programatically

In My application I have top navigation bar and a tableview below the navigation bar. I have CollectionViewCell with two rows which added inside the UITableViewHeader programmatically. When ever I scroll the the TableView to top, i want the header to stop just below the navigation bar, and update the TableView Header height so I can show only one row. I just want to do an animation (like Shrinked)when the TableViewHeader sticks to the navigationbar the two collectionview rows should turn into one row by decreasing the Header Height. How can I do it programmatically
Below is my code for showing CustomHeaderView
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let headerView = UIView.init(frame: CGRect(x: 0, y: 0, width: self.view.frame.width, height: 183))
let headerCell = tableView.dequeueReusableCell(withIdentifier: kLastPlayedidentifier) as! LastPlayedTVC
headerCell.frame = headerView.frame
headerCell.category = lastPlayedData
headerView.addSubview(headerCell)
return headerView
}
Also i'm checking for the scroll position to set the tableview header height progmmatically which isn't successful for me.
func scrollViewDidScroll(_ scrollView: UIScrollView) {
print(scrollView.contentOffset)
if scrollView.contentOffset.y > 237 //This value is to check when the header reached the top position {
//Condition to check and animate the headerview height to make collectionview cell two rows into one rows.
}
How can I achieve the TableViewHeader height update when header sticks on top while scrolling.
Any help is appreciated.
What you are looking for is "sticky header"
and you want to change the header as well.
Sticky part is built in automatically I think if you just use UITableViewController(style: .plain), if that doesn't work for you, you can just google sticky header and there are lots of answers.
the part about changing the height or animating it. you are doing it right, just do something like:
// update your viewForHeader method to account for headerRows variable above
// update your viewForHeader method to account for headerRows variable above
// default 2, you modify this in your scroll
var headerRows = 2
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let height = headerRows == 2 ? 183 : 91
let headerView = UIView.init(frame: CGRect(x: 0, y: 0, width: self.view.frame.width, height: height))
let headerCell = tableView.dequeueReusableCell(withIdentifier: kLastPlayedidentifier) as! LastPlayedTVC
headerCell.frame = headerView.frame
headerCell.category = lastPlayedData
headerView.addSubview(headerCell)
return headerView
}
func scrollViewDidScroll(_ scrollView: UIScrollView) {
print(scrollView.contentOffset)
if scrollView.contentOffset.y > 237 {
updatedHeader.frame.size.height = 40
self.tableviewObj.tableHeaderView = updatedHeader
headerRows = 1 } else {
headerRows = 2
}
self.tableView.reloadSectionHeaders()
}
If you want to do some animating instead, what you would do is store reference to your headerView in a variable of your view controller and inside your scrollViewDidScroll animate it using UIView.animate{...}
hope this helps man.

Top to Bottom Collection View Flow Layout with first cell starting at bottom

I am trying to mimic Instagram live comments section where the first cell in the UICollectionView appears at the bottom but the flow is still top to bottom. I.e. everything about the flow layout is the exact same except that the first cell is at position (x: 0, y: heightOfCollectionView)...
Below is my naive implementation. I also thought about having the collection view increment in height per item in the UICollectionView until themaxY >= centerY of the superview.
import UIKit
class CommentsLayout: UICollectionViewFlowLayout {
override func layoutAttributesForItem(at indexPath: IndexPath) -> UICollectionViewLayoutAttributes? {
let layoutAttribute = super.layoutAttributesForItem(at: indexPath)?.copy() as! UICollectionViewLayoutAttributes
if indexPath.section == 1 {
print(collectionView?.frame.size.height)
layoutAttribute.frame = CGRect(x: 0, y: 600, width: collectionViewContentSize.width, height: 40)
}
return layoutAttribute
}
}

Swift 3.0 - Vertical lines on TableViewCell for every CellIndentationLevel

I have an app that has a bunch of collapsible comments.
Each cell that holds a comment has an indentation cell and I would like to draw a vertical line the height of the cell for every indentation level. The end goal is to look something like this: Taken from Reddit
I tried to add a rectangle shaped view for every indent level in CellForRowAt but it would just keep adding onto itself whenever I scrolled out of view and back into it.
Currently I have it working in the "willDisplay cell" function but it only loads it when the ENTIRE cell is visible, not partially and it still has some issues of overlapping content with lines.
Here's my current code:
func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
for cell in commentTable.visibleCells {
if cell.indentationLevel > 0 {
for i in 1...cell.indentationLevel {
let rect = UIView(frame: CGRect(x: i * 15, y: 0, width: 1, height: Int(cell.bounds.height)))
cell.addSubview(rect)
}
}
}
}
How can I do this preferably in cellForRowAt function, or the simplest and most efficient way to get this done?
You can do this in cellForRowAtIndexPath. Note that you should not just add views to your cells without tracking them because the cells are reused (thats why its called dequeResuableCell). Make a property called indentationViews and a function called setIndentationLevel. In cellForRowAtIndexPath you call cell.setIndentationLevel (note that I have removed your if because for 0..
func setIndentationLevel(indentationLevel: Int) {
for i in 0..<cell.indentationLevel {
let view = UIView(frame: CGRect(x: i * 15 + 15, y: 0, width: 1, height: Int(cell.bounds.height)))
cell.addSubview(view)
indentationViews.append(view)
}
}
You also need to implement prepare for reuse to kill all of the views you just added before the cell gets used again:
override func prepareForReuse() {
indentationViews.forEach{$0.removeFromSuperview()}
indentationViews.removeAll()
}

How to set UICollectionViewCell height to 90% of the View (Screen) height?

I'm trying to set the UICollectionViewCell height as 90% of the screen size. So the cell size would look good when using different devices.
The problem is that I'm not sure how to set the cell height programmatically. All cell should look the same size, so there's no need to consider the content, I only want the cell height to be 90% of the screen.
Here is what it looks like in iphone 6 screen:
However, when switching to a smaller device it looks like this:
Thank you in advance for your help!
You can set your UICollectionView's flow layout tile size programmatically. There are a couple of different places you could cause this, I would start with viewWillAppear (in your ViewController class) for starters:
override func viewWillAppear() {
super.viewWillAppear()
if let layout = self.schedulesView.collectionViewLayout as? UICollectionViewFlowLayout {
var cellSize = UIScreen.main.bounds.size // start with the full screen size
cellSize.height *= 0.9 // adjust the height by 90%
layout.itemSize = cellSize // set the layouts item size
}
}
You can set collectionView itemSize by using collectionViewFlowLayout according to device size. Try below method..
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAtIndexPath indexPath: IndexPath) -> CGSize {
// All the values are changable according to your needs.
let layout = collectionView.collectionViewLayout as! UICollectionViewFlowLayout
layout.sectionInset = UIEdgeInsets(top: 25, left: 3, bottom: 3, right: 3)
layout.minimumInteritemSpacing = 50
layout.minimumLineSpacing = 50
return CGSize(width: self.collectionView.frame.width - 50, height:self.collectionView.frame.height - 100)
}
Note: From the above code you will get box type collectionView itemSize that covers the view accordingly to device size.
Just figured what the problem is with contents inside UICollectionViewCell not updating their size.
Just need to as this to the subclass of UICollectionViewCell
override var bounds: CGRect {
didSet {
contentView.frame = bounds
}
}

Swift - autoresize UiTableViewCell to fit content [duplicate]

In my story board I have a UITableView with dynamically generated UITableViewCells. Each cell contains 2 labels and 1 text view:
I have a code that adjust the size of the textfield to the amount of text:
let fixedWidth = cell.myComment.frame.size.width
cell.myComment.sizeThatFits(CGSize(width: fixedWidth, height: CGFloat.max))
let newSize = cell.myComment.sizeThatFits(CGSize(width: fixedWidth, height: CGFloat.max))
var newFrame = cell.myComment.frame
newFrame.size = CGSize(width: max(newSize.width, fixedWidth), height: newSize.height)
cell.myComment.frame = newFrame;
and it works fine, when I set a background color of my textView to red I see:
and the cell itself - I'm setting the size in here:
func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat
{
if indexPath.row == 0 {
return 100//this is my static cell
}
else {
return 117; //for now it's hardcoded - how can I set this value dynamically based on content?
}
}
So as I wrote in the comment above - how can I set the height of the cell dynamically based on the amount of text in the text view?
The key to getting self-sizing table cells (autolayout-based, which I recommend) is as follows:
Add your subviews to the contentView of the UITableViewCell
Provide constraints between your subviews and the contentView such that your subviews reach all edges of the table cell. In your case, this probably means aligning the leading, trailing, top, and bottom edges of your UITextView to the corresponding edges of the contentView.
Set the row height to UITableViewAutomaticDimension instead of a hardcoded CGFloat.
Somewhere in your controller, provide an estimation of the height with tableView.estimatedRowHeight = x (a hard coded constant is fine, this is for performance).