Swift: Disable touches on a UITableViewCell - ios

I have a UITableView on top of a MKMapView. I want to have similar functionality to how Apple's Maps app works. Where you can move a table up and down but still be able to move the map that is behind it. Right now I have a blank cell at index 0 that is clear and I want to be able to disable all touches that that cell receives and allows the map behind it to move, but when the cell in index 1 is touched that cell can scroll up and the rest of the table is now on top of the map.
If there is a better way to solve this problem I am up to try your solution!

func tableView(_ tableView: UITableView, didSelectRowAt
indexPath: IndexPath){
//UITableViewCell *cell = something
if indexPath.row == 0 {
cell.selectionStyle = .none
cell.isUserInteractionEnabled = false
}
}
What this code does is it makes sure that the cell is not highlighted when the user taps it. And then the second line in the if is to make sure that tableView:didSelectRowAtIndexPath: is not called which will be the case if the line is left out, and even though selectionStyle is none!

Related

Swift - How to expand UITableViewCell's height, while pushing adjacent cells away from the selected cell?

I am working on a ViewController with a TableView populated with dynamic cells from a prototype nib. I have run into a dead-end trying to recreate certain a cell-expanding animation.
My goal:
When a cell is selected, the selected cell should "expand" (grow in height to twice it's starting size) while at the same time creating space between the cell directly above and below the selected cell.
I've found an example of EXACTLY the asethetic I am looking for in the app "Things". Below are two screenshots showing the table before and and after a cell is selected:
Screenshot of table BEFORE expansion
Screenshot of table AFTER expansion
The best way I can describe the desired animation is the UITableView version of "the parting of the Red Sea". When a cell is selected, the surrounding cells give way lending the selected cell more room.. and the user's focus.
What I've tried:
I found Simon Lee's method answering a similar question and implemented it into my project. And although it animates the row-height change perfectly, it only pushes the adjacent cells on one side of the selected cell. (ie: if the cell at index 4 is selected, all the cells from index 5+ move down but those from index 0-3 stay static. Thereby not achieving the look I'm seeking.)
Using that method, the relevant sections of my code looked something like:
var cellHeight: CGFloat = 72
var selectedCell: IndexPath?
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
if indexPath == selectedCell {
return cellHeight * 2
} else {
return cellHeight
}
}
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
selectedCell = indexPath
tableView.beginUpdates()
tableView.endUpdates()
}
func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) {
selectedCell = nil
tableView.beginUpdates()
tableView.endUpdates()
}
Because that didn't result in my desired animation, I tried insertRows:at:with: to insert 2 empty cells (1 above and 1 below the selected row) -- then deleteRows:at:with: to remove them upon deselecting the cell. This ultimately made for a better looking animation, and looked closer to the "Things" example I'm shooting for. However this made the table overly complicated because by adding and removing cells each time a row is selected, it would change the index of the other cells making it frustrating to predict which cells would have what index at any given time.
A possible solution idea?
After working on this for a couple of days the only other way I could think to accomplish what I want is to somehow scroll the table slightly at the same time that the selected cell's height it changed.. so that as the cell expands (moving the following cells downward) it would make the previous cells appear to move upward. I'm hesitant to try this because it feels like a hack, there should be a better way to accomplish this.
ANY help would be thoroughly appreciated! I've been pulling my hair out at an alarming rate. Thank you to anyone who can share their knowledge.

UITableViewCell styling resetting when scrolled off and back onto view

I currently have a TableView in my project, which is set up to turn a cell green when it is pressed, and back to clear if it is pressed a second time. However, if I scroll down to the bottom of the table view, and scroll back up, all my cells have been reset to their default clear colour.
I'm not sure how to go about fixing this issue, as anything I can find referring to it is in Objective-C rather than Swift. Any help and advice as to how to go about this would be great, thanks.
Everytime a UITableViewCell goes out of the screen, any function that you've written in the tableViewController/ViewController runs again.
for example in cellForRowAtIndexPath if you have a cell.setUpCell() or something similar, it will rerun and reset your values to the original values.
if you have a
var name = testName in your MainVC
and you update something in your cell, you should change the name in your mainVc too.
Every time you scroll or call tableView.reloadData() UITableView cells will reload. So, every time you select UITableViewCell, add selected index (indexPath.row) to an array(ex: selectedIndexArray) in your didSelectRowAt indexPath: delegate. If the cell you selected is already selected one, then remove the cell from selectedIndexArray.
And in your cellForRowAt indexPath: manage the cells using selectedIndexArray.
var selectedIndexArray:[Int] = [] //to save selected tableViewCells
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let isSelected = false
for each in selectedIndexArray
{
if each == indexPath.row
{
isSelected = true
}
}
if isSelected == true
{
//set selected cell color
}
else
{
//set default cell color
}
}
You need to write the logic of adding and removing cell indexes in your didSelectRowAt indexPath:.

tableviewcell repeating uibuttons

