Cells for CollectionView Are Not All Showing - swift

The code below is my test files for my final project that will look like this. As you can see I will be scrolling by rows of one or two.
I have figured out how to get the horizontal scroll to work, however, it only displays two out of the six buttons as shown here in the simulator. As You can tell, it just repeats itself. I am needing the app to show app six buttons respectively.
The code for this:
var multiButton = [String]()
class ViewController: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource {
var multiButton = ["faceButton", "faceButtonTwo", "faceButtonThree", "faceButtonFour", "faceButtonFive", "faceButtonSix"]
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return multiButton.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell=collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! MyCollectionViewCell
// cell.multiButton.layer.cornerRadius=50.0
return cell
// cell.myWebSeriesImage.image=UIImage(named: webSeriesImages[indexPath.row])
// return cell
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
}
I have a separate file with all my IBOutlets as shown in this code:
import UIKit
class MyCollectionViewCell: UICollectionViewCell {
// var multiButton = ["faceButton", "faceButtonTwo", "faceButtonThree", "faceButtonFour", "faceButtonFive", "faceButtonSix"]
#IBOutlet weak var faceButtonFour: UIButton!
#IBOutlet weak var faceButtonFive: UIButton!
#IBOutlet weak var faceButtonThree: UIButton!
#IBOutlet weak var faceButtonTwo: UIButton!
#IBOutlet weak var faceButton: UIButton!
#IBOutlet weak var faceButtonSix: UIButton!
I have double checked the Identifiers, classes (class for cells are set for "myCollectionViewCell", which is the same file all IBOutlets are in), made sure all UIButtons were Installed, and have tried to find any abnormalities in the Attributes and Identity Inspector.
I also would like to address the issue of not being able to scroll horizontal without clicking outside the button.
UPDATE for Post:
This is what we are seeing currently after a previous comment to resize the collectionview. It continues to repeat over and over and I am struggling to find the reasons in my code.
This is a screenshot of main.storyboard.

This is very basic. You need to create something like this:
First create a collectionView with required height (50 for example) and add a button inside its cell. Give any width or height to the button (maybe 80 x 30) and add leading, trailing, top and bottom constraints. Make sure to change scroll direction to horizontal as required by you.
After that create a collectionView class and connect your button outlet to it:
import UIKit
class ButtonCollectionViewCell: UICollectionViewCell {
#IBOutlet weak var button: UIButton!
override func awakeFromNib() {
super.awakeFromNib()
}
}
In your main ViewController, connect collectionView and add delegate & datasource function:
import UIKit
class ViewController: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource {
#IBOutlet weak var collectionViewButtons: UICollectionView!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
collectionViewButtons.delegate = self
collectionViewButtons.dataSource = self
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 6 //number of buttons
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! ButtonCollectionViewCell
cell.button.setTitle("Button\(indexPath.item)", for: .normal) //set button title
if indexPath.item == 0 { //first button
cell.button.backgroundColor = UIColor.purple //set button background
}
else if indexPath.item == 1 { //second button
cell.button.backgroundColor = UIColor.red
}
else if indexPath.item == 2 { //3rd button
cell.button.backgroundColor = UIColor.systemGreen
}
else { // for remaining buttons
cell.button.backgroundColor = UIColor.darkGray
}
return cell
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
if indexPath.item == 0 { // opens any page by clicking button 1
let vc = storyboard?.instantiateViewController(withIdentifier: "anyVC1") as! ViewController1
navigationController?.pushViewController(vc, animated: true)
}
else if indexPath.item == 1 {
let vc = storyboard?.instantiateViewController(withIdentifier: "anyVC2") as! ViewController2
navigationController?.pushViewController(vc, animated: true)
}
else if indexPath.item == 2 {
let vc = storyboard?.instantiateViewController(withIdentifier: "anyVC3") as! ViewController3
navigationController?.pushViewController(vc, animated: true)
}
else {
let vc = storyboard?.instantiateViewController(withIdentifier: "anyVC4") as! ViewController4
navigationController?.pushViewController(vc, animated: true)
}
}
}
You can return any number of buttons by changing return 6 to any required number or use any array which can further be used to set properties of buttons created.
The didSelectAnItem can be used to add functionality when a cell is tapped.
In the end you should get output like this where you can scroll horizontally to see remaining buttons:

Related

UICollectionView Cells overlapping with each other when i use a button to increase cell height

I have a CollectionView setup and i have a button inside that increases the cell height by a fixed amount. However when it does this is overlapps with the cell below meaning the cell below doesnt move down to make space.
Ive been trying to figure this out for days and i cant seem to get it working.
class ViewController: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource {
var colors = [UIColor.red,UIColor.blue]
#IBOutlet weak var col: UICollectionView!
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 2
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! cellCollectionViewCell
cell.frame.size.height = CGFloat(317 + cell.button.tag*45)
cell.backgroundColor = colors[indexPath.row]
return cell
}
#IBAction func increaseHeight(_ sender: Any) {
col.reloadData()
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
}
class cellCollectionViewCell: UICollectionViewCell {
#IBOutlet weak var butt: UIButton!
#IBAction func incHeight(_ sender: UIButton) {
sender.tag = sender.tag + 1
}
}
Editing the frame of the cell directly is probably not the best approach. Instead override collectionView sizeForItemAtIndexPath, and specify the height change there. This should allow the collection view to re-layout correctly with the new cell height.
You can see other questions like this one for more details

IBOutlet pageControl is invalid

I trying to add pageControl in viewController for display current page and total pages.
I have collectionView inside viewController. But if i add #IBOutlet in viewController i get the error:
"The pageControl outlet from the DetailViewController to the UIPageControl is invalid. Outlet cannot be connected to repeating content."
That means repeating content?
I understand that this question has been asked many times, but I tried what was suggested but nothing helped.
PageControl in main.storyboard have only one #IBOutlet and it throws an error...
If need my code, he is here:
class DetailViewController: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource, UITableViewDelegate, UITableViewDataSource {
// MARK: - IBOutlet's
#IBOutlet weak var collectionView: UICollectionView!
#IBOutlet weak var tableView: UITableView!
#IBOutlet weak var pageControl: UIPageControl!
var hallImages: Hall?
var currentPage = 0
override func viewDidLoad() {
super.viewDidLoad()
}
override func viewWillAppear(_ animated: Bool) {
tableView.estimatedRowHeight = 626
tableView.rowHeight = UITableViewAutomaticDimension
}
// MARK: - CollectionView
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
guard let imagesHall = hallImages?.ImagesHalls.count else {
return 0
}
return imagesHall
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! DetailCollectionViewCell
if let imagesHalls = hallImages?.ImagesHalls[indexPath.item] {
cell.imageView.sd_setImage(with: URL(string: imagesHalls))
}
return cell
}
}
How i can add pageControll in collectionView or collectionCell (i don't know how is better)?
I had the same problem. It is because your page control is a subview of the cell. You cannot do this.
take it out of your cell
put it in your main view/ safe area

Trouble added cell to UICollectionView

Trying to add a cell to my ViewController, and I'm having trouble. I'm wondering if I have all my delegates. Currently, I can change the color of the collection view's background, but can't add any cells.
I'm using an array of text from my Listing() object to drive the collection view cells. On viewDidLoad the length is 4. I envisioned using this count for the numberofItemsInSection, however, if I put the print statement there it is never printed. Which makes me think the wrong delegate is called and the method is never hit. Correct?
import UIKit
class ListingDetailViewController: UIViewController,
UICollectionViewDelegateFlowLayout {
var listing = Listing()
// #IBOutlet var image: UIImageView!
#IBOutlet var post: UITextView!
#IBOutlet var price: UILabel!
#IBOutlet var amenitiesCollection: UICollectionView!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
navigationItem.title = listing.title
self.amenitiesCollection!.backgroundColor = UIColor.gray
print(listing.amenities.count)//printed 4
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int{
print(listing.amenities.count)
return listing.amenities.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let identifier = "UICollectionViewCell"
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: identifier, for: indexPath)
return cell
}
}
Make sure you have linked the CollectionView delegate and datasource to your view controller.
In viewDidLoad() add:
self.amenitiesCollection.delegate = self
self.amenitiesCollection.dataSource = self
==================================
EDIT:
If you have already linked the delegate and dataSource, try reloading the collection view in viewDidAppear(_:)
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
self.amenitiesCollection.reloadData()
}

How to select multiple images from UICollectionView and transfer them to another View Controller?

