Swift - Button action not triggered in table view cell - swift

I have a ViewController who contains a TableView. I want in each cell, a red button who did something (let's say 'hello' for test), or when I touch the cell anywhere but not on the button I perform a segue.
But even when I touch the button, it's the segue who perform. I tried some search on SF but none of the questions help me...
I don't know if that's usual but when I touch the cell, all the row white background become gray, even the background of the red button.
In storyboard I have this cell hierarchy :
The user interaction is enabled on both cell and button.
In the questions I found they said, on the cell set 'accessory' on 'disclosure indicator', I did it, but if it's possible I would like to keep it at 'None'.
Also I set a custom class for the cell, here is the code :
class MyTableViewCell: UITableViewCell {
#IBOutlet weak var rentButton: UIButton? // I use this class for 2 tableview almost similar, but in the other I don't have the redButton, that's why I put an '?'
}
I also set the delegate and datasource of the tableView to my ViewController, here is the code of my view controller :
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath) as! MyTableViewCell
cell.rentButton!.tag = indexPath.row
cell.rentButton!.addTarget(self, action: #selector(MyViewController.rent(_:)), forControlEvents: .TouchUpInside)
return cell
}
// Rent() is never called:
func rent(sender: UIButton) {
print("here \(sender.tag)")
}
EDIT : The solution was to put out the button from the conainer view !

You can stop the segue from actioning when the button is pressed by performing it programatically. You can do the following:
Remove your segue that goes from the cell to another view controller and change it go from the TableViewController to the other view controller
Create a variable in your TableViewController class such as: var buttonPressed = false
In your button action set buttonPressed to true
In didSelectRow, check that buttonPressed is not true then performSegue and change buttonPressed to false, else do nothing
As discussed, move the button from the container to the content view

Related

UIButton is changing other UIButton's in collectionView cell, how do I prevent this?

I've created a custom collectionView cell class that contains a UIButton. So each cell contains it's own button that a user can press. However whenever one cell button is tapped it causes background color changes to buttons in other cells. I want it to where only the selected button's background color is changed instead and to prevent the change to other buttons. Below is my code:
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cellID", for: indexPath) as! SubjectsCell
cell.subjectButton.setTitle(subjectNames[indexPath.row], for: .normal)
cell.subjectButton.addTarget(self, action: #selector(updateBackgroundColor(_:)), for: .touchUpInside)
if cell.subjectButton.isChosen == selectedState{
cell.subjectButton.backgroundColor = .green }
else if cell.subjectButton.isChosen != selectedState {
cell.subjectButton.backgroundColor = UIColor(red: 34.0/255.0, green: 210.0/255.0, blue: 255.0/255.0, alpha: 1)
}
return cell
I realize that dequeueReusableCell causes some cells to be reused, if this is my problem how I prevent cell changes happening to random cell's and only affect the cell that the tapped button is in.
You're right that dequeueReusableCell(withReuseIdentifier:for:) is the source of the issue here! You just need to have your cell class override UICollectionReusableView's prepareForReuse() method and reset the background to whatever it needs to be.
You may need to change your data model so you have a way of remembering which cells have had the button pressed since the cells can't hold on to that data without causing problems.
Also note that calling addTarget inside that collectionView(_:cellForItemAt:) may cause problems later, targets are typically only added once when the object is set up initially. To avoid issues you should set that up either in the nib / storyboard as an action, or when you setup the view objects if you're doing programmatic view setup.
Here's Apple's documentation on prepareForReuse().
You can do something like this:
class SubjectsCell : UICollectionViewCell
{
#IBAction func buttonAction(_ sender: UIButton) {
updateBackgroundColor()
}
}
so the cell view background update should present in SubjectsCell because its a view update not in job of viewController.

Remove a uiview once a table view cell is tapped (swift)

I have a custom xib table view cell that has a green uiview on it. The uiview acts as a new message indicator - whenever a message comes in, the green view is displayed. When a user taps the cell, I want to set the view to hidden. My only question is; how would I go about hiding the view just on that specific table view cell and not all table view cells?
Suppose your model
class Item {
var greenHidden = false
/// more properties
}
Then create the green view inside the xib and according to the current state do inside cellForRowAt
let cell = //
let item = arr[indexPath.row]
cell.greenView.isHidden = item.greenHidden
When the cell is tapped inside didSelectRowAt do
arr[indexPath.row].greenHidden = true
self.tableView.reloadRows(at:[indexPath],with:.none)

Returning to the same scroll position of UICollectionView after tapping a cell

