Add a view to CollectionView header in StoryBoard - ios

I have 2 views on top of my CollectionView and just want to scroll on all these 3 views. I understand the best approach is to place these 2 top views in my collectionView header. How can I achieve this in storyboard (interface builder) without any code?
(I use this way in my another tableView but I have can't do this with CollectionoView)
I drag those 2 views to my collectionView's reusableView(headerView) and I've faced with this error:
enter image description here

There is no way you can drag and drop in interface builder and get header view for collection view. You have to additionally implement viewForSupplementaryElementOfKind method which returns UICollectionReusableView. While using collection reusable view, we have to treat that view in different way similar to stuffs we do for reusable cell.
Steps to follow.
Create a class (HeaderViewExample) for that header view.
Assign class (HeaderViewExample) to the reusable view you have just added in interface builder.
Give a reusable identifier (HeaderViewExample) to that reusable view.
Now you add label or buttons to the reusable view and create outlets for those outlets in the Class HeaderViewExample.
(Note: While using reusable views, don't create outlets directly in the controller.)
Now Update your CollectionViewController with the below code.
override func collectionView(collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, atIndexPath indexPath:
NSIndexPath) -> UICollectionReusableView {
var reusableView = UICollectionReusableView()
if kind == UICollectionElementKindSectionHeader {
guard let view = collectionView?.dequeueReusableSupplementaryViewOfKind(kind, withReuseIdentifier: String(HeaderViewExample), forIndexPath: indexPath) as? HeaderViewExample else { return reusableView }
view.label = "Test String"
view.backgroundColor = UIColor.redColor()
} else {
assert(false, "Unexpected element kind")
}
return reusableView
}

Related

Is it possible to have a UITableView under a UICollectionView?

Long story short. I have a ViewController that has a ColletionView that's the main component of the page. The CollectionView has 2 reusable cell a Header and a Footer. I would like to have a TableView inside the footer but that's not possible I get the following error when I try to connect the TableView:
"Illegal Configuration: The tableView outlet from the ViewController to the UITableView is invalid. Outlets cannot be connected to repeating content."
My tip is that I want to achieve this in a total wrong way.
I want to achieve the following:
[SOLVED]
The solution was the following: I made a CollectionReusableView file for the Footer then exactly when #karem_gohar said I passed the following:
footer.tableView.delegate = footer.self
footer.tableView.dataSource = footer.self
I connected the tableView to the CollectionReusableView, I made an array to test it out I filled the tableView with the elements of the array.
Ps.:I made a TableViewCell and linked a label to it. The label showed the element of the array.
I assume you did register the footer/header nib like this:
segmentCollectionView.register(UINib(nibName: /* CellNibName */, bundle: nil), forSupplementaryViewOfKind: UICollectionView.elementKindSectionFooter, withReuseIdentifier: /* CellId */)
and then dequeue the cell like this
func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView {
if kind == UICollectionView.elementKindSectionFooter {
let cell = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: /* CellId */, for: indexPath) as! /* Your Class */
}
else {
}
}
so the trick is in your registered cell class as a footer you can go to the xib file and add the UITableView inside the reference /* Your Class */
link the UITableView in the cell class not theUIViewControllerclass that contains theUICollectionView`
then pass the data you want when you dequeue the cell and perform all your business inside the cell class

Best way to programmatically set a dynamic height of a collection view header?

I have a view HeaderView that is subclassing UICollectionReusableView and which is a UIStackView arranging some subviews with labels. The number and texts of those labels depend of the information requested to a service.
Such view is registered to a collectionView this way:
collectionView.register(HeaderView.self, forSupplementaryViewOfKind: UICollectionElementKindSectionHeader, withReuseIdentifier: HeaderView.reuseIdentifier)
Then I've implemented collectionView(_:viewForSupplementaryElementOfKind:at:) method like this:
public func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView {
switch kind {
case UICollectionElementKindSectionHeader:
if let headerView = collectionView.dequeueReusableSupplementaryView(ofKind: kind,
withReuseIdentifier: HeaderView.reuseIdentifier,
for: indexPath) as? HeaderView {
// Provide the headerView with the texts it needs to show
return headerView
}
fatalError("no view")
default:
fatalError("no view")
}
}
and also implemented collectionView(_:layout:referenceSizeForHeaderInSection:) method.
My issue is that collectionView(_:layout:referenceSizeForHeaderInSection:) is called first, and at that moment the headerView has not been instantiated, so I can't get its actual height. I can't provide a fix height either because, as I said, the height of such headerView will depend on the information I get from a service and it's going to be variable.
I'm not using either storyboard or xib files, I'm creating all the views and setting the layout in code.
I should also add that actually I need this HeaderView to be the header of just one section in my collection view, so I may not need to dequeue and reuse it?

Nested CollectionView in Storyboard

I have a collectionView with cell and then again a collectionView in this cell. This child collectionView is again having a cell in it. Now i want to communicate with the cell in my child collectionView from the parent collectionView. How to do that in swift 3 in storyboard? As shown in the image attached I want to communicate from first collectionView to the radio cell
In your main ViewController.swift conform it to the protocols UICollectionViewDataSource, UICollectionViewDelegate.
Now from your storyboard take an outlet of your parent CollectionView to your ViewController.swift.
Then create a Cocoa Touch Class which is subclass of UICollectionViewCell for your custom cell of UICollectionview and take an outlet of your child CollectionView in this class.
Now go to your storyboard and select your parent Collectionview cell and set its class to your custom cell class and then set an Identifier for this cell in Attributes inspector.
Now again create class for your child UICollectionview cell and do the same as parent UICollectionview.
Now everything is setup in your storyboard. After this you should write the code for your procedure in delegate methods of UICollectionView.
Now in your ViewController.swift file write the delegate methods of UICollectionView.
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell
{
let cell =
parentCollectionViewOutlt.dequeueReusableCell(withReuseIdentifier: "parentcell", for: indexPath) as! ParentCollectionViewCell
cell.childCollectionView.reloadData()
return cell
}
Now in your parent CollectionView cell class file:
Also conform it to the protocols UICollectionViewDataSource, UICollectionViewDelegate and write all delegate methods for UICollectionView and then write following code as:
override func awakeFromNib() {
super.awakeFromNib()
childCollectionView.delegate = self
childCollectionView.dataSource = self
childCollectionView.reloadData()
}
Now here in cellForItemAt() method do the same procedure for taking cell of your child CollectionView by specifying its identifier and then do your code in it and return your cell. Here you can do whatever you want to do in your child CollectionView's cell that means you have an access to your child CollectionView's cell in this class for custom cell of your parent CollectionView.
Follow this link
https://ashfurrow.com/blog/putting-a-uicollectionview-in-a-uitableviewcell/
In this tutorial the same scenario is being explained just one change
adding UICollectionView in UITableViewCell.
Go through this above link , and try to implement. It will help you

CollectionView in ScrollView

I am working on an iOS app where I want to show a UIScrollView with two UILabels an UIImageView and a UICollectionView at the bottom. Now I don't know how to do this in auto layout, who could help me out?
I've tried just adding everything and setting the constraints to each other, but I do remember that the UIScrollView needs to calculate the intrinsic content height. How can I create this scroll view?
I would avoid embedding the UICollectionView into a UIScrollView in this case. It will be easier to add the UILabels and UIImageView into a section header using a UICollectionReusableView subclass.
Here are the steps:
Add a section header to the UICollectionView:
Create your section header view class by subclassing UICollectionReusableView. Set custom class and reuse identifier of the header reusable view:
Lay out your header view. Connect your outlets.
Implement the viewForSupplementaryElementOfKind method.
override func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView {
// If you also use footers:
// use a switch statement on the 'kind' argument to
// decide which view to dequeue.
let view = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: "Header", for: indexPath)
// set up your header view
return view
}

UICollectionReusableView header possible bug

I have a custom UICollectionReusableView with a single label inside: the label has leading, trailing, top and bottom constraints set to 8.
On the controller, I register the cell and then:
func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForHeaderInSection section: Int) -> CGSize {
return self.sectionSizeForIndex(section)
}
func collectionView(collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, atIndexPath indexPath: NSIndexPath) -> UICollectionReusableView {
let cell = self.collectionView.dequeueReusableSupplementaryViewOfKind(UICollectionElementKindSectionHeader, withReuseIdentifier: "cellID", forIndexPath: indexPath) as! FooCollectionViewCell
cell.setupLabelWithText("Lorem ipsum")
return cell
}
For debugging reasons, I show both the borders of the cell and the borders of the inner label, with different colors.
Here's what happens: The cell got the right frame, but the inner label seems not update constraints according to its parent view (cell).
On "Debug View Hierarchy", I see that also cell.contentView doesn't update itself -> I suppose that is this the reason why the label doesn't update.
In cell awake from nib:
override func awakeFromNib() {
super.awakeFromNib()
self.label.numberOfLines = 0
self.autoresizingMask = [.FlexibleWidth, .FlexibleHeight]
self.translatesAutoresizingMaskIntoConstraints = true
}
add this inside viewForSuplementary
switch kind {
case UICollectionElementKindSectionHeader:
let cell = self.collectionView.dequeueReusableSupplementaryViewOfKind(UICollectionElementKindSectionHeader, withReuseIdentifier: "cellID", forIndexPath: indexPath) as! FooCollectionViewCell
cell.setupLabelWithText("Lorem ipsum")
return cell
default: break
}
this will let you collectionView know that you actually are using a header and not a footer or other type of view kind
The problem may be that you are using an instance of UICollectionViewCell for a supplementary view instead of the usual custom subclass of UICollectionReusableView.
UICollectionReusableView does not have a contentView property, unlike UICollectionViewCell. The latter creates its own view for that property by manipulating your view hierarchy and constraints. It manages the frame of the content view, and gives it a gesture recognizer, amongst other things. The relationship between the cell (which is itself a view) and the content view (as a subview of the cell) is somewhat opaque and has led to developer grief in previous versions of iOS.
There is nothing in the documentation expressly forbidding the use of UICollectionViewCell as a supplementary view. But there are implicit indications that the expected practice is to the contrary.
The purpose of UICollectionViewCell is to "present the main content" of your collection view, or "your main data items". It "presents the content for a single data item". Supplementary views, on the other hand, "are separate from the collection view's cells". "Like cells, these views are provided by the data source object, but their purpose is to enhance the main content of your app."
When configuring supplementary views in a storyboard, the "Collection View Programming Guide for iOS" provides the following guidance:
For supplementary views, drag a Collection Reusable View from the object library and drop it on to your collection view. Set the custom class and the collection reusable view identifier of your view to appropriate values.
There is no express guidance about configuring supplementary views programmatically, but there is also no reason to think the expected practice would be any different.
In testing your scenario (iOS 10.2 and iOS 9.3, Xcode 8), I could not reproduce the problem. I found that the frames of the content view and label were both set correctly.
But the easiest solution to your problem is likely to be to adopt the expected practice:
Change FooCollectionViewCell (and any associated nib file) from a subclass of UICollectionViewCell to a subclass of UICollectionReusableView.
Remove the autoresizing mask lines from awakeFromNib.

Resources