Collection View horizontal direction with dynamic height - ios

I have a collection view with direction set to horizontal and paging enable. The things is, the height of my collection cell each page sometimes is higher than the phone screen size. What I want to achieve is user can scroll down the cell and swipe right to the next page.
Currently, I only able to display the collection cell one full page, without manage to scroll downward based on content height. Here some code:
extension EventListDetailsVC: UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return dataArray.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cat = dataArray[indexPath.row]
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "celldetails", for: indexPath) as? EventListDetailsCVC
cell?.imageEvent.image = UIImage(named: cat.imageEvent)
cell?.eventTitleLabel.text = cat.titleEvent
cell?.eventDescriptionLabel.text = cat.content
return cell!
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: self.collectionView.frame.size.width, height: self.collectionView.frame.size.height)
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
return UIEdgeInsets.zero
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat {
return 0
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
return 0
}
}
this how it should be
I tried to embed my collectionView into tableView, but it seems does not work because I have dynamic height in a cell.
Is it another way to achive this?
p/s I just started learning swift, thanks.

Have you tried embedding a scroll view inside each collection view cell?
That would make sure that the collection view cell height never exceeds the phone height while the scroll view will work on displaying more content as you scroll down whether it be text or images or whatever view you decide to embed in the scroll view itself.

I think you should try UIPageViewController with the scroll transition style. It has native pagination between pages.
Every page should have UIScrollView.

Related

Displaying two cells per row in CollectionView Swift

I am trying to set my collection view cell sizes so that I get two cells per row.
I have looked at plenty of solution for sizing cells for collection views. I actually have used some solutions before for sizing three cells per row that have worked for me.
What I have so far:
extension BusinessViewController: UICollectionViewDelegateFlowLayout {
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
let width = (view.frame.width - 20) / 2.0
return CGSize(width: width, height: width)
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
return UIEdgeInsets(top: 5, left: 5, bottom: 5, right: 5)
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
return 10
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat {
return 10
}
}
Right now I just get one big cell per row and I don't know why. Usually when I have to have 3 cells per row, simply subtracting the insets from the views width and dividing by the number of desired cells is enough. Not sure why this is causing me an issue.
You can try checking the "estimatesSize" property of UICollectionView.
It could have been set to "Automatic" instead of "None".
I solved the same problem with this solution

How can I set custom horizontal scroll for Collection View in Swift, XCode?

