Dynamic UICollectionView inside dynamic UITableViewCell - swift

I have a collection view that is dynamic and can have any number of cells in it. It is positioned inside a table view cell.
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return UITableViewAutomaticDimension
}
My table view is correctly configured to be dynamic because the other cells work fine so the issue is not there.
Here is what I currently have... As you can see there is no collection view below
This is what my desired out come is... (Forcing a height constraint on the collection view)
I have configured constraints on all sides of the collection view correctly, as it works when I give a fix height constraint. But this defeats the object of a dynamic collection view...
I have linked an outlet to the UICollectionViewFlowLayout and set an estimated cell size and given the cell the correct constraints on the label inside as you can see in the image where I forced the height constraint.

Create a subclass for collectionView and override intrinsicContentSize.
class DynamicCollectionView: UICollectionView {
override func layoutSubviews() {
super.layoutSubviews()
if !__CGSizeEqualToSize(bounds.size, self.intrinsicContentSize) {
self.invalidateIntrinsicContentSize()
}
}
override var intrinsicContentSize: CGSize {
return collectionViewLayout.collectionViewContentSize
}
}
In Interface builder change the class of your collectionView to DynamicCollectionView (subclass UICollectionView).
Set estimated cell size of UICollectionViewFlowLayout.
flowLayout.estimatedItemSize = CGSize(width: 1,height: 1)

Related

How to size a XIB cell so that 2 labels can appear?

I'm smashing my head against the wall for the past 3 hours trying to figure this out. After watching countless tutorials, I still can't seem to figure out why this XIB cell cannot show both labels on the tableview.
XIB file:
What it keeps showing up as:
I just don't understand. I've tried everything, setting height constraints, distance constraints, stack views, but nothing will get the second label on the bottom to show up in the table view cell. Is there an obvious thing I am missing here?
OK, this is absolutely insipid but I figured it out, by randomly copying and pasting bits of code online until something worked. Here's what worked (swiped from hackingwithswift)
override func awakeFromNib() {
super.awakeFromNib()
NSLayoutConstraint.activate([
titleLabel.topAnchor.constraint(equalTo: contentView.topAnchor,constant: 5),
titleLabel.leadingAnchor.constraint(equalTo: contentView.layoutMarginsGuide.leadingAnchor),
titleLabel.trailingAnchor.constraint(equalTo: contentView.layoutMarginsGuide.trailingAnchor),
titleLabel.bottomAnchor.constraint(equalTo: projLabel.topAnchor),
projLabel.topAnchor.constraint(equalTo: titleLabel.bottomAnchor),
projLabel.leadingAnchor.constraint(equalTo: contentView.layoutMarginsGuide.leadingAnchor),
projLabel.trailingAnchor.constraint(equalTo: contentView.layoutMarginsGuide.trailingAnchor),
projLabel.bottomAnchor.constraint(equalTo: contentView.bottomAnchor)
])
final result:
Try this:
Select TableView in Storyboard -> Identity Inspector
Set Row Height to Automatic (let empty)
Set estimate to some value (for example 150)
On cell class implement this method (example):
override func sizeThatFits(_ size: CGSize) -> CGSize {
// 1) Set the contentView's width to the specified size parameter
contentView.pin.width(size.width)
// 2) Layout the contentView's controls
layout()
// 3) Returns a size that contains all controls
return CGSize(width: contentView.frame.width, height: adsViewsCount.frame.maxY + padding)
}
Implement this with UITableViewDatasource:
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
// The UITableView will call the cell's sizeThatFit() method to compute the height.
// WANRING: You must also set the UITableView.estimatedRowHeight for this to work.
return UITableView.automaticDimension
}

UITableview Cell height is changing on scrolling tableview in iOS 14.0

UITableview Cell Height is changing on scrolling table view, I am using dynamic height for table view cell.
Basically I'm working on a chat screen and using two custom classes for incoming and out-going message and everything is handled dynamically.
it was working till iOS 13 and getting issue on ios 14
using in viewDidLoad
self.chatTableView.estimatedRowHeight = 172
self.chatTableView.rowHeight = UITableView.automaticDimension
and using
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return 44
}
for dynamic height handling
rest I have also tried the hugging property on label
override func awakeFromNib() {
self.layoutIfNeeded()
}
override func didMoveToSuperview() {
super.didMoveToSuperview()
layoutIfNeeded()
}
in tableview cell, but didn't see any difference
It must be because of the data in the cells.Try removing the below line and give a static height if you want so then the height will be same throughout.
self.chatTableView.rowHeight = UITableView.automaticDimension

Header view of UICollectionView keeps duplicating on scroll - How to create fixed (non-sticky), single collection view header?

