I'm having a problem with my tableview, I can tap on my cells just fine. But if I quickly tap the same cell twice. It runs the "didSelectRowAtIndexPath" twice. Adding 2 of the same views, to my navigation Controller Stack
Here's the function:
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
var VC = detaiLSuggestion_VC()
self.navigationController?.pushViewController(VC, animated: true)
var selectedCell:UITableViewCell = tableView.cellForRowAtIndexPath(indexPath)!
if selectedCell.backgroundColor == UIColor.formulaFormColor() {
println("Buy Action")
selectedCell.backgroundColor = UIColor.formulaMediumBlue()
UIView.animateWithDuration(0.5, animations: {
selectedCell.backgroundColor = UIColor.formulaFormColor()
})
} else {
println("Sell Action")
selectedCell.backgroundColor = UIColor.formulaGreenColor()
UIView.animateWithDuration(0.5, animations: {
selectedCell.backgroundColor = UIColor.formulaLightGreenColor()
})
}
why am I able to select the same cell twice? and how would I go about fixing that?
why am I able to select the same cell twice?
Because the cell is still on screen to be tapped. You might want to do something other than navigation with cell taps and then you would not want to block future taps. Also multiselect would be much more complicated if this was not the case.
and how would I go about fixing that?
A simple boolean flag to indicate that something has been tapped would work or else you might want to set the allowsSelection property of the CollectionView to NO while you are presenting another view controller
Related
After we tap on the table view cells to push and pop to the detail view, if we swipe back to the previous table view, you'll notice that the cell stays highlighted and interactively unhighlights as we swipe.
How can this be programmatically implemented in UIKit?
The following reference illustrates the behaviour:
WWDC20 Introduction to SwiftUI: https://developer.apple.com/videos/play/wwdc2020-10119/?time=630
First, if you haven't already, you need to mark your "selected" when you tap on it:
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
guard let cell = tableView.cellForRow(at: indexPath) as? SubclassedCell else {
return
}
//`setSelected(:animated:) is built into `UITableViewCell`
cell.setSelected(true, animated: true)
...
Then in viewWillAppear(_:) you're going to coordinate the deselection animation with the edge swipe animation:
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
//1
guard let selectedIndexPath = tableView.indexPathForSelectedRow else {
return
}
//2
if let transitionCoordinator = self.transitionCoordinator {
transitionCoordinator.animate(alongsideTransition: { (context) in
self.tableView.deselectRow(at: selectedIndexPath, animated: true)
}, completion: nil)
//3
transitionCoordinator.notifyWhenInteractionChanges { (context) in
if context.isCancelled {
self.tableView.selectRow(at: selectedIndexPath, animated: true, scrollPosition: .none)
}
}
} else {
//4
tableView.deselectRow(at: selectedIndexPath, animated: animated)
}
}
That's a LOT of code, here are the highlights:
Only run this if there's a selected index path. There's no selection if you’re on this screen for the first time. (Btw, the table view keeps track of its own selected index path(s). You just need to mark cells selected or not selected).
Coordinate the row deselection animation with the current animation "context" (i.e. the edge swipe animation context).
You might change your mind mid-swipe! If this happens, you want to re-select the thing you were deselecting.
Back in the day, before transition coordinators, you only had to add this one line. This else case is there in case there's no transition coordinator (old version of iOS, going back in the stack without animation, etc).
Ok..before you give up on UIKit, know there's a shortcut.
Shortcut: Use UITableViewController instead of UIViewController
Instead of subclassing UIViewController and adding a table view, just subclass UITableViewController. You still have to mark your cell selected, but that's it.
This works because UITableViewController has a property called clearsSelectionOnViewWillAppear, which is set to true by default. It takes care of everything for you.
I use SwipeCellKit for do swipe actions for my tableview.
I try to do the left swipe for check or unckech for accessoryType of my cell and everything work fine, but after i press check the tableview reload the data immediatelly and i can't see the animation of roollback the check button. So i want to ask how i can call reload data after this animation end.
I have something like this:
I have something like this:
But i want fade animation like this
I want this animation
My code:
override func tableView(_ tableView: UITableView, editActionsForRowAt indexPath: IndexPath, for orientation: SwipeActionsOrientation) -> [SwipeAction]? {
var action = super.tableView(tableView, editActionsForRowAt: indexPath, for: orientation) ?? []
guard orientation == .left else { return action }
let checkAction = SwipeAction(style: .destructive, title: nil) { action, indexPath in
self.completeItem(at: indexPath)
}
action.append(checkAction)
return action
}
private func completeItem(at indexPath: IndexPath){
if let item = itemArray?[indexPath.row]{
do{
try realm.write {
item.done = !item.done
}
}
catch{
print( error.localizedDescription)
}
}
tableView.reloadData()
}
In order to hide the action on select, you need to set the hidesWhenSelected property for the action.
checkAction.hidesWhenSelected = true
Also, the example doesn't reload the tableView. Instead, they use an animation to remove the dot. You will need to manually delay your reload until the hide animation is complete.
See line 156 for the property
See lines 256 - 273 for the animation
https://github.com/SwipeCellKit/SwipeCellKit/blob/develop/Example/MailExample/MailTableViewController.swift
I'm currently developing my first iOS app for a college. When you start the app, there is a grouped table view which should represent a menu. This works fine so far, but I'm unable to connect the segues properly. As far as I know I should connect the cell itself with the navigation controller it should lead to. Although every cell should lead to another navigation controller. It's a menu, so that point should be clear. Unfortunately I'm unable to connect a single cell with multiple navigation controllers and when I add multiple prototype cells, I have the problem that every cell should have it's own identifier.
The first screen you see in my app looks basically like the mail app. There are two groups and each cell leads to another navigation controller.
I managed to implement the navigation in some weird way, but get a lot of bugs like "nested push results in corrupted nav bar".
I'm absolutely frustrated right now, I spent a lot of hours on this single problem already and I'm unable to find any solution.
edit:
one of the biggest problems currently is that if I navigate to a point and then head back the the view before, the grouped view is first displayed too close to the top and when the animation is complete the whole view jumps back down where it belongs.
this is how it should look like (and looks like when it jumps back): https://dl.dropboxusercontent.com/u/34140308/uploads/2016-04-25%2010.28.48.png
this is how it looks like during the animation: https://dl.dropboxusercontent.com/u/34140308/uploads/2016-04-25%2010.28.48%202.png
edit2: I connected the view controller itself (not the cells) with the respective view controller. Then I call the segues programmatically like this:
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
tableView.deselectRowAtIndexPath(indexPath, animated: true)
if indexPath.section == 0 {
if indexPath.row == 0 {
self.performSegueWithIdentifier("showSpeiseplan", sender: self)
} else if indexPath.row == 1 {
self.performSegueWithIdentifier("showStudiersaal", sender: self)
} else if indexPath.row == 2 {
self.performSegueWithIdentifier("showErzieher", sender: self)
} else if indexPath.row == 3 {
self.performSegueWithIdentifier("showHausordnung", sender: self)
} else if indexPath.row == 4 {
self.performSegueWithIdentifier("showNews", sender: self)
}
} else if indexPath.section == 1 {
if indexPath.row == 0 {
self.performSegueWithIdentifier("showZugewieseneStunden", sender: self)
}
}
}
The other major problem right now is that if you press a single cell multiple times before it's loaded, the view gets opened multiple times as well.
The way I usually do segue's from a tableView is by connecting the segue from the viewController rather than the tableviewCells. This way you can call performSegueWithIdentifier in didSelectRowAtIndexPath.
Eg
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
tableView.deselectRowAtIndexPath(indexPath, animated: true)
tableView.userInteractionEnabled = false
switch indexPath.section {
case 0:
switch indexPath.row {
case 0: performSegueWithIdentifier("showSpeiseplan", sender: self)
case 1: performSegueWithIdentifier("showStudiersaal", sender self)
case 2: performSegueWithIdentifier("showErzieher", sender self)
case 3: performSegueWithIdentifier("showHausordnung", sender self)
case 4: performSegueWithIdentifier("showNews", sender self)
default: tableView.userInteractionEnabled = true
}
case 1:
switch indexPath.row {
case 0: performSegueWithIdentifier("showZugewieseneStunden", sender: self)
default: tableView.userInteractionEnabled = true
}
default: tableView.userInteractionEnabled = true
}
}
and in viewWillDisappear:
override func viewDidDisappear(animated: Bool) {
tableView.userInteractionEnabled = true
}
If your cells are editable or dynamic (they change indexPath) then either use cell.tag in cellForRowAtIndexPath to distinguish them, or add a property to you custom cell class (or make one if you haven't) and add a property that you can use to identify the correct segue.
Edit: To fix the tableView Offset jump on animation, create a variable tableViewContentOffset above viewDidLoad, and then in viewDidLoad add:
tableViewContentOffset = tableView.contentOffset
and in viewWillAppear restore it if it has changed.
if tableView.contentOffset != tableViewContentOffset {
tableView.contentOffset = tableViewContentOffset
}
also, maybe just see what happens when you put this in viewWillAppear:
tableView.contentOffset = CGPointZero
tableView.contentInset = UIEdgeInsetsZero
I have a GADBannerView between my tableviewcells, my banner doesn't have the full width of UITableViewCell, when i clicked outside the banner in tableviewcell my application was crashed, because in the detail of tableviewcell don't have any data to receive. I tried to do a bool logic but it doesn't work:
if !isAd {
let news = newsTeam[indexPath.row]
print(indexPath.row)
viewController.news = news
self.navigationController?.pushViewController(viewController, animated: true)
}
i set the isAd = true when i will call my Ad.xib for table view cell.
with this code i disable all the cells, when the cell who has a banner is appearing.
In your tableView's delegate method you can do something like this:
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
let cell = tableView.cellForRowAtIndexPath(indexPath)
if let _ = cell as? {YOUR_AD_CELL_CLASS}{
return
}
}
That way, whenever the cell is of type {YOUR_AD_CELL_CLASS} you stop further execution (put that code at the very top for an early exit).
This question has been answered many times. But the answers I could find on it, didn't work for me, cause I can't seem to call the cell's class.
to further explain:
I have a viewController, with a UITable. The cells are configured in a UITableViewCell class. (it's from this class I need to pull the information)
my "cell class" is called mySuggestionsCel
Here's my code for "didSelectRowAtIndexPath"
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
tableView.allowsSelection = false
var selectedCell:UITableViewCell = tableView.cellForRowAtIndexPath(indexPath)!
var VC = detaiLSuggestion_VC()
self.navigationController?.pushViewController(VC, animated: true)
if selectedCell.backgroundColor == UIColor.formulaFormColor() {
selectedCell.backgroundColor = UIColor.formulaMediumBlue()
UIView.animateWithDuration(0.5, animations: {
selectedCell.backgroundColor = UIColor.formulaFormColor()
})
} else {
selectedCell.backgroundColor = UIColor.formulaGreenColor()
UIView.animateWithDuration(0.5, animations: {
selectedCell.backgroundColor = UIColor.formulaLightGreenColor()
})
}
}
I tried doing
mySuggestionsCell.someVariable
I also tried selectedCell.someVariable
neither worked.
I need to get this information from my detailSuggestion_VC(), from my cell Class. But the data it needs to pull, is the data the specific cell that's getting selected has. Which is why I'm having some trouble getting this to work.
I looked around for a while. But couldn't find any questions or answers to this specific issue.
Any help would be greatly appreciated
I'm making the following assumptions:
You have a tableViewCell class file that controls your table cells.
You have a detail-view controller that your table segues to when you tap a cell.
What you want to do is to pass the tapped cell's information so your new view controller has all the cell's info.
Instead of this:
var selectedCell: UITableViewCell = tableView.cellForRowAtIndexPath(indexPath)!
You will need to instead do a typecast into your tableViewCell class. Like so:
var selectedCell = tableView.cellForRowAtIndexPath(indexPath)! as tableViewCell
What you need to do next is to call the following function:
performSegueWithIdentifier(/*Segue Identifier goes here*/, sender: selectedCell)
Making this call will pass selectedCell's contents into sender, which can be used in prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject)
make sure you override prepareForSegue somewhere in your class.
Now, in prepareForSegue:, you can get a reference to the destinationViewController, and initialize the instance variable in the destinationViewController that will hold your selectedCell's variables.
//in prepareForSegue
let controller = segue.destinationViewController as detailSuggestion_VC
controller.cellInfo = sender