The code is written in Swift. I'm building a social app where the user can make posts. I'm using Firebase as a backend (database, storage). So, I have a UICollectionView that gets all the photos from the photo library of the device and populate the collection view using a custom cell. In the same View controller, I have another custom cell that the user can use to take a photo and use it to make a post. To make it clearer:
If the user decides to take a photo, when they click on "Use photo" they need to be presented to a new view controller that should display the photo they just took along with other options (such as title, description and tags using UITextFields & UITextView).
If the user decides to select multiple photos from their own library, I have to somehow mark those photos/cells (i.e. using a button for a checkmark), add the selected photos to an array (with some limit, maybe 10 photos top). When they click "Next" button, the array needs to be sent to the New Post View Controller where all the images should be dynamically displayed maybe using a horizontal UICollectionView (?!) (with an option to remove an image if it was selected by accident) and again, as above, have the opportunity to add title, description, etc. Now, I cannot figure out how to do any of that.
I looked for a solution, but I'm kind of stuck on this for couple days now, so help is very much welcome!
Here's what I have in the Collection View controller (PS: I didn't include the part with the function that gets the images from the Photos)
import UIKit
import Photos
class PrePhotoPostVC: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource, UINavigationControllerDelegate, UIImagePickerControllerDelegate, UICollectionViewDelegateFlowLayout {
#IBOutlet weak var nextButton: UIBarButtonItem!
var photosLibraryArray = [UIImage]()
#IBOutlet weak var collectionView: UICollectionView!
override func viewDidLoad() {
super.viewDidLoad()
checkPhotoLibraryPermission()
setupCollectionViewDelegates()
}
#IBAction func cancelButtonPressed (_ sender: UIBarButtonItem) {
dismiss(animated: true, completion: nil)
}
#IBAction func nextButtonPressed (_ sender: UIBarButtonItem) {
nextButton.isEnabled = false
}
#IBAction func takeAphotoButtonPressed (_ sender: UIButton) {
// Camera Autorization
AVCaptureDevice.requestAccess(forMediaType: AVMediaTypeVideo) { response in
if response {
if UIImagePickerController.isSourceTypeAvailable(UIImagePickerControllerSourceType.camera) {
let imagePicker = UIImagePickerController()
imagePicker.delegate = self
imagePicker.sourceType = UIImagePickerControllerSourceType.camera;
imagePicker.allowsEditing = false
self.present(imagePicker, animated: true, completion: nil)
}
else {
print("Camera isn't available in similator")
}
}
else {
print("unautorized")
}
}
}
func numberOfSections(in collectionView: UICollectionView) -> Int {
return 2
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
if section == 0 {
return 1
} else {
return photosLibraryArray.count
}
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
if indexPath.section == 0 {
let cellCamera = collectionView.dequeueReusableCell(withReuseIdentifier: cellPrePostCameraCell, for: indexPath)
return cellCamera
}
else {
let cellPhotoLibrary = collectionView.dequeueReusableCell(withReuseIdentifier: cellPrePostPhotoLibrary, for: indexPath) as! PrePhotoPostPhotoLIbraryCell
cellPhotoLibrary.awakeFromNib()
cellPhotoLibrary.photoLibraryImage.image = photosLibraryArray[indexPath.row]
return cellPhotoLibrary
}
}
}
A screenshot of what this UICollectionView looks like:
Here's my code from the Photo Library Cell:
import UIKit
class PrePhotoPostPhotoLIbraryCell: UICollectionViewCell {
// MARK: Outlets
#IBOutlet weak var photoLibraryImage: UIImageView!
// var selectedPhotos = [UIImageView]()
#IBAction func selectedButtonPressed(_ sender: UIButton) {
self.layer.borderWidth = 3.0
self.layer.borderColor = isSelected ? UIColor.blue.cgColor : UIColor.clear.cgColor
}
override func awakeFromNib() {
photoLibraryImage.clipsToBounds = true
photoLibraryImage.contentMode = .scaleAspectFill
photoLibraryImage.layer.borderColor = UIColor.clear.cgColor
photoLibraryImage.layer.borderWidth = 1
photoLibraryImage.layer.cornerRadius = 5
}
}
First of all declare an array of mutable type that will store the selected cells item in it.
var _selectedCells : NSMutableArray = []
then in your viewDidLoad function add below code.
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
//this will allow multiple selection on uicollectionviewcell
CollectionView.allowsMultipleSelection=true //CollectionView is your CollectionView outlet
}
Then, Implement delegate functions of collectionview for selecting and deselecting cells
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath){
//add the selected cell contents to _selectedCells arr when cell is selected
_selectedCells.add(indexPath)
collectionView.reloadItems(at: [indexPath])
}
func collectionView(_ collectionView: UICollectionView, didDeselectItemAt indexPath: IndexPath) {
//remove the selected cell contents from _selectedCells arr when cell is De-Selected
_selectedCells.remove(indexPath)
collectionView.reloadItems(at: [indexPath])
}
I'd suggest saving the NSIndexPath of the selected item in an array, and then using that for the basis of comparison in the delegate function cellForItemAt indexPath.
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "YOUR_CELL_Identifier", for: indexPath as IndexPath)
//add your tick mark image to the cell in your storyboard or xib file.
let tickImage = cell.viewWithTag(YOUR_IMAGE_TAG_HERE) as? UIImageView
//Show tickImage if the cell is selected and hide tickImage if cell is NotSelected/deSelected.or whatever action you want to perform in case of selection and deselection of cell.
if _selectedCells.contains(indexPath) {
cell.isSelected=true
collectionView.selectItem(at: indexPath, animated: true, scrollPosition: UICollectionViewScrollPosition.top)
tickImage?.isHidden=false
}
else{
cell.isSelected=false
tickImage?.isHidden=true
}
return cell
}
In Order to send items to next controller, get all the items from selected indexpaths.