I have a UICollectionView that is populated with all photos from the devices photo library. After a cell (photo) is tapped, it segues to a view controller that allows for editing. On this view, there is an "Add Photo" button to return the user back to the UICollectionView (to select another photo). I need for the scroll position to "focus" the previous tapped cell in the center of the view without any animations or jumping.
I have tried saving the tapped indexPath as a variable, then on viewDidAppear, scroll to that indexPath with scrollToItemAtIndexPath. The problem is I can't figure out how to update a variable (to save indexPath) on cell tap. I tried this in didSelectItemAtIndexPath, but the value never actually saves.
var cellTappedIndexPath = Int()
Inside didSelectItemAtIndexPath:
cellTappedIndexPath = indexPath.row
The value for cellTappedIndexPath never saves.
Just for testing out scrollToItemAtIndexPath, I have added the following to viewDidAppear:
customViewCollectionView.scrollToItemAtIndexPath(NSIndexPath(forItem: 25, inSection: 0), atScrollPosition: UICollectionViewScrollPosition.CenteredVertically, animated: false)
// 25 is just a number I have set for testing. Ultimately, I would like this to be the saved indexPath of the last tapped cell.
This causes the collectionView to "jump" to cell 25 once it's fully loaded. If I set animated to true, it loads at the top, then scrolls down to cell 25. Not my desired result.
I just want to be able to do 2 things here.
1 - Save the cell tapped as a variable.
2 - use scrollToItemAtIndexPath (with the variable in #1) so the view just loads up instantly with the last cell tapped right into the middle, No animations or anything.
Let me know if further clarification is needed. THANKS!
You could save the selected indexPathreceived when the collectionview cell is tapped and use it when required.
var selectedIndexPath: NSIndexPath?
func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) {
selectedIndexPath = indexPath
}
func scrollToCell(){
if let index = selectedIndexPath{
customViewCollectionView.scrollToItemAtIndexPath(index, atScrollPosition: .CenteredVertically, animated: false)
}else{
print("A cell hasnt been selected yet")
}
}

YPDrawSignatureView - Table scrolling when drawing signature

So I want a signature view within a table cell. Obviously whenever somebody tries to draw in the cell, the table scrolls.
How would I stop the scrolling but ONLY when the user is writing in the signature box?
I found better solution for this issue rather than putting button. Implement the delegate methods in viewController,
class mainVC: UIViewController,YPSignatureDelegate {
Than set delegate of signature view to this view controller
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "SignatureCell", for: indexPath) as! SignatureCell
cell.signatureView.delegate = self
return cell
}
And then add these code. This are two delegates of YPSignature. Add in Main view controller
func didStart() {
tableView.isScrollEnabled = false
}
// didFinish() is called rigth after the last touch of a gesture is registered in the view.
// Can be used to enabe scrolling in a scroll view if it has previous been disabled.
func didFinish() {
tableView.isScrollEnabled = true
}
I would solve this with a button covering the cell, and when the user taps it, the cell displays the YPDrawSignatureView. Just before the signature view is shown, disable the scrolling:
tableView.scrollEnabled = false
Later when you save the signature, enable scrolling again by setting scrollEnabled to true.
I added a uitableview and custom cells. In one of the custom cells contain a button(ex. addSignatureButton) on the top of signatureView.
I used delegate method to communicate between uitableviewcell and uiviewcontroller. A delegate is added to UITableViewCell to notify whether the addSignatureButton is tapped. Once it is tapped, addSignatureButton is hidden, signatureView is visible and the tableview's scroll is disabled. When user finishes adding signature, signatureView is hidden, addSignatureButton is visible and tableview scroll is enabled.
https://github.com/alvinvgeorge/DrawSignatureOnTableViewCell

How to determine which cell is being viewed or clicked in a collection view

I want to be able to edit records that are displayed in a collection view.
I've added an "Edit" button to the collection view. What is the best way to determine which cell is to be edited?
I thought of doing something like so:
func scrollViewDidEndDecelerating(scrollView: UIScrollView) {
visibleCell = collectionView.visibleCells().first as MessageCell
}
I didn't want to add the edit button to the xib itself as I don't want the button to scroll when the cell scrolls
One possibility is to have a variable in your ViewController called something like isEditing. This will be set to true when the edit button is clicked.
Then, set your collection view's delegate to self.
Implement this method: func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath), A UICollectionViewDelegate method.
In the method, write something like:
if isEditing{
// What happens when selected and editing
} else{
// What happens when selected and not editing
}