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!
Related
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
}
When I want to see an array in a collection view in swift, it gets multiplied by the amount of sections in the collection view. Why is this and how do I stop it?
let numbers = ["one", "two", "three"]
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 3;
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let theCell = collectionView.dequeueReusableCell(withReuseIdentifier: "theCell", for: indexPath) as! cell
for number in numbers {
print("\(number)")
}
return theCell
}
I hoped that it would return:
one
two
three
but instead it returned:
one
two
three
one
two
three
one
two
three
Since you have three cells per section, and assuming you have only one section, collectionView(_:cellForItemAt:) gets called three times. Each time you are printing all the elements of the numbers array. To only print the element corresponding to the current index, replace the for loop by:
print(numbers[indexPath.row])
My app includes two collectionViews , mainCollectionView and nestedCollectionView which is in the mainCollectionViewCell .
It's like the iPhone calendar app , each cell in the mainCollectionView has nestedCollectionView which represents a month(the number of the cells will be the number of the month days).
class cell_Main:UICollectionViewCell{
let collectionView:UICollectionView = {
let cv = nestedCollectionView()
cv.backgroundColor = .white
return cv
}()
to update the nestedcollectionView if the month changes , I"ve used nestedcollectionView.reloadData() inside the method(which belongs to mainCollectionView ):
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell_main", for: indexPath) as! cell_Main
let nested_CollectionView = cell.collectionView as! nestedCollectionView
.
.
.
nested_CollectionView.reloadData()
}
! if I scroll the mainCollectionView, the nestedCollectionView supposed to be updated (the month will be changed).
my question: the code works fine , but is it the right way to reloadData() here?, does it an expensive CPU work, does the app use too much CPU?
instead of using nested Collection View which represent month in a year , I've tried to make one Main CollectionView , and the number of sections will be 12 (the months number) , each section represent month and in each section the numberOfItemsInSection will be the month days number . and any updation can be here(without using reloadData()):
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
}
.finally when we scroll down to the end section we would call reloadData() to update the new numberOfSections and move to the next year .
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 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.