I am trying to recreate the tinder card stack which can then be swiped through. I have decided to do this using UIcollectionView.
I was going to make an array of user objects and within each, there would be an array of images. So for the number of sections, I would say arr.count and for the number of sub-sections arr[section].arrImg.count.
Currently, I have a problem where when I run the project I get a vertical stack of 5 images. I assume each image represents one cell. But I need these cells to be stacked on top of each other like tinder.
How can I do that (stacked on top of each other like tinder)?
The logic for making the card layout:
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
print(peopleArr[section].arrOfProfileImages.count, "jfldhsajklfhsdkj")
return peopleArr[section].arrOfProfileImages.count
}
//This current version loads all people it should only return like 3...
func numberOfSections(in collectionView: UICollectionView) -> Int {
print("fkhdsgafhjdgsajhfgdsak", peopleArr.count)
return peopleArr.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cardCell", for: indexPath) as! DatingCardCollectionViewCell
cell.imageView.image = UIImage(named: "ProfileImage")//peopleArr[indexPath.row].arrOfProfileImages[indexPath.section]
return cell
}
Related
How can I have a UICollection View, with One cell in the first row, and three cells in the second row?
I want to display a picture in the first row, and below it 3 pictures.
You need to use collectionView's Datasource method number of section to specify how many section you required in your collectionview. in that section you can pass number of cell you want to display. and in cell for item you can set data according to section and Item value.
try like this.
func numberOfSections(in collectionView: UICollectionView) -> Int {
return 3 // you can return as per your requirement
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
if section == 0 {
return 2 // number of cell you want to display in each section
}else if section == 1 {
return 3 // number of cell you want to display in each section
}else {
return 4 // number of cell you want to display in each section
}
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: reuseIdentifierCollection, for: indexPath) as! HomeCollectionViewCell
return cell
}
You need to implement your own custom layout. By default the collection view has UICollectionViewFlowLayout, that fills the cells in a horizontal/vertical grid.
You can change this behaviour with your own layout, i.e. a class implementing UICollectionViewLayout.
To get started, I would recommend checking this and this tutorials.
I have a UICollectionView, which has 2k+ records. At anytime only 6-7 rows will be visible and I'm using reusable cells. Everything works fine.
But when I make a console log in cellForRowAtIndexPath, initially 80+ rows are being loaded. After that it loads 1st 7 rows again, and properly loads only the visible cells.
Why does it load 80+ rows initially. This make a slight lag in initial loading.
func numberOfSections(in collectionView: UICollectionView) -> Int {
return 1
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return results.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
print("Cell For Row -> \(indexPath)")
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "ResultCell", for: indexPath) as! ResultCell
cell.data = result[indexPath.item]
return cell
}
UPDATE:
I was using auto-sizing cells. So I did define estimatedItemSize as UICollectionViewFlowLayoutAutomaticSize
I tried defining a proper CGSize instead of UICollectionViewFlowLayoutAutomaticSize. And the extra cells stopped loading.
While performing autosizing cells, we give estimatedItemSize.
On using UICollectionViewFlowLayoutAutomaticSize for estimatedItemSize, the collectionview tries to load a countable number of cells (visible and non-visible) and get the estimated size.
If a proper CGSize (estimated) is given, the extra cells(non-visible) would be loaded less. So, the closer your estimated size is, the lesser non-visible cells are loaded.
What is the most common way to delete cells from a UICollectionView?
In a UITableView I use the editActionsForRowAt or editingStyle methods to delete rows, does UIControllerView has something similar or you need to implement your own deleting method?
What I have is a UICollectionView with a lot of photos where each cell/photo is attached to a segue which takes you to a larger version of the photo.
The easiest way I could be to do it in the didSelectItemAt method but in my case that is not an option since as soon as a photo is tapped it segues to the other viewController (larger image).
What would be the best way to add a deleting functionality in a situation like the one I'm describing above?
The following threads show how to delete using the didSelectItemAt.
How to add a delete button to Collection View Cell in Swift?
How to delete item from collection view?
CODE
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return fruits.count
}
public func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell{
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "fruitCustomCell", for: indexPath) as! fruitCollectionViewCell
cell.labelFruitName.text = fruits[indexPath.row].fruitName
return cell
}
App Diagram
This is a really basic wireframe of what I'm trying to achieve:
This is what I currently have in Xcode, resulting in 3 cells per row, with no space in between. The date label cell isn't showing up because I don't know how to get cellForItem to recognize it along with the post cells (hence the question):
I have two separate cell classes - one for the date labels and one for the rows of images.
My collection view methods are as follows:
func numberOfSections(in collectionView: UICollectionView) -> Int {
return 1
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return posts.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "postCell", for: indexPath) as! PostCell
let dateCell = collectionView.dequeueReusableCell(withReuseIdentifier: "dateLabelCell", for: indexPath) as! DateLabelCell
cell.postImage.loadImageUsingCacheWithUrlString(posts[indexPath.row].pathToImage)
cell.postID = posts[indexPath.row].postID
cell.postImage.contentMode = UIViewContentMode.scaleAspectFill
// Here I'll have to get the date and have the labels display the days of the week properly
dateCell.dateLabel.text = "Monday"
return cell
}
But I'm not sure how to manage both cells in the above methods. I'll have to sort the posts by a timestamp so things posted on a certain day get added to the correct day's row, but that's something I'll do another day - for now I'm just wondering how I can get the UI laid out so that the collection view shows a date label, then a row of post cells, and repeat.
Thanks for any advice!
I have created a collection view that pulls from an array of images (8 right now, but user can add more). I originally was using a scrollview, but found it easier with a collection, and thanks to this great community, went to a collection view. I need to find the indexPath to delete an item at a given point. So here is some code I have so far, but I am new to this specifically. Here is some code I currently have.
class ViewController: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource {
#IBOutlet weak var myCollectionView: UICollectionView!
func numberOfSections(in collectionView: UICollectionView) -> Int {
return 1
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return imageArray.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! UserFeedCollectionViewCell
cell.myImage.image = UIImage(named: imageArray[indexPath.row])
cell.myImage.layer.cornerRadius = 12.0
cell.myImage.clipsToBounds = true
return cell
}
//delete item at current item - 2
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
if indexPath.row > 2 {
myCollectionView.deleteItems(at: [])
}
}
Hope this will help and feel free to ask in the comments if you have a question.
Edit: Paging is enabled, and it is horizontal scrolling, and each image takes up the whole cell.
How about keeping an array of tapped on image indices?
Define a variable for the indexes at the top:
var selected = [IndexPath]()
Then implement didSelectItemAt as:
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
selected.append(indexPath)
if selected.count > 2 {
let ndx = selecte.count - 3
let twoBack = selected[ndx]
myCollectionView.deleteItems(at:[twoBack])
}
}
The above would work fine for the first selection, but at that point, you would need to figure out how you handle the next selection - whether you wipe the selected array and start over, or need to keep track of further selections to handle the next input.
Depending on how you want to proceed, the selected array would either need to be wiped or to be modified to remove the item that was deleted.