I wanted to implement a view hierarchy like the following so that the ENTIRE view would be scrollable:
UIScrollView
Image View
Collection view
But a lot of people on here have said that it is better to use the header that comes along with the collection view. I've done that but now I have a new problem: as I scroll the collection view, any configurations I've done to the header cell in the viewForSupplementaryElementOfKind function is duplicating (Eg: If I programmatically create a new view in viewForSupplementaryElementOfKind function, this view will keep creating as I scroll)
I kind of get that this is happening because I'm dequeuing the header using dequeueReusableSupplementaryView. But I've tried searching on Apple docs and there are no other codes I can use to instantiate the header view without making it reusable.
Is there any way I can create a view controller as described above without using UICollectionView?
I've tried setting the number of sections to 1 hoping that it would only be reused ONCE but it doesn't work.
Edit: Also tried setting header size using UICollectionViewDelegateFlowLayouta and using UICollectionView instead of UIViewController and UICollectionViewDataSource etc.
func collectionView(_ collectionView: UICollectionView,
viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView
{
switch kind {
case UICollectionView.elementKindSectionHeader:
guard
let headerView = collectionView.dequeueReusableSupplementaryView(
ofKind: kind,
withReuseIdentifier: "DiscoverHeader",
for: indexPath) as? DiscoverHeader
else {
fatalError("Invalid view type")
}
// Rotating arrow image
headerView.arrowImg.transform = headerView.arrowImg.transform.rotated(by: CGFloat.pi/0.67)
return headerView
default:
assert(false, "Invalid element type")
}
}
Why not UIImageView and UICollectionView inside UIScrollView?
You can definitely create a UIScrollView and add an UIImageView and a UICollectionView in it.
But that won't work as expected. This is because you're embedding a scrollView(UICollectionView) inside another scrollView. Scrolling the collectionView vertically will hamper the scrolling of the outer scrollView.
Solution:
Try giving the height of the header view using UICollectionViewDelegateFlowLayout's method,
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForHeaderInSection section: Int) -> CGSize {
return CGSize(width: collectionView.bounds.width, height: 100.0) //give the height as per your requirement...
}
Also, set the contentMode of imageView as Aspect Fit / Aspect Fill.

Setting the height: TableViewCells with custom Nib that are different sizes

I have a TableViewController that has a custom TableViewCell under the identifier "customCell". Heres an image of the configuration of the cell along with the IBOulets connected to it:
The cell takes information from my backend and presents it. The description text view (just noticed that I accidentally named it descriptionLabel) doesn't allow scrolling so it expands based off of the content that it's holding. The database is being processed correctly from the database, and it's displaying on the app. The only problem is that the cell is not its correct height. On the TableViewControl that's registering this cell through its identifier, I automatically set the height of the cell using UITableViewAutomaticDimension in heightForRow:
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return UITableViewAutomaticDimension
}
but that's not working either. *The only thing that works is when I set the height of each cell to a standard value such as 200. That doesn't work for me because each cell will be a different height because of the length of the textView.
How do I set the height of a custom nib (tableViewCell) so that it adjusts based off of the content within it instead of setting the height to a specific value?
1-Remove both textViews and replace them with labels
2- Title lbl with theses constraints
top,leading,trailing , .lines = 0
3- Description lbl with theses constraints
bottom ,leading,trailing to contentView,top to bottom of title lbl , .lines = 0
Off course you can leave the 2 textviews , but you have to give each one an initial height and do this in
override func layoutSubviews() {
super.layoutSubviews()
self.titleTvHeight.constant = self.titleTv.contentSize.height
self.desTVheight.constant = self.desTv.contentSize.height
}
//
Don't forget to set this in viewDidLoad of the VC
tableView.estimatedRowHeight = 200
tableView.rowHeight = UITableViewAutomaticDimension
Anyway you can remove heightForRowAt

in UITableviewcell in Xcode 9.0.1 cell size it not expanding at runtime?

I have tried with drag and drop UITableviewcell and change row height from file inspector cannot expanded cell height at runtime.
in Xcode 9.0.1 I am facing issue regarding Cell height not increasing at run time.
Swift 3+
If you want dynamic row height, you can define your constraints (making sure they're unambiguous), set the label's numberOfLines to zero, and then in viewDidLoad, tell it that rows should automatically adjust their height:
override func viewDidLoad() {
super.viewDidLoad()
tableView.estimatedRowHeight = your height here
tableView.rowHeight = UITableViewAutomaticDimension
}
OR Try this.
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return UITableViewAutomaticDimension
}
func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
return UITableViewAutomaticDimension
}
You have to configure your cells to be self-sizing:
1: Add the following lines to viewDidLoad(). Specify a tableViewRowHieght that you think will be the average height of the cells displayd in your tableView:
tableView.rowHeight = UITableViewAutomaticDimension
tableView.estimatedRowHeight = 200
2: Makes sure all of the labels in your cell are capable of expanding to as many lines as needed. This is done by setting Number Of Lines in Attribute Inspector to 0 as I have done for my Title label in the image below:
3: Finally, you must set constraints for every element in your cell so that the compiler can correctly calculate the size of the cell at runtime. Here I've added two lables contrained the height of the first to the top of the view, and bottom to label 2 below. Then label 2 must be contrained to the bottom of the view. As long as your contraints contain no "gaps" between the top of the cell to the bottom, the compiler can calculate the height of the cell: