I’m using VoiceOver, and having an issue with a UICollectionView. I have an initial screen with ten buttons, each of which links through to one of ten cells in the collection view. The collection view is actually the full size of the screen, and each cell contains a child view controller. This all works fine with VoiceOver switched off, but when it’s switched on, activating one of the buttons in the middle of the set always causes the collection view to pop to its first cell, even if I didn’t tap the first button. I think this is because the VoiceOver “focus” goes to the first element it sees (i.e. the first cell).
I’ve tried using the UIAccessibilityScreenChangedNotification and the same with Layout with an argument of the cell in question, but it’s making no difference, it’s not popping to my required element, and is always popping to the first cell in the collection.
What could I be doing wrong here?
I’m adding a snippet, this is called in viewDidLayoutSubviews, and works fine for the actual scrolling if VoiceOver is turned off. But as soon as VO is on, it breaks.
if (self.initialIndexPath) {
[self.collectionView scrollToItemAtIndexPath:self.initialIndexPath atScrollPosition:UICollectionViewScrollPositionNone animated:NO];
UIAccessibilityPostNotification(UIAccessibilityScreenChangedNotification, [self.collectionView cellForItemAtIndexPath:self.initialIndexPath]);
}
This works absolutely fine for actually focusing on the cell, but the VoiceOver portion is completely ignored, the notification does not shift the focus to that correct cell at all, it's always the first element in the first cell.
Also to note, the cells themselves are NOT accessibilityElements and should not be, they implement the UIAccessibilityContainer protocol, and so the title label of each cell would be where I'd like the focus to end up.
This was a bug in iOS and is fixed now.
I started to see this bug in iOS8. And reported a bug to Apple about this 6. Nov 2014.
Was fixed in iOS 9.3.2.
There is nothing you can do as developer if you are on affected OS version. Recommend users of your app to update the OS.
Related
So here's the description of the loop my app keeps falling on:
There is a UITableView containing ReactiveTableViewCell's (but I think RX part doesn't really matter here, so let's pretend these are UITableViewCell). Each cell embeds a UITextField upon an expandable/collapsable UIView (that allows me to show any error message related to the textfield) - when there is no error to show, this subview is collapsed.
The thing is, when UITableView gets scrolled and makes reuse of an "errored" cell, the subview of this cell is still expanded. As PrepareForReuse() method is made to reset cell state before a reuse, I thought it would be the right place to collapse the subview, and indeed it does... until the app falls into a loop, resizing top-screen and bottom-screen same cell forever.
How do you think I could fix this issue? Maybe is there a way to increase cell reuse tolerance so UITableView won't reuse a cell as soon as it disappeared from screen? Maybe shall I have a try with a resize-lock while list is being scrolled, but it will always leave some margin for error so it's not the fix I'm looking for.
Thanks for your help.
EDIT :
Well, it seems like the RX part was not so clueless. The IObservable I was subscribing to, aiming to show the error message, was a ReplaySubject. It appears that looping was happening on there due to this little guy, refreshing the UITableView (through TV.BeginUpdates/TV.EndUpdates) endlessly. So by now I assume ReplaySubject and cell-reuse won't work well altogether, since a simple replacement with a BehaviorSubject fixed the issue.
I have UITableView in a ViewController (not a UITableViewController) with UITextFields in each row. I would like the TableView to automatically scroll so that the row below the row being edited is always displayed. This allows the user to tap the next row to edit it. The built in iOS Reminders app has this behaviour.
I have followed Apple's advice on managing the keyboard but that only scrolls to show the row you are editing just above the keyboard, not the row below it.
I have tried adjusting the frame in scrollRectToVisible: but it makes no difference. In fact commenting out that line of code seems to have no effect at all.
It seems that the UITableView will always try to scroll to show the UITextfield being edited just above the keyboard, and I can't find a way of adjusting or overriding this behaviour so that it shows the row below it also.
Update:
I've found that the automatic scrolling behaviour can be prevented by overriding the private scrollTextFieldToVisible method of UITextField.
However, the automatic scrolling code provided by Apple in the linked documentation still does not work.
You can try setting setContentOffset property instead of scrollRectToVisible. like
[self->_scrollView setContentOffset:CGPointMake(0, textFieldRect.origin.y)];
Please follow the below link, it will make your work very easy.
Just add the files and make the tableview class name as "TPKeyboardAvoidingTableView"
https://github.com/michaeltyson/TPKeyboardAvoiding
I've checked all the usual suspects. I have a UITableView in an iOS 8 app that uses the UITableViewCellStyle.Subtitle and sets a subtitle for every cell. I won't bother including code as it's no different from any other code for this. The issue I'm having is best described as follows: my cells also have actions (the new API in iOS 8 lets you add actions to your cells accessible by swiping left on them, similar to Mail). Sometimes (seemingly random), however, the subtitles don't show up unless I swipe on them. Upon swiping, the subtitle appears. Scrolling the cell in and out of view again makes the subtitle disappear until I swipe on it once more. What could be causing this? The subtitle attribute is clearly being set on the cell, it just isn't visible when the cell becomes visible.
Additional info: when troubleshooting, I decided to disable the actions on the cell to see if that was the issue. However, the same problem would occur. Interestingly, with actions disabled, scrolling the cell out and back into view would cause the subtitle to appear.
I'm not unconvinced it's related to this: Subtitles of UITableViewCell won't update
You can chech my answer here for a temporary work around. Just put a blank space character in the interface builder inside the subtitle. check the answer for more details.
I'm building a dictionary app, and one of the features is that you can "drill down" into a definition. You look up a word, there's a word in the definition you don't understand, so you tap that word and the app shows you the definition for that word, if available. This is pretty standard for iOS dictionary apps on the App Store, if anyone's familiar.
One feature is that I am going to have a bar that shows each word as you drill down, so you get a sort of "chain" of words across this horizontal bar. The idea is you can tap on the words in the chain to navigate forwards and backwards through your chain of words.
To represent this chain I am using a UICollectionView, with a subclassed UICollectionViewController. Since it's essentially a "grid" with a single row, this made sense to me. I'm using a storyboard, so I simply embedded my custom controller into the main view, pass events back and forth between the master controller and this custom collection controller. Pretty simple.
Now, let's say the user taps many different words, so you get the "chain" of UICollectionViewCells growing across the bar from left to right until you hit the edge. Since UICollectionView is based on/has a UIScrollView in it, this shouldn't be a problem. My concept is that, if the number of items to be displayed exceeds the width of the view, the CollectionView would expand the contentView and place items off the right edge of the view port, and I could then programmatically scroll the view to show the newly added item.
Here's the code that I use to do this (edited). It's a method that I call in my subclassed UICollectionViewController:
- (void)reloadDataWithAnimation
{
[self.collectionView performBatchUpdates:^{
[self.collectionView reloadSections:[NSIndexSet indexSetWithIndex:0]];
} completion:^(BOOL finished) {
[self.collectionView scrollToItemAtIndexPath:[NSIndexPath indexPathForRow:model.data.count - 1 inSection:0]
atScrollPosition:UICollectionViewScrollPositionNone animated:YES];
}
}];
}
This is more or less what I'd normally do with a UITableView: tell it to reload its data after I have changed the model. It didn't quite work at first until I found a question on SO that covered the use of performBatchUpdates, and I had trouble doing the scrollToItemAtIndexPath until I realized it needed to go into the completion block.
Now, here's the funky part: everything works fine before the items fill up the whole view. The first time an item would go beyond the boundaries, the CollectionView places the item below the last item in the row. This looks really strange because the view is only one row tall, so you can kinda half-see the item parked below the last one in the row, mostly obscured. No scrolling occurs.
At this point, if you scroll the CollectionView back and forth, the item reconfigures itself and moves into the correct position. Or, if you add another item, they align correctly and the view scrolls as intended. Successive additions work just fine. However, if you scroll back to the left and then add another item, it briefly appears underneath the last currently visible item in the viewport, then the view scrolls off to the far right and as it scrolls the misplaced item jumps up into its proper position.
Although I began posting this question as I could find nothing on Stack Overflow, in the course of writing my question, the Similar Question sidebar updated and I found similar questions, and eventually an answer.
Similar question: UICollectionView cell layout is out of the collection view's bounds
Apparently this issue is known to Apple.
Here is the solution linked to in the above question: https://stackoverflow.com/a/13389461/700471
The code that Nick Snyder posted solved the problem for me perfectly.
Edit: Additionally, in the end I subclassed UICollectionViewLayout, bypassing FlowLayout, and made my own layout with this tutorial.
Have a strange issue where about 15% of the time, when selecting a cell with a UITableView the cell highlight flashes quickly and didSelectRowAtIndexPath is not called. The rest of the time it is working fine.
Tested how it was being selected (fast / slow finger nail, etc), but this does not seem to be the case. Looks semi-random.
Any thoughts one what might be causing this?
IOS 6.x
[Addition]
Thanks for the comments so far.
If while clicking the mouse (simulator) is moving, the problem can be duplicated. Even if the table is set to .scrollEnabled = false it is still happening. Also, the didHighlightRowAtIndexPath does fire and the didSelectRowAtIndexPath does not in the "quick" case.
Same thing happens on IOS 5.x also...
[Conclusion]
Well, it turns out that the scrolling was turned off for the table and it seems to be even more picky with the "moving tap" Turning the scrolling on actually made the "moving tap" less picky. There were a couple of other postings that I just found that pretty much said the same thing. This is a strange conclusion for a table view that has scrolling disabled and produces a "quick highlight" with no selection. Looks like this is why they added the didHighlight in IOS 6 to try and get around this "issue".
is it possible that a view from with in the cell is absorbing the touch rather than the cell ?
maybe you have a gesture recognizer in the cell, those take priorities over simple touch events
It seems that for some reason your cell is disabled. Try setting cell.enabled = TRUE; right before the cell is displayed and see if it fixes anything.
You're moving your finger up or down slightly, causing the table to scroll. Your item will not be selected, and the highlight will disappear. I've dealt with this before by tracking the row in tableView:didHighlightRowAtIndexPath, and then doing the action in tableView:didUnhighlightRowAtIndexPath: . You might also be able to solve your problem by making the tableView not scrollable if that's an option in your ui.