I want to set custom horizontal scroll for my CollectionView, that it will be scrolling by 1 cell (not by the whole width of my screen).
I could set HORIZONTAL scroll, but not custom. (See screens).
1 screen: my extension of my collectionView for UIScrollViewDelegate.
*I saw, that in console (see too) "x" - my offset = 290 - it's true! But on fact it is not 290. Paging was marked in "true" 2 screen: delegate and dataSource.
Help, please!
First you need to set your collectionView scroll direction horizontal (UICollectionViewScrollDirectionHorizontal) and set pagingEnabled to YES
It means your collection view will be scroll horizontally with one by one cell.
Set horizontal direction (Select collection view from XIB or Storyboard)
And for set pagination enable
myCollectionView.pagingEnabled = true
Updated :
You should use of UICollectionViewDelegateFlowLayout delegate
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize
{
let width = UIScreen.main.bounds.size.width
var height = 101.7 // set height as you want
return CGSize(width: width, height: height)
}
If using storyBoard the go to collection view and select the right handed tab "show the size inspector" and change
minimum spacing for cells = 0
minimum spacing for lines = 0
if you want to change directly from code then implement these UICollectionViewDelegateFlowLayout methods
func collectionView(_ collectionView: UICollectionView, layout
collectionViewLayout: UICollectionViewLayout,
minimumLineSpacingForSectionAt section: Int) -> CGFloat {
return 0
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat {
return 0
}
must be remember scrolling direction set horizontal
and pagination enabled
and implement this delegate methods into code
extension ViewController: UICollectionViewDelegateFlowLayout {
func collectionView(_ collectionView: UICollectionView, layout
collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath:
IndexPath) -> CGSize {
return CGSize(width: collectionView.frame.size.width, height:
collectionView.frame.size.height)
}
}
You could create a custom UICollectionViewFlowLayout that will center the cells in the screen and then page one at a time. Karmadust have written a good blog post that I have successfully used in the past to do the same thing
http://blog.karmadust.com/centered-paging-with-preview-cells-on-uicollectionview/

UICollectionView refreshing issue

In an iOS app I have a UICollectionView which has 100 (or 80, or 40) cells to start with.
At the beginning all is fine, the layout is OK and the size of each cell is also right, smaller if there is 100 and larger if there is only 40 cells.
Inside the app the user has the possibility to change the number of cells to 100 (or 80, or 40).
When the number changes the layout and size of each cell should be changed accordingly. But that part does not work as expected.
When the user changes the number of cells this code is executed:
myCollectionView.reloadData()
myCollectionView.collectionViewLayout.invalidateLayout()
And for some reasons something is not working. Should I do something more or different in the code above?
The number of cells is right, but the size of the news cells is messed up and I am not totally sure about the layout (positionning).
As far as the UICollectionViewDelegate protocol is concerned, I only implement one method:
func collectionView(_ collectionView: UICollectionView,
didSelectItemAt indexPath: IndexPath) {
.........
}
For the UICollectionViewDelegateFlowLayout protocol, I implement the following:
func collectionView(_ collectionView: UICollectionView,
layout collectionViewLayout: UICollectionViewLayout,
sizeForItemAt indexPath: IndexPath) -> CGSize {
let cellSide = UIScreen.main.bounds.width * 3 / CGFloat(brain.getSide()! * 4)
return CGSize(width: cellSide, height: cellSide)
}
func collectionView(_ collectionView: UICollectionView,
layout collectionViewLayout: UICollectionViewLayout,
minimumInteritemSpacingForSectionAt section: Int) -> CGFloat {
return 6.0
}
func collectionView(_ collectionView: UICollectionView,
layout collectionViewLayout: UICollectionViewLayout,
minimumLineSpacingForSectionAt section: Int) -> CGFloat {
return UIScreen.main.bounds.width / (CGFloat(brain.getSide()!) * 4.4)
}
It seems like the methods above are working fine at start, giving adequate values. But they do not even seem to be called when the user changes the settings.
Please try this reloading method
Objective-c
[self.collectionView performBatchUpdates:^{
[myCollectionView reloadData];
}
completion:^(BOOL finished) {}
];
Swift-3
myCollectionView?.performBatchUpdates({
myCollectionView.reloadData()
}, completion: { (result: Bool) in
})
I ended up by solving the problem, using cell prototypes with a different cell identifier for each size I need and it works perfectly.

UIPageViewController along with UICollectionView for cell grid structure

I have a UICollectionView, which uses UICollectionViewFlowLayout to arrange my cells inside the collection view.
Inside my cells, I have an image and a label. Using the above layout I am able to design my collection view with vertical scrolling,
But instead of vertical scrolling, I want a structure like UIPageViewController which will contain my UICollectionView with the above cells.
I have tried with flowLayout.scrollDirection = .horizontal,
But with that approach I could not solve my issue.
I am new to Swift and I am not using storyboards.
Open your storyboard, select the collectionView and change the scroll direction from vertical to horizontal as shown below :)
Now your collectionView will start scrolling horizontally than vertically :)
If you want pagination, like ViewControllers in pageViewController, select the collectionView and select paging enabled check box :)
Now if you want your collection view cell to cover the whole collectionView like view controllers in UIPageViewController, type this in your UICollectionView delegate :)
extension YourViewController : UICollectionViewDelegateFlowLayout {
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return self.pageViewController.frame.size
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat {
return 0.0
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
return 0.0
}
}
Want to leave spacing between cells return value instead of 0.0 in the above method :) Thats all
EDIT
In case you dont have storyboard you can set the scroll direction and other properties programmatically using
(self.collectionView.collectionViewLayout as! UICollectionViewFlowLayout).scrollDirection = .horizontal
I found my answer from the below link:
http://swiftiostutorials.com/ios-tutorial-using-uipageviewcontroller-create-content-slider-objective-cswift/
It really helped me a lot. Thanks.

Placing the cells in a collection view in the centre rather than the outsides in swift

By default, a collection view will attempt to space out the cells in the collection by spacing them evenly so that there will be one cell touching either side of the collection view. Example:
But, when the cell is too wide to fit multiple cells in one row on the collection view, it will centre the cell in the collection view.
Is there a way to make the behaviour of centring cells, like in the 3rd picture, the default for the collection view so that there is 0 space between the individual cells and space on either side to the edges of the collection view?
Not that I'm aware of. You should implement something like this:
func collectionView(_ collectionView: UICollectionView,
layout collectionViewLayout: UICollectionViewLayout,
sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize {
CGFloat width = UIScreen.mainScreen().bounds.size.width
return CGSize(width, anyHeight)
}
and then implement the delegate method below as well:
func collectionView(collectionView: UICollectionView,
layout collectionViewLayout: UICollectionViewLayout,
insetForSectionAtIndex section: Int) -> UIEdgeInsets {
return UIEdgeInsetsZero
}
Make sure to implement rotation handling too if it's applicable.
My answer would be to use a carefully set up something like
let insets = UIEdgeInsets(top: yourvalues, left: yourvalues, bottom: yourvalues, right: yourvalues),
and feed it to either YourCollectionView.contentInset, or
func collectionView(collectionView: UICollectionView,
layout collectionViewLayout: UICollectionViewLayout,
insetForSectionAtIndex section: Int) -> UIEdgeInsets {
return sectionInsets
}
This should work! Lemme know if you have any troubles with it!

Resources