Make CollectionView Cell horizontal cell bigger than others - ios

I have a collectionView and want to make the center cell is bigger than other cells and when move to previous or next cell make it bigger in center
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
if collectionView == self.collectionView {
return slidData.count
} else {
return categoryData.count
}
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
if collectionView == self.collectionView {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "imageCell", for: indexPath) as! SliderImgCell
cell.categoryName.text = slidData[indexPath.row].imageTitle
cell.detail.text = slidData[indexPath.row].imageContent
cell.pics = slidData[indexPath.item]
return cell
} else{
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "categoryCell", for: indexPath) as! CategoryCell
cell.categoryName.text = categoryData[indexPath.row].depName
cell.pics = categoryData[indexPath.item]
return cell
}
}

You need to save the selected indexPath like this:
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
selectedIndexPath = indexPath
}
Your collection view must confirm UICollectionViewDelegateFlowLayout. Then in sizeForItemAt method resize your cell:
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
if indexPath == selectedIndexPath {
return CGSize(width: 200, height: 90)
} else {
return CGSize(width: 180, height: 80)
}
}

Basically you want a Carousel animation.
Take a look into this library and either use full of it or take help from the code.

You can achieve this by using ScrollViewDidScroll(_:) method and find the center cell and enlarge it.
I wrote clear comments on the code below, if you want to go into details check-out my article about this:
https://medium.com/#sh.soheytizadeh/zoom-uicollectionview-centered-cell-swift-5-e63cad9bcd49
func setFocusedCellStyle(_ scrollView: UIScrollView) {
guard scrollView is UICollectionView else { return }
// get the centerPoint
let centerPoint = CGPoint(x: self.collectionView.frame.size.width / 2 + scrollView.contentOffset.x, y: self.collectionView.frame.size.height / 2 + scrollView.contentOffset.y)
// get the indexPath for the cell at center
if let indexPath = self.collectionView.indexPathForItem(at: centerPoint), self.centerCell == nil {
// centerCell is instance variable of type: YourCell
self.centerCell = (self.colorPickerCollectionView.cellForItem(at: indexPath) as! CustomCollectionViewCell)
UIView.animate(withDuration: 0.2) {
// Choose desired scale value
self.transform = CGAffineTransform(scaleX: 1.58, y: 1.58)
}
}
if let cell = self.centerCell { // center cell is global variable
let offsetX = centerPoint.x - cell.center.x // get to current position of the cell
// when cell is 15 pixels away from the center to the sides
// reset the cell size.
if offsetX < -15 || offsetX > 15 {
UIView.animate(withDuration: 0.2) {
self.transform = CGAffineTransform.identity
}
self.centerCell = nil // set this to nil so next cell in the center will enter the above scope
}
}
}

Related

Set image height from image URL to PinterestLayout CollectionView

I create a CollectionView with PinterestLayout, so this is a collection view with different cells hight. It's work, but when I put my code to the project with Firestore (when image in cells I take from URL) I have a problem, because in this line "let photo = post.floverImg" I think I have to put something like in cell "cell.imageView.sd_setImage(with: URL(string: flovers[indexPath.row].floverImg!))" to show Image and not String.
extension HomeViewController {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return flovers.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell
{
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "CustomCell", for: indexPath) as! CustomCell
cell.imageView.sd_setImage(with: URL(string: flovers[indexPath.row].floverImg!))
cell.label.text = flovers[indexPath.row].floverName
// cell.descriptionLabel.text = flovers[indexPath.row].floverName
cell.layer.cornerRadius = 15
return cell
}
}
func collectionView(collectionView: UICollectionView, heightForPhotoAt indexPath: IndexPath, with width: CGFloat) -> CGFloat
{
if let post = posts?[indexPath.item], let photo = post.floverImg {
let boundingRect = CGRect(x: 0, y: 0, width: width, height: CGFloat(MAXFLOAT))
let rect = AVMakeRect(aspectRatio: photo.size(), insideRect: boundingRect)
return rect.size.height
}
return 200
}
https://ibb.co/J3KdDtG
https://ibb.co/JzXZv3V

Swift UICollectionView Show/Hide Items on Tap

