I have a custom layout for uiCollectionView. Now if collectionView has 0 sections. And i push from collectionViewController to another controller and then pop. Now if section count is 0 collectionView will automatically invalidateLayout. How to stop this behaviour.
I have also override shouldInvalidateLayout but it never gets called.
Hey I have a UITableView. There are 4 large cells (so they are not all displayed on the screen). At various points through the app I want to disable user interaction for all of them however I am getting a nil unwrap error when I run this code:
for row in 0...3 {
let cell = tableView.cellForRowAtIndexPath(NSIndexPath(forRow: row, inSection: 2)) as! AnswerTextChoiceCell
cell.userInteractionEnabled = reEnable ? true : false
}
I'm guessing it's because it can't fetch the cell because it's not displayed on the screen. How Would I go about disabling all user interaction for all the cells?
I don't want to disable the user interaction on the tableView as it will prevent the user from scrolling.
Any pointers on this would be really appreciated!
Try once.
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
//Configure the cell
if indexPath.row == yourcell {
cell.userInteractionEnabled = false
}
return cell!
}
Hope this helps.
Without seeing the rest of your code and your TableView the only two things I can see that would cause that crash would be:
When you are casting the cell from 'cellForRowAtIndexPath' to your 'AnswerTextChoiceCell' type
You have the wrong section passed in to your 'cellForRowAtIndexPath' function
To try and see which of the two it is I would first try omitting the 'AnswerTextChoiceCell' cast completely and see if the problem goes away, or at least that it stops crashing. The function will return a UITableViewCell anyway and the userInteractionEnabled property is available on that object anyway so this will still allow you to test out what you're after.
If that doesn't work then we'll need a bit more information about your table view such as, how many sections do you have, is it storyboard based, etc.
I'm working on the accessibility of a calendar which is actually a collectionView. Whenever a cell is tapped, the collectionView will be reloaded by calling
[self.collectionView reloadData];
The problem is if the voiceOver is running, the focus will move to another place after the cell tapped because that cell is reused on somewhere else.
Is there anyway to keep the focus where it was after the reloadData? Thanks!
Just find a workaround for this. The focus is changed because the focused cell is reused somewhere else when doing [colleciontView reloadData].
So if we reload the collectionViewCells one by one, that focused cell will not be used anywhere else. I call this method to reload the collectionView when VoiceOver is running.
- (void)reloadCalendarCollectionView {
NSInteger items = [self.calendarItems count];
for (NSInteger i = 0; i < items; i++) {
[self.collectionView reloadItemsAtIndexPaths:#[[NSIndexPath indexPathForItem:i inSection:1] ]];
}
}
You could try doing self.collectionView.accessibilityElementsHidden = YES before reloading data. Then, when it completes, you will have to do the inverse & then post a notification for the cell you're looking for.
We have a collection view and this collection view reloading data in every second. When user taps cell, focus changing after every reload, so collectionview cell selects wrong cell at indexPath.
Create a protocol for delegation in cell:
protocol AccessibilityCellProtocol{
func accessibilityFocused(cell:UICollectionViewCell)
}
Override accessibilityElementDidBecomeFocused in your cell:
override class func accessibilityElementDidBecomeFocused(){
self.delegate.accessibilityFocused(cell:self)
}
In view controller create an selectedIndexPath variable. Assign it in delegation method.
func accesibilityFocused(cell:UITableViewCell){
selectedIndex = collectionView.indexPath(for: cell)
}
And in your didSelectItemAtIndexPath method:
if UIAccessibility.isVoiceOverRunning{
cellTappedWith(indexPath:selectedIndex)
return
}
cellTappedWithIndexPath(indexPath:indexPath)
I've a tableView with custom cells.
Each cell has different interface, elements. All they have different sizes.
Each cell has different type of elements and their count.
All these elements are created dynamically, so I'm creating them, making their frames and adding as subviews.
So the problem that heightForRowAtIndexPath executes before cellForRowAtIndexPath where I'm creating the row and constructing its interface and I don't know how to pass calculated height to heightForRowAtIndexPath
How can I count row height before and pass its value to heightForRowIndexPath for correct drawing of my tableView?
If your cell view is really very complex and every component's height are depending on data source. You can try to create the view in heightForRowIndexPath method and then cache the created view to a dictionary in your view controller and use it directly in cellForRowAtIndexPath. In this way you only need to create the view once when user scrolling the table. If the datasource is not changing very frequently, you can reuse the cached view in heightForRowIndexPath as well.
And if the tableview has a lot of rows, you should return an approximate value for height in estimatedHeightForRowAtIndexPath to speed up the loading process of the view controller. Otherwise during loading tableview, it will try to calculate all row's height which may requires a lot of time.
But I really don't think your cell would be so complex. If only some UITextLabels that depends on datasource for the height, you can simply only calculate the height for the label, then add it to other components' height which is fixed.
You really should consider subclassing UITableViewCell and adding your custom logic inside your subclass.
Starting from there, you'll have such options:
Create static method in your cell that will receive all data necessary to draw your cell (e.g heithtForCellWithFirstString:secondString:accessoryImage etc) and calculate height using string size computation methods. Use this method inside heightForRowAtIndexPath.
Use autolayout for laying out subviews of your cell and then set table view's row height property to UITableViewAutomaticDimension. This way you won't need heightForRow delegate method at all. There are plenty of tutorials on this, for example: http://www.raywenderlich.com/87975/dynamic-table-view-cell-height-ios-8-swift
Try to create a subclass of UITableViewCell.
All elements created by you put inside UIView, which is put in a cell.
Create three NSLayoutConstraint, one from UIView.top to top of the cell, the second from UIView.bottom to the bottom of the cell and the third - the height of the UIView.
In the viewDidLoad method of tableViewController set row height as the UITableViewAutomaticDimension
:
override func viewDidLoad() {
super.viewDidLoad()
self.tableView.rowHeight = UITableViewAutomaticDimension
}
In a subclass of UITableViewCell create a method that will calculate the height of the cell and change NSLayoutConstraint, which sets the height of the cell. For example:
:
func adjustHeightOfInnerView() {
let height = 100
self.myInnerCellViewHeightConstraint.constant = height
self.contentView.setNeedsUpdateConstraints()
}
In the method cellForRowAtIndexPath call the adjustHeightOfTableview:
:
func tableView (tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("myCell", forIndexPath: indexPath) as! myTableViewCellSubclass
cell.adjustHeightOfTableview()
return cell
}
I'm having an issue with UITableView's didSelectRowAtIndexPath.
My table is setup so that when I select row it initializes a new view controller and pushes it.
The first time I tap any row in the table, the method does not get called. Once I select another row, it begins to work as normal.
I have verified this by setting a breakpoint on didSelectRowAtIndexPath. When adding an NSLog to the method I see that when I select the second row that finally pushes the new view controller, I see two log statements appear in the console at the same time.
Any suggestions?
Any chance you accidentally typed didDeselectRowAtIndexPath?
Also check the selection property of your table view in xib file. Use 'Single Selection' or 'Multiple Selection' as required.
I experienced the following issue:
first tap in row -> no effect, no selection, never
second tap and following -> correct selection behavior, always
In my case, my error was checking Show Selection on Touch in Interface Builder. You can uncheck it in IB here:
Hope that helps someone
Check If you have set any Gesture recognisers in your class. Removing gesture worked for me.
I debated even posting this answer because I think the stars kind of aligned in order for this to manifest itself.
I am having a variation of this problem and have checked the other solutions. On my table view it isn't processing the very last row of my table on the first tap. It highlights it, but didSelectRowAtIndexPath isn't being called. All the other rows work fine. But if I turn the tableview bounce on then it seems to solve the problem (but then you have to deal with a tableview bounce).
UITableViewCellSelectionStyleNone was set for the cell displaying that problem
(ios9).
I have ended up calling
[tableView deselectRowAtIndexPath:indexPath animated:NO];
first thing in
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
which is not the same, but is good enough.
makes me wonder what kind of table breakage ios10 brings.
this issue happens also when you are working with gesture recogniser within a tableView in this case you don't need to remove them, you need only to make sure that your gesture property cancelsTouchesInView = false this is a boolean value affecting whether touches are delivered to a view when a gesture is recognised.
SWIFT 2
Make sure you have this set to true:
self.tableView.allowsSelection = true
Put this above your right after your viewDidLoad() and before the super.viewDidLoad()
SWIFT 3
If you are working with Swift 3 in a class which isn't a UITableViewController and you are using UITableViewDelegate, then you may need to use the method title:
#objc(tableView:didSelectRowAtIndexPath:) func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath){...}
This worked for me, although I have just migrated my project to Swift 3. It's fairly new so this may be fixed later.
SWIFT 3
None of the other answers worked in my case, what fixed it for me was:
tableView.delaysContentTouches = false
If you have set any UITapGestureRecognizer in your class, you can add this line in your didSelectRowAtIndexPath:
[tableView deselectRowAtIndexPath:indexPath animated:NO];
This worked for me.
Swift 4.2
Disabling "Delay Touch Down" in the attributes inspector solved the issue.
After that the clicks are smooth and didSelectRowAt fires immediately.
didSelectRowAt function was not called in my app in first or second tap...
I was trying to solve the problem could not find any solution. But suddenly I was recognise, I was using view.animation color change... Delegate method was not called while animation persist
In my case I had a UITableView section header with a gesture recognizer. When the header is tapped, it should insert few rows into that section and animate the insertion (like expand/collapse section).
First time when expanded and tapped, the didSelectRow delegate method was not fired. For further taps and expand/collapse actions, it was working as expected.
Per answer by #Ayoub Nouri I set cancelsTouchesInView to false, and this resolved the issue.
tapGestureRecognizer?.cancelsTouchesInView = false
What worked for me was to start typing "didSelect..." and then let autocorrect fill in the rest. Apparently some detail of my syntax was wonky. As others have said, Use the IDE!!
I had the same issue on my tableView(swift 4.2), it could be fixed with allowsMultipleSelection property on tableView.
If allowsMultipleSelection is set to true the table view selection mechanism will change in a way that by selecting each cell the tableView didSelectRowAtIndexPath: is called for the first time and by selecting the same cell for the second time the tableView didDeselectRowAtIndexPath: is called.
It means that if the number of times a cell tapped are odd (1, 3, 5, ...) then always tableView didSelectRowAtIndexPath: will be called and if the number of times a cell tapped are even (2, 4, 6, ...) then always tableView didDeselectRowAtIndexPath: will be called.
This makes tableView didSelectRowAtIndexPath: function to be called on the third selection for the same cell and so the result is double tap for calling didSelectRowAtIndexPath:!!!
If you want the tableView didSelectRowAtIndexPath: to be called on each selection for a cell then the tableView multiple selection has to be set false, tableView.allowsMultipleSelection = false.
By doing this, every time the cell is tapped tableView didSelectRowAtIndexPath: will be called on table view and by selecting another cell tableView didDeselectRowAtIndexPath: will be called for the cell was selected before and then the tableView didSelectRowAtIndexPath: will be called for the newly selected cell.
class TableViewController: UITableViewController {
override func viewDidLoad() {
super.viewDidLoad()
tableView.allowsMultipleSelection = false
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
print("This will be called for each cell tap")
}