collectionView's didSelectItemAtIndexPath not working [Swift]

I've been having this problem recently, and I couldn't seem to find a fix on any other similar questions. I have a collectionView which just display's colours (see below image) and I would like to store the cell's background colour in a variable to pass through an unwind segue, in order to set a background colour of another element. However, I can't seem to get this function to work as it has on previous projects and versions of this application and I was wondering if anyone knows what the problem might be ?
After pressing the 'add' button at the bottom, it unwinds and appends a new item to another collectionView, seen here:
I am able to get the name that the user has put in, however I have to use a default colour as I can't seem to get the didSelectItemAtIndexPath function to work.
Here's my code for the addViewController (first image)
import UIKit
import ChameleonFramework
class mondayViewController: UIViewController {
// collectionView
#IBOutlet var dayView: UICollectionView!
// data to display
var data = Day.mondayData()
// data from segues
var receivedName: String?
var receivedColour: UIColor?
override func viewDidLoad() {
super.viewDidLoad()
// set title
self.navigationController!.navigationBar.topItem!.title = "Monday"
// set datasource for collectionView
// datasource is self as the collectionViewDataSource methods are in the extension class below
dayView.dataSource = self
// make the navigationBar flat to flow onto the options tab
self.navigationController?.hidesNavigationBarHairline = true
}
#IBAction func unwindToMonday(segue: UIStoryboardSegue) {
if segue.identifier == "mondayUnwind" {
let subjectAdd = segue.sourceViewController as! mondayAddSubjectView
receivedName = subjectAdd.nameField.text
appendStuff()
}
}
func appendStuff() {
data.append(Day(name: receivedName, color: UIColor.flatRedColor()))
dayView.reloadData()
}
override func preferredStatusBarStyle() -> UIStatusBarStyle {
return UIStatusBarStyle.LightContent
}
// data.append(Day(name: receivedName, color: receivedColour))
// dayView.reloadData()
// currently used for testing
#IBAction func mondayAddButton(sender: AnyObject) {}
}
// mandatory functions for UICollectionView to work
// this includes assigning the number of sections, how manycells are meant to be in the section(s) and what cell to use (mondayCell in this case)
extension mondayViewController: UICollectionViewDataSource {
func numberOfSectionsInCollectionView(collectionView: UICollectionView) -> Int {
return 1
}
func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return data.count
}
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCellWithReuseIdentifier("cell", forIndexPath: indexPath) as! mondayCell
cell.data = self.data[indexPath.item]
return cell
}
func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) {
let cell = collectionView.cellForItemAtIndexPath(indexPath)
}
// custom style the size of the collectionView. Changes the width to fill the screen and the height to 70
func collectionView(collectionView: UICollectionView,
layout collectionViewLayout: UICollectionViewLayout,
sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize {
let kWhateverHeightYouWant = 80
return CGSizeMake(collectionView.bounds.size.width, CGFloat(kWhateverHeightYouWant))
}
}
if anyone could let me know if I am doing something wrong, or if there is a solution to this issue, that would be awesome.
Cheers,
Rowan
UPDATE:
I have added the collectionViewDataSource and Delegate Methods to the main class (code below):
import UIKit
import ChameleonFramework
class mondayAddSubjectView: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource {
var pageView: PageViewController = PageViewController()
#IBOutlet var selectColourLabel: UILabel!
// would be a public variable, however it is an internal class
internal var cellColour: UIColor!
// collectionView
#IBOutlet var colourPicker: UICollectionView!
// textfield for the user to input their subject name
#IBOutlet var nameField: UITextField!
// source of colours to use in the colour collectionView
private var data = collectionViewColors.createColor()
override func viewDidLoad() {
super.viewDidLoad()
self.colourPicker.delegate = self
colourPicker.dataSource = self
// gesture recognizer to determine when the user has tapped anywhere but the text field, which cancells the keyboard
let tap: UIGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(mondayAddSubjectView.dismissKeyboard))
view.addGestureRecognizer(tap)
}
// dismiss keyboard when the user taps away from the text field (called above with #selector)
func dismissKeyboard() {
view.endEditing(true)
}
// MARK: - CollectionView Delegate and Data source methods
func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) {
let cell = collectionView.cellForItemAtIndexPath(indexPath)
print("it works")
}
// choose how many sections are in the collectionView. as no content break is required, this will be 1
func numberOfSectionsInCollectionView(collectionView: UICollectionView) -> Int {
return 1
}
// choose how many items are in each section. as there is only 1 section, it will be the number of stored items
func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return data.count
}
// set re-use identifier and the data that will go in each cell
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCellWithReuseIdentifier("cell", forIndexPath: indexPath) as! colourCell
cell.data = self.data[indexPath.item]
return cell
}
}