Within a UICollectionView, I would like to show/hide more content when an item is tapped.
Currently, I am doing this by designing a larger cell on a Storyboard, with just the UILabel I want to always show at the top. When an item is tapped, the didSelectItemAt() and sizeForItemAt() calls are coded as:
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
selectedIndex = indexPath.item
print("didSelectItemAt: \(selectedIndex)")
collectionView.reloadItems(at: [indexPath])
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
var size = CGSize()
size.width = collectionView.frame.width
size.height = 50
if let index = selectedIndex {
print("SizeForItemAt item:\(indexPath.item), \(index)")
if index == indexPath.item {
size.height = 150
} else {
size.height = 50
}
}
return size
}
Which has this output (taken from an iPhone Simulator screen capture, converted to GIF). Note, when hiding/reducing the height on the higher item, the blue box animates behind the lower item.
Is there a better way to implement this?
You can achieve this by adding UILabel as collectionview Section and expandad/collapsed view as row. When user select label , you can change rows height
Declare section number :
func numberOfSections(in collectionView: UICollectionView) -> Int {
return 2
}
Declare row count in section:
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
if indexPath.section == 0{
return 1
}
else indexPath.section == 1{
return 1
}
return 0
}
Then fill your section and rows in cellForRowAt
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cellID", for: indexPath) as! CellViewController
if indexPath.section == 0{
cell.yourLabel.text = "bla bla"
if indexPath.row == 0{
// You can declare another cell in here
let blueViewCell = collectionView.dequeueReusableCell(withReuseIdentifier: "blueViewCellID", for: indexPath) as! BlueViewController
}
}
}
And in sizeForItemAt function
func collectionView(_ collectionView : UICollectionView,layout collectionViewLayout : UICollectionViewLayout,sizeForItemAt indexPath : IndexPath) -> CGSize{
if indexPath.section == 0{
if indexPath.row == 0{
if firstSectionOpened == true {
return 50
}else{ return 0 }
}
let width = collectionView.frame.width / CGFloat(4)
return CGSize(width: width, height: width)
}
}
Then in didSelect
var firstSectionOpened : Bool = false
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
if indexPath.section == 0 {
if firstSectionOpened == true{
firstSectionOpened = false
}
else{
firstSectionOpened = true
}
self.myCollection.reloadData()
}
}

Scroll conflict for multiple CollectionView in a ViewController

I have two UICollectionView collectionViewA and collectionViewB in my ViewController, collectionViewB is presented as a subView when a button is tapped, the issue i have now is that when i scroll on collectionViewB, collectionViewA scrolls too, is there a way to only scroll for the active collectionView without affecting the second.?
extension TrendListVC: UICollectionViewDelegate,
UICollectionViewDataSource, UICollectionViewDelegateFlowLayout{
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
if collectionView == self.collectionViewForSubView{
return count
}
return 60
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
if collectionView == self.collectionViewForSubView{
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellId, for: indexPath) as! ModalViewCell
//let setting = settings[indexPath.item]
//cell.setting = setting
return cell
}else{
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell2", for: indexPath) as! CollectionCell
cell.itemNameLabel.text = "Name".uppercased()
return cell
}
}
func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView {
var reusableView : CollectionHeader? = nil
if collectionView == self.collectionView{
if (kind == UICollectionElementKindSectionHeader) {
let head = collectionView.dequeueReusableSupplementaryView(ofKind: UICollectionElementKindSectionHeader, withReuseIdentifier: "headerCell", for: indexPath) as! CollectionHeader
head.trendListVc = self
head.headerHeightConstraint = headerHeightConstraint
reusableView = head
}
}
return reusableView!
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
if collectionView == self.collectionViewForSubView{
if count % 2 != 0 && indexPath.item == count - 1{
let paddingSpace = sectionInsets.left * (itemsPerRowForSubView + 1)
let availableWidth = collectionViewForSubView.frame.width - paddingSpace
return CGSize(width: availableWidth + 23, height: cellHeight)
}else{
let paddingSpace = sectionInsets.left * (itemsPerRowForSubView + 1)
let availableWidth = collectionViewForSubView.frame.width - paddingSpace
let widthPerItem = availableWidth / itemsPerRowForSubView
return CGSize(width: widthPerItem, height: cellHeight)
}
}else{
let paddingSpace = sectionInsets.left * (2 + 1)
let availableWidth = view.frame.width - paddingSpace
let widthPerItem = availableWidth / itemsPerRow
return CGSize(width: widthPerItem + 4, height: widthPerItem)
}
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForHeaderInSection section: Int) -> CGSize {
if collectionView == self.collectionView{
return CGSize(width: view.frame.width, height: 50)
}else{
return CGSize(width: 0, height: 0)
}
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
if collectionView == self.collectionView{
showControllerForSetting(setting: "Name")
}else if collectionView == self.collectionViewForSubView{
print("Some thing")
}
}
}
This is most likely due to using your ViewController as delegate and datasource for both of your collection views. You need to create separate delegate classes for each collection view.