I am having a little trouble with buttons on a tableview.
I have a tableViewCell that I customised with 3 buttons. I set the buttons to hidden in interface builder and when the table loads the buttons are hidden as expected.
I then set the hidden property of the tableview to false when didSelectRow is called and hidden.true when didDeselectRow is called. This works fine as well. The problem is the buttons that are set to visible in the didSelectRow are also visible every seven cells down. they keep repeating themselves.
Below is the code that shows the buttons
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
let cell = tableView.cellForRowAtIndexPath(indexPath) as! ContactsViewCell
print("Table selected")
cell.insertEmailButton.hidden = false
cell.insertPhoneButton.hidden = false
cell.insertAllButton.hidden = false
cell.contactTextLabel.alpha = 0.2
cell.contactDetailTextLabel.alpha = 0.2
}
And this hides them when the tableViewCell is deselected
func tableView(tableView: UITableView, didDeselectRowAtIndexPath indexPath: NSIndexPath) {
let cell = tableView.cellForRowAtIndexPath(indexPath) as! ContactsViewCell
cell.insertEmailButton.hidden = true
cell.insertPhoneButton.hidden = true
cell.insertAllButton.hidden = true
cell.contactTextLabel.alpha = 1.0
cell.contactDetailTextLabel.alpha = 1.0
}
I did some research and I learnt it might be the row with the buttons.hidden set to false are being reused by the tableview. But I understand from documentation that the cell being reused is from cellForRowAtIndexPath and not the cell at didSelectRow which is where I am setting the button.hidden to false.
I also tried using the cell.isSelected property in an if else statement in the cellForRowAtIndexPath to hide and show the buttons but this does not show the buttons at all.
Thanks in advance for your help
The tableview reuses the view of the cell when the table is scrolled, to save memory. So, for example, when you set the button to visible (inside didSelectRow) and then scroll down the table, the tableview will take the cells that go out of the visible screen at the top and will reuse them at the bottom, to save the overhead of creating new cells, improving performance.
That is why, your previous properties on the cells are repeating.
To get the desired hidden button on scrolled cells, I recommend setting button.hidden to true/false in
tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell
This will set the button to hidden whenever a new row is scrolled into the visible view area.
Hope this helps.
I solved the recurring buttons by hiding them when I check if the cell is deselected in cellForRowAtIndexPath. This also means any cell I select will lose its selected status and buttons will disappear when it leaves the view.
I can live with that.
if cell.selected == false{
cell.emailButton.hidden = true
cell.phoneButton.hidden = true
cell.allButton.hidden = true
}
UITableView reuses its cell to improve performance. So, you can not do the way you are trying. What we have to do is, like other tableview cell info e.g. title, description, thumb image etc we also need to save the state for buttons in the array. When you want to hide a button for the cell take object at index from the array and change the button state for the button and reload that table view cell. Still if you face problem or feel difficult to understand, please feel free to ask.

Image inside tableViewCell automatically zooms when touched, why?

I have no idea why, but when I touch a cell, image inside it kind of zooms and is partially of screen. Below you can see, the first row looks like it should and the second row was selected and now looks zoomed.
There is not much code, only ViewController and TableViewCell that both have minimum required code.
EDIT: Here's how I add cells, and there is no didSelectAtRow.
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("cell") as! TableViewCell
cell.myImage.image = UIImage(named: "uk.png")
return cell
}
EDIT2: Initially my imageView constrains where 0 to all margins, so that whole cell would be only image. When I made image quite small, none of zooming happens, so maybe I am doing something wrong with constrains?
Final Edit - Problem Solved
Not sure, how that zooming happened, but in my case trying different constrains solved the problem.
It is because your tableview is reuse its cell
First set the constraints of the cell.
and
also implement the
the code in cellForRowAtIndexPath with
if(cell == nil)
{
cell = [[UITableViewCell alloc] init];
}
also share your code for didSelectRowAtIndexPath

iOS UITableViewCell needs to be pressed twice to call didSelectRowAtIndexPath

I have a UITableView that sometimes requires you touch it twice to select a cell.
More specifics:
Two touches are needed only after the table has been scrolled all the way up or all the way down.
Only the second touch even calls didSelectRowAtIndexPath.
When the table opens in the natural "scrolled up position", cells are indeed selectable with just one touch.
If you scroll just a little bit (not all the way down/up), the cells will select with just one touch.
If cells do not fill the whole table and scrolling is not required, it works fine.
Go all the way to the top or bottom and you have to touch twice.
I have a feeling that the first touch is really making the UITableViewCells selectable or is activating the table in some way.
Things I have checked:
My code definitely doesn't call didDeselectRowAtIndexPath anywhere.
No UIGestureRecognizers are using setCancelsTouchesInView:.
Other settings on the table:
self.tableView.scrollEnabled = YES;
self.tableView.showsVerticalScrollIndicator = NO;
self.tableView.bounces = NO;
self.tableView.separatorStyle = UITableViewCellSeparatorStyleSingleLine;
What's causing this?
Update
Oddly enough, setting self.tableView.bounces = YES; fixed the problem.
I am still looking into the root cause in case anyone has a better answer. Obviously I would like for the table not to bounce, but not if it costs key functionality.
May be you implemented didDeselect instead of didSelect?
Swift:
Once a cell gets tapped, it also gets selected, try deselecting it as soon as it was tapped.
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
tableView.deselectRowAtIndexPath(indexPath, animated: false)
}
Other things to check also are delaysContentTouches and canCancelContentTouches properties.
Swift 4
You need to surround your updates with beginUpdates() and endUpdates()
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
// get current cell
let cell = tableView.cellForRowAtIndexPath(indexPath) as! YourCustomCell
// change the value
// Update the tableView
tableView.beginUpdates()
tableView.reloadRowsAtIndexPaths([indexPath], withRowAnimation: .Automatic)
tableView.endUpdates()
}
Maybe you should try to disable delaysContentTouches:
tableView.delaysContentTouches = NO;

Resources