CollectionView Custom Cell accessing atributes outside of the cell - ios

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()
}

Related

Check if text field in collectionView is empty

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.")
}
}

Displaying checkmark on collectionview

I have a collection view where when each cell is tapped a larger version of the cell image pops up and disappears when tapped again. On top of this I'd like to be able to select a view in the corner of the cell that displays a blue checkmark(SSCheckMark View) or a greyed out checkmark when tapped again. My current code is:
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "photoCell", for: indexPath) as! PhotoCell
cell.backgroundColor = .clear
cell.imageView.image = UIImage(contentsOfFile: imagesURLArray[indexPath.row].path)
cell.checkmarkView.checkMarkStyle = .GrayedOut
cell.checkmarkView.tag = indexPath.row
cell.checkmarkView.checked = false
let tap = UITapGestureRecognizer(target: self, action: #selector(checkmarkWasTapped(_ :)))
cell.checkmarkView.addGestureRecognizer(tap)
return cell
}
func checkmarkWasTapped(_ sender: SSCheckMark) {
let indexPath = IndexPath(row: sender.tag, section: 1)
if sender.checked == true {
sender.checked = false
} else {
sender.checked = true
}
collectionView.reloadItems(at: [indexPath])
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
addZoomedImage(indexPath.row)
addGestureToImage()
addBackGroundView()
view.addSubview(selectedImage)
}
But when I run and select the checkmark view I get the error:
unrecognized selector sent to instance on the first line of checkmarkWasTapped() i can see that it doesn't like sender but i don't know why. Any help would be great.
UITapGestureRecognizer tap's sender is the gesture. The checkmarkWasTapped method definition is wrong. And you can get the checkmarView using sender.view. Try this.
func checkmarkWasTapped(_ sender: UIGestureRecognizer) {
let checkmarkView= sender.view as? SSCheckMark
let indexPath = IndexPath(row: checkmarkView.tag, section: 1)
if checkmarkView.checked == true {
checkmarkView.checked = false
} else {
checkmarkView.checked = true
}
collectionView.reloadItems(at: [indexPath])
}

Change ImageView image on UICollectionViewCell on Tap

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.

How to delete a Cell from Collection View?

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)
}
}

How to access the index of the selected cell in UICollectionView

I have a few cells in my UICollectionView in which I create buttons:
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCellWithReuseIdentifier("cell", forIndexPath: indexPath)
let button = UIButton(frame: CGRectMake(0, 0, cell.bounds.size.width, cell.bounds.size.height))
button.setTitle("ButtonTitle")
button.addTarget(self, action: "buttonAction:", forControlEvents: UIControlEvents.TouchUpInside)
return cell
}
Then I add a action to the button which switches to a new ViewController setting the name of the button as title with:
func buttonAction(sender: AnyObject?) {
let vc = NewViewController()
vc.title = sender!.titleLabel!!.text
revealViewController().pushFrontViewController(vc, animated: true)
}
But I now also would like to access the index of the selected cell / button. Does anybody know how to do this?
do like
Step-1
button.tag = indexPath.row
button.setTitle("ButtonTitle")
button.addTarget(self, action: "buttonAction:", forControlEvents: UIControlEvents.TouchUpInside)
Step-2
func buttonAction(sender: UIButton) {
if let sendertitle = sender.titleLabel?.text {
let vc = self.storyboard?.instantiateViewControllerWithIdentifier("NewViewControllerIdentifier") as? NewViewController
vc.title = sendertitle
revealViewController().pushFrontViewController(vc, animated: true)
}
}
Choice -- 2
if you want to implemnt the simple way do like
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCellWithReuseIdentifier("cell", forIndexPath: indexPath)
return cell
}
on didSelect call
func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) {
let vc = self.storyboard?.instantiateViewControllerWithIdentifier("NewViewControllerIdentifier") as? NewViewController
vc.indexPath = indexPath.row
revealViewController().pushFrontViewController(vc, animated: true)
}
In your buttonAction:
let btn = sender as! UIButton
let point = btn.convertPoint(btn.bounds.origin, toView: self.tableView)
let indexPath = self.tableView.indexPathForRowAtPoint(point)
Just use this method :
let point = button.convertPoint(btn.bounds.origin, toView: self.collectionView)
let mypath = self.collectionView?.indexPathForItemAtPoint(point)
Use your button position to get the proper indexpath
If the entire cell is displaying a button maybe you should just remove the button and implement the following:
func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) {
// Perform any action you want after a cell is tapped
// Access the selected cell's index with the indexPath.item value
let item = itemCollection[indexPath.item]
}

Resources