How to add an extra static cell to my UICollectionView?

I have an array of photos that I currently display in a UICollectionView. The only thing I still want to add is an extra static cell that should give the user the possibility to open the camera. I used an if-else statement to detect the index. Unfortunately, the console gives me an out of index error.
To be precise: I want this static cell to be in the top left corner, followed by my array of images. Do I have to add two sections, or should I register another custom cell to accomplish this? As of now I can see my extra cell, but it's not working when tapped (out of index).
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return imageArray.count + 1
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: photoId, for: indexPath) as! PhotosCollectionViewCell
if indexPath.row == imageArray.count {
cell.backgroundColor = UIColor.lightGray
cell.addGestureRecognizer(UIGestureRecognizer(target: self, action: #selector(tappedCamera)))
} else {
cell.imageView.image = imageArray[indexPath.item]
cell.imageView.addGestureRecognizer(UIGestureRecognizer(target: self, action: #selector(tappedPhoto)))
}
return cell
}
Updated code (solution)
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return imageArray.count + 1
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
if indexPath.row == 0 {
let cameraCell = collectionView.dequeueReusableCell(withReuseIdentifier: cameraId, for: indexPath) as! CameraCollectionViewCell
return cameraCell
}
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(tappedPhoto))
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: photoId, for: indexPath) as! PhotoCollectionViewCell
cell.imageView.image = imageArray[indexPath.row - 1]
cell.imageView.addGestureRecognizer(tapGesture)
return cell
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
if indexPath.row == 0 {
print("Camera")
}
}
var startingFrame: CGRect?
var blackBackGroundView: UIView?
var selectedImageFromPicker: UIImage?
var selectedImageCompressed: UIImage?
func tappedPhoto(sender: UIGestureRecognizer) {
if let indexPath = self.collectionView?.indexPathForItem(at: sender.location(in: self.collectionView)) {
let imageView = self.collectionView?.cellForItem(at: indexPath)
startingFrame = imageView?.superview?.convert((imageView?.frame)!, to: nil)
let zoomingImageView = UIImageView(frame: startingFrame!)
zoomingImageView.image = imageArray[indexPath.row - 1]
zoomingImageView.isUserInteractionEnabled = true
zoomingImageView.contentMode = .scaleAspectFill
zoomingImageView.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(handleZoomOut)))
if let keyWindow = UIApplication.shared.keyWindow {
blackBackGroundView = UIView(frame: keyWindow.frame)
blackBackGroundView?.backgroundColor = UIColor.black
blackBackGroundView?.alpha = 0
keyWindow.addSubview(blackBackGroundView!)
keyWindow.addSubview(chooseLabel)
keyWindow.addSubview(zoomingImageView)
// Set selected image and compress
selectedImageFromPicker = imageArray[indexPath.row - 1]
selectedImageCompressed = selectedImageFromPicker?.resized(withPercentage: 0.1)
chooseLabel.rightAnchor.constraint(equalTo: keyWindow.rightAnchor, constant: -25).isActive = true
chooseLabel.bottomAnchor.constraint(equalTo: keyWindow.bottomAnchor, constant: -25).isActive = true
UIView.animate(withDuration: 0.3, delay: 0, usingSpringWithDamping: 1, initialSpringVelocity: 1, options: .curveEaseOut, animations: {
self.blackBackGroundView?.alpha = 1
self.chooseLabel.alpha = 1
let height = self.startingFrame!.height / self.startingFrame!.width * keyWindow.frame.width
zoomingImageView.frame = CGRect(x: 0, y: 0, width: keyWindow.frame.width, height: height)
zoomingImageView.center = keyWindow.center
}, completion: {(completed) in
// Do nothing
})
}
}
}
Do I have to add two sections, or should I register another custom
cell to accomplish this?
In your case, just adding one cell at the beginning of the collection should be fair enough, there is no need to multi-section it.
Your methods should be implemented as follows:
1- numberOfItemsInSection method: should be as is:
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return imageArray.count + 1
}
2- cellForItemAt method: depends on the first cell, if it should be a different cell:
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
// first row
if indexPath.row == 0 {
let cameraCell = collectionView.dequeueReusableCell(withReuseIdentifier: "cameraCell-ID", for: indexPath)
// setup the cell...
return cameraCell
}
let defaultCell = collectionView.dequeueReusableCell(withReuseIdentifier: "defaultCell-ID", for: indexPath)
// setup default cell...
return defaultCell
}
Or, if you want it to be the same cell, but with some editions:
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell-ID", for: indexPath)
// first row
if indexPath.row == 0 {
// setup the cell as cemera cell...
} else {
// setup the cell as default cell...
}
return cell
}
Actually, there is no need to add UITapGestureRecognizer for each cell, all you have to do is to implement collection​View(_:​did​Select​Item​At:​) delegate method:
Tells the delegate that the item at the specified index path was
selected.
3- didSelectItemAt method:
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
if indexPath.row == 0 { // camera cell
// handle tapping the camera cell
} else { // default cells
// handle tapping the default cell
// don't forget that:
// getting the first element in 'imageArray' should be imageArray[indexPath.row - 1]
}
}
Hope this helped.

