I have a collection view (CollectionViewController) with 3 cells (each cell has it's own class). In the first cell (TextCell) I have a text field and a button (nextButton). When I press the button I want to check if the text field is empty or not. If it's not empty, I want to switch to the second cell.
CollectionViewController:
let textCell = TextCell()
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: self.cellId, for: indexPath)
// TextCell
if indexPath.item == 0 {
let tCell = collectionView.dequeueReusableCell(withReuseIdentifier: textCellId, for: indexPath)
let nextButton = textCell.nextButton
nextButton.addTarget(self, action: #selector(handleNextButton), for: .touchUpInside)
return tCell
}
return cell
}
//Handle Action
#objc func handleNextButton() {
let text = textCell.TextField.text
if text?.isEmpty == false {
scrollToIndex(menuIndex: 1)
} else {
print("Text field is empty.")
}
}
The problem is that every time i check if the text field is empty or not, it say's it is empty although it's not.
To identify whether the UITextField inside UICollectionViewCell is empty or not, you need to pass index position when button is clicked. To pass index position you can use tag. By using tag you can get clicked index position. After getting position, you can access elements from current index position by using cellForItemAtIndexPath . You can find the particular index position UITextField is empty or not using the fetched cell reference
In Your cellForItemAt
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
if indexPath.item == 0{
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "YOUR_CELL_IDENTIFIER", for: indexPath) as! YOUR_UICOLLECTIONVIEW_CELL
cell.nextBtn.tag = indexPath.item
cell.nextBtn.addTarget(self, action: #selector(handleNextButton(_:)), for: .touchUpInside)
return cell
} else {
///use your other cells here
}
}
In your ViewController
func handleNextButton(_ sender:UIButton){
let indexPath = IndexPath(item:sender.tag,section:0)
let cell = YOUR_COLLECTIONVIEW.cellForItem(at: indexPath) as! YOUR_UICOLLECTIONVIEW_CELL
if cell.txtFld.text == "" {
print("TextField is empty")
} else {
print("TextField not empty")
}
}
Hope this will help you
First - Remove the next line, It's not needed and is definitely wrong!
let textCell = TextCell()
Now replace your func with that:
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
// TextCell
if indexPath.item == 0 {
let tCell = collectionView.dequeueReusableCell(withReuseIdentifier: textCellId, for: indexPath) as! TextCell
let nextButton = tCell.nextButton
nextButton.addTarget(self, action: #selector(handleNextButton), for: .touchUpInside)
return tCell
}
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: self.cellId, for: indexPath)
return cell
}
And The Handler
//Handle Action
#objc func handleNextButton(sender: UIButton) {
let tCell = sender.superview as! TextCell
let text = tCell.TextField.text
if text?.isEmpty == false {
scrollToIndex(menuIndex: 1)
} else {
print("Text field is empty.")
}
}
Related
I have a UICollectionView with 4 UICollectionViewCells. Each cell contains a UITableView with a varying number of cells.
I have an array from which I need to pass a value (depending on the indexPath) into the cell. My problem is that it always gives me nil when I try to do this.
So for example I have this array:
let arrayOfStrings = ["test1", "test2", "test3", "test4"]
I have this code in my collection view's cellForItemAt method:
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "testCollectionViewCell", for: indexPath) as! TestCollectionViewCell
cell.myString = arrayOfStrings[indexPath.row]
cell.label.text = "This text is set."
return cell
}
The cell's label is set properly, but when I try to print myString in the cell's table view's cellForRowAt method it always returns nil.
I need the string because I plan to manipulate the table views depending on the string passed in.
So why is this happening and what can be done?
You can try like this
extension HomeViewController : UITableViewDelegate, UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 4
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if indexPath.row == 0 {
let cell = tableView.dequeueReusableCell(withIdentifier: "DealTableViewCell", for: indexPath) as! DealTableViewCell
cell.DealCollectionView.dataSource = self
cell.DealCollectionView.delegate = self
cell.DealCollectionView.tag = 10101
return cell
} else if indexPath.row == 1 {
let cell = tableView.dequeueReusableCell(withIdentifier: "BusinessTableViewCell", for: indexPath) as! BusinessTableViewCell
cell.BusinessCollectionView.dataSource = self
cell.BusinessCollectionView.delegate = self
cell.BusinessCollectionView.tag = 10102
return cell
} else if indexPath.row == 2 {
let cell = tableView.dequeueReusableCell(withIdentifier: "FilterTableViewCell", for: indexPath) as! FilterTableViewCell
cell.FilterCollectionView.dataSource = self
cell.FilterCollectionView.delegate = self
cell.FilterCollectionView.tag = 10103
return cell
} else {
let cell = tableView.dequeueReusableCell(withIdentifier: "ComboTableViewCell", for: indexPath) as! ComboTableViewCell
cell.ComboCollectionView.dataSource = self
cell.ComboCollectionView.delegate = self
cell.ComboCollectionView.tag = 10104
return cell
}
}
}
Add the collection view to each tableview cell and set delegate in tableview cell
extension HomeViewController : UICollectionViewDelegate, UICollectionViewDataSource {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
if collectionView.tag == 10101 {
return 3
} else if collectionView.tag == 10102 {
return 3
} else if collectionView.tag == 10103 {
return 3
} else if collectionView.tag == 10104 {
return 3
}
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
if collectionView.tag == 10101 {
let cell = collectionView.dequeueReusableCell(withIdentifier: "DealCollectionViewCell", for: indexPath) as! DealCollectionViewCell
return cell
} else if collectionView.tag == 10102 {
let cell = collectionView.dequeueReusableCell(withIdentifier: "BusinessCollectionViewCell", for: indexPath) as! BusinessCollectionViewCell
return cell
} else if collectionView.tag == 10103 {
let cell = collectionView.dequeueReusableCell(withIdentifier: "FilterCollectionViewCell", for: indexPath) as! FilterCollectionViewCell
return cell
} else if collectionView.tag == 10104 {
let cell = collectionView.dequeueReusableCell(withIdentifier: "ComboCollectionViewCell", for: indexPath) as! ComboCollectionViewCell
return cell
}
return UICollectionViewCell()
}
}
For reload the collectionView in use
if let cell = self.tableView.cellForRow(at: IndexPath(row: i, section: 0)) as?
tableViewCell {
cell.collectionView.reloadData()
}
item added to the array when I am using didSelectItemAt indexPath
and the array contains more than one element, but only one cell has the picture "Rectangle Filled"
override func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
indexSelected = indexPath.item
if trashButtonIsActive == true {
selectedItems.append(indexPath.item)
// I am adding indexPath.item to the array.Which need to compare with indexPath.item in cellForItemAt method.//
} else if trashButtonIsActive == false {
if selectedItems.count != 0 {
selectedItems.removeAll()
}
self.performSegue(withIdentifier: "cardView", sender: indexPath)
}
self.collectionView.reloadData()
}
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
if trashButtonIsActive == true && selectedItems.count == 0 {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! CollectionViewCell
cell.labelText = array![indexPath.item].frontal
cell.buttonToTrash.setImage(UIImage(named: "Rectangle Empty"), for: .normal)
return cell
}else if trashButtonIsActive == true && selectedItems.count != 0 {
for index in selectedItems {
//I don't know why , but it compares only first element in the array //
if indexPath.item != index {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! CollectionViewCell
cell.labelText = array![indexPath.item].frontal
cell.buttonToTrash.setImage(UIImage(named: "Rectangle Empty"), for: .normal)
return cell
}else{
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! CollectionViewCell
cell.labelText = array![indexPath.item].frontal
cell.buttonToTrash.setImage(UIImage(named: "Rectangle Filled"), for: .normal)
return cell
}
}
}else if trashButtonIsActive == false {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! CollectionViewCell
cell.labelText = array![indexPath.item].frontal
cell.buttonToTrash.setImage(nil, for: .normal)
return cell
}
let cellTwo = collectionView.dequeueReusableCell(withReuseIdentifier: "cell hello", for: indexPath)
return cellTwo
}
I want indexPath.row's which are equal to the elements in the array to have the picture "Rectangle Filled". Would anyone be able to assist?
make your model like this
struct ModelName{
var name: String
var rectangle: Bool
}
then you array which is selected items will be like this
var selectedItems = [ModelName]()
then in viewdidload or anywhere you are trying to initialise data you can do this
selectedItems.apped(ModelName(name: "name", rectangle: false)
selectedItems.apped(ModelName(name: "new", rectangle: true)
selectedItems.apped(ModelName(name: "newname", rectangle: false)
selectedItems.apped(ModelName(name: "namename", rectangle: false)
etc
then for cellforrow at do this
let item = selectedItems[indexPath.item]
cell.textlabel.text = item.name
if item.rectangle == true{
cell.rectButton.setImage(UIImage(named: "rectangle", for: .normal)
}else{
cell.rectButton.setImage(nil, for: .normal)}
return cell
I have tried with just name and rectangle you can do whatever you want if you don't want to initialse with any value make that variable nil
I am trying to change some attributes of the custom view cell in my collection view outside of the cell, but I can not figure it out what I am doing wrong:
In cellForItem I have :
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "PatientProfileCell", for: indexPath) as! PatientQuestionCell
if Auth.auth().currentUser?.uid == userID {
cell.commentButton.setTitle("Edit post", for: .normal)
cell.commentButton.addTarget(self, action: #selector(editPostAction), for: .touchUpInside)
}
} else {
print("Not the current user for collection view")
}
}
Everything works perfectly here but when I do trigger the action nothing happens. This is the function :
//post actions
func editPostAction() {
print("Edit post Enabled")
let cell = PatientQuestionCell()
cell.questionView.isEditable = true
cell.questionView.isSelectable = true
cell.questionView.isScrollEnabled = true
cell.questionView.becomeFirstResponder()
}
How can I change the attributes of the cell with this function?
You can make use of the tag property of UIButton like this:
Inside your collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) method, add this line of code:
cell.commentButton.tag = (indexPath.section * 100) + indexPath.item
Then set the target of your button like this:
cell.commentButton.addTarget(self, action: #selector(editPostAction(sender:)), for: .touchUpInside)
Now, add a new method, which is your selector:
func editPostAction(sender: UIButton) {
let section = sender.tag / 100
let item = sender.tag % 100
let indexPath = IndexPath(item: item, section: section)
let cell = self.collectionView?.cellForItem(at: indexPath) as! PatientQuestionCell
cell.questionView.isEditable = true
cell.questionView.isSelectable = true
cell.questionView.isScrollEnabled = true
cell.questionView.becomeFirstResponder()
}
I have a UICollectionView which uses custom xib file for it's cells. In the cell I have an ImageView for check box. I want to change the image of the `ImageView1 when it was taped. I tried the following code snippet but, it's not working for me
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: reuseIdentifier, for: indexPath) as! V_Cell
if show_delete == true {
cell.img_delete.image = UIImage(named: "checked")
}
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: reuseIdentifier, for: indexPath) as! V_Cell
// Configure the cell
let data = valves_[indexPath.row]
cell.v_name.text = data
if show_delete == true {
cell.img_delete.isHidden = false
} else if show_delete == false {
cell.img_delete.isHidden = true
}
return cell
}
In this code I've tried to change the image of ImageView in didSelectItemAt.
My custom xib file is as following.
Please suggest a way to make it work. Thanks.
For these kind of problems, it is always better to keep an array which contains whether an item at a given indexpath is checked or not.
var checkArray: [Bool] = [Bool](repeating: false, count: numberOfRowsInCollectionView)
// this should be the same size as number of items in collection view
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: reuseIdentifier, for: indexPath) as! V_Cell
checkArray[indexPath.row] = !checkArray[indexPath.row] // if it's true, make it false and vice versa logic
collectionView.reloadItems(at: [indexPath])
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: reuseIdentifier, for: indexPath) as! V_Cell
// Configure the cell
let data = valves_[indexPath.row]
cell.v_name.text = data
if show_delete == true {
cell.img_delete.isHidden = false
} else if show_delete == false {
cell.img_delete.isHidden = true
}
if checkArray[indexPath.row] {
cell.img_delete.image = //image for check
}else {
cell.img_delete.image = //image for no check
}
return cell
}
Finally I solved it by the following code.
var checkArray = [Int]()
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
if show_delete == true {
if checkArray.contains(indexPath.row) {
let index = checkArray.index(of: indexPath.row)
checkArray.remove(at: index!)
collectionView.reloadItems(at: [indexPath])
} else {
checkArray.append(indexPath.row)
collectionView.reloadItems(at: [indexPath])
}
}
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: reuseIdentifier, for: indexPath) as! V_Cell
// Configure the cell
let data = valves_[indexPath.row]
cell.v_name.text = data
if show_delete == true {
cell.img_delete.isHidden = false
} else if show_delete == false {
cell.img_delete.isHidden = true
}
if checkArray.contains(indexPath.row) {
cell.img_delete.image = UIImage(named: "checked_n")
} else {
cell.img_delete.image = UIImage(named: "unchecked")
}
return cell
}
I put taped element indexes in an array and reloaded the items at indexpath. if the array contains the reloaded index then it displays the check mark, if not it removes the check mark.
I want to delete cell from UICollectionview,when user touchUpInside(Button) to remove cell.
Here is my code:
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: reuseIdentifier, for: indexPath as IndexPath) as! CollectionViewCell
cell.myLabel.text = self.items[indexPath.row]
cell.deleteBtn?.layer.setValue(indexPath.row, forKey: "Cdelete")
cell.deleteBtn?.addTarget(self, action: Selector(("deleteColor:")), for: UIControlEvents.touchUpInside)
cell.backgroundColor = UIColor.cyan // make cell more visible in our example project
return cell
}
func deleteColor(sender:UIButton) {
let i : Int = (sender.layer.value(forKey: "Cdelete")) as! Int
self.items.remove(at: i)
collectionView.reloadData()
}
Where i am doing wrong?
set tag for your deletebutton for fetch the current cell/ know the which cell you tapped
cell.deleteBtn?.tag = indexPath.row
cell.deleteBtn?.addTarget(self, action: #selector(yourVCName. deleteColor(_:)), for: .touchUpInside)
and call like
#IBAction func deleteColor(_ sender: UIButton){
print("Button pressed 👍 ")
// continue your work
var hitPoint = sender.convert(CGPoint.zero, to: yourCollectionViewName)
var hitIndex: IndexPath? = yourCollectionViewName.indexPathForRow(at: hitPoint)
self.items.remove(at: hitIndex.row)
self.yourCollectionViewName.performBatchUpdates({
self.yourCollectionViewName.deleteItems(at: [hitIndex])
}) { (finished) in
self.yourCollectionViewName.reloadItems(at: self.yourCollectionViewName.indexPathsForVisibleItems)
}
}