Two cells in single CollectionView of different dimensions

I have two cells within a single collection view. They both have different dimensions but for some reason on runtime both of the cells appear to have the same dimension.
Here's my setup:
internal func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
if cellType == .books {
return books.count
} else if cellType == .spotlights {
return spotlights.count
} else {
return 0
}
}
internal func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
if cellType == .books {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "booksCollectionCell", for: indexPath) as! BooksCollectionCell
let bookTitle = books[indexPath.item].title
let authors = books[indexPath.item].authors
cell.configureCell(title: bookTitle, authorNames: authors)
return cell
} else {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "spotlightsCollectionCell", for: indexPath) as! spotlightsCollectionViewCell
cell.configureCell(image: #imageLiteral(resourceName: "testImage"))
return cell
}
}
Here's my storyboard screenshots:
and this is setup for collectionView:
edit: So I managed to get somwhere (thanks to cpatmulloy) by putting this code in cellForItem:
cell.frame = CGRect(x: cell.frame.origin.x, y: cell.frame.origin.y, width: 180.0, height: 130.0)
However, here's the result (look at the last cell in tableview):
Try explicitly setting the cell's height and width in the cellForItemAtIndex Path function.
Be sure to set these example properties (i.e bookCellWidth) yourself
internal func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
if cellType == .books {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "booksCollectionCell", for: indexPath) as! BooksCollectionCell
let bookTitle = books[indexPath.item].title
let authors = books[indexPath.item].authors
cell.configureCell(title: bookTitle, authorNames: authors)
cell.frame = CGRect(x: cell.frame.origin.x, y: cell.frame.origin.y, width: bookCellWidth, height: bookCellHeight)
return cell
} else {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "spotlightsCollectionCell", for: indexPath) as! spotlightsCollectionViewCell
cell.configureCell(image: #imageLiteral(resourceName: "testImage"))
cell.frame = CGRect(x: cell.frame.origin.x, y: cell.frame.origin.y, width: spotlightCellWidth, height: spotlightCellHeight)
return cell
}
}
Ok so I managed to fix it!
First I added UICollectionViewDelegateFlowLayout to the cell class, then:
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
if cellType == .spotlights {
return CGSize(width: 250.0, height: 180.0)
} else {
return (collectionViewLayout as! UICollectionViewFlowLayout).itemSize
}
}

Resources