Prevent clicks to pass through in UIView in Swift - ios

Suppose I have a tableview cell.
On this I have an UIVIew rating control which works by adding buttons as subviews.
When the user clicks besides the buttons, but still on the rating control, the click is passed through to the underlying cell. I do not want that.
I am thinking there must be a proper way inside the rating control code (derived from UIView) to catch all clicks passed to it and simply never pass them through any further to the cell.

Related

UICollectionView in a UITableViewCell with Accessibility

I'm adding Accessibility support to my iOS app and I'm having trouble with a collection view in one of my table view cells.
For example, when the user scrolls (horizontally) from the first cell to the second cell, Accessibility still reads the contents of the first cell. If I try to tap on a view in the second cell, it highlights an empty space to the left of the second cell (where the first cell would be but no longer visible) and reads the contents of the first cell.
When the collection view is not in a table view cell (i.e. a subview of a UIView), this does not happen.
I'm suspecting this has something to do with calling UIAccessibilityPostNotification(UIAccessibilityLayoutChangedNotification) and I've tried calling it in many different places, but nothing has worked.
The following two screenshots show a collection view inside a UIView. Accessibility is enabled, so it gets selected with a black border when tapped.
When user taps first cell, it will get selected.
When the user taps 'Next', goes to the second cell, and taps the cell, the new cell will get selected.
The next two screenshots show the collection view inside a table view cell.
When the user taps the first cell, it gets selected and VoiceOver properly reads "I'm label 0".
However, when the user taps 'Next', goes to the next cell, and taps the second cell, it does not get selected and VoiceOver will still read, "I'm label 0".
The code is available here on github.
I had simillar problem which I eventually resolved.
I think that you have mismatched elements with
isAccessibilityElement = true
over each other.
I have a table view which scrolls vertically and each cell contains a title and collection view which scrolls horizontally.
I set isAccessibilityElement to true only on title and collection view cells, false on the rest.
Then, I subclassed UICollectionView and overrode the following NSObject methods:
func accessibilityElementCount() -> Int
func accessibilityElement(at: Int) -> Any?
func index(ofAccessibilityElement element: Any) -> Int
It basically just tells the voice over that your collection view has these accessible elements. The collection view itself is not accessible which is not a problem, the contrary. You could probably use
open var accessibilityElements: [Any]?
instead.
Here is some more reading from documentation (UIAccessibility.h):
UIAccessibilityContainer methods can be overridden to vend individual elements that are managed by a single UIView.
For example, a single UIView might draw several items that (to an end user) have separate meaning and functionality. It is important to vend each item as an individual accessibility element.
Sub-elements of a container that are not represented by concrete UIView
instances (perhaps painted text or icons) can be represented using instances of UIAccessibilityElement class (see UIAccessibilityElement.h).
Accessibility containers MUST return NO to -isAccessibilityElement.
To allow nice 3-finger voice over scroll you probably want to override
func accessibilityScroll(_ direction: UIAccessibilityScrollDirection) -> Bool
as well and scroll your collection view accordingly.
You may want to try this:
let nextCell = collectionView.cellForItemAtIndexPath(nextIndexPath)
UIAccessibilityPostNotification(UIAccessibilityScreenChangedNotification,
argument: nextCell)
in your onNextButtonTapped method, after your call to scrollToItemAtIndexPath.
This will focus Accessibility on the next collection view cell.

Save a user-input from a textfield inside a tableView

Not sure but maybe I just missed the easy way...
What I am trying to achieve is:
I have a tableView with a tableViewCell, in this tableViewCell I have a textfield in which the user can make an Input, I want to save that input when he clicks a button.
I know how to do this with the prepareForSegue function but I want do it just with the Button Action. Is that possible? Or other question, when I use the didSelectRowAtIndextPath function, can I directly access the content of the cells outlet, textfields, labels, buttons....?
Thanks for any comments...

Setting content inside of a UITableViewCell from outside source?

I have a UITableViewController with a few UITableViewCells. Each of those cells have different content: labels, images, text fields, etc. I am needing to set those pieces of content based around user interaction of my UITableViewController class.
For example: I have a cell that has a UIImageView in it. When a user taps the UIImageView I want a UIActionSheet to show. The problem is that I can't set the UIImageView as a property of the UITableViewController class. It has to be a property of a subclass for that UITableViewCell. But that means if I write the code for showing a UIActionSheet in the UITableViewCell subclass it won't show in the UITableViewController class.
My question is, since all of the objects within a UITableViewCell are in their own class, how do I alert the UITableViewController class when one of those actions happens?
Also, when a UIActionSheet is displayed it will need to show up in my UITableViewController class. If I select an item from that action sheet and wanted the text of that item to propagate to setting the text of a UILabel inside of a UITableViewCell, how could I do that?
With UITableViewController you control everything through the UITableViewDataSource implementation.
Here is how you can do it: make an int field in your model class that says which row needs to show a cell with an action sheet, and set it to -1 (which means that no cell needs to show an action sheet). In the tap handler of the UIImageView call the model, and tell it that the cell to which the UIImageView belongs needs an action sheet now. At that point you tell your UITableView to reload data. This sets the whole system in motion again - the table view calls back your data source to ask for the count, and then it calls again for the cell. This is when your data source looks at the model, sees that the row needs an action sheet, and returns a subclass of the cell with the action sheet visible.
Here is a diagram showing this sequence of events.
When the user is done with the action sheet, the action sheet needs to call the model again, and tell it that the action sheet is no longer needed (i.e. set the index back to -1). After that it should call the table view again, and tell it to reload the data. The sequence will repeat again, but is time there will be no flag asking for the action sheet, so a regular cell would be returned.
well, I simply suggest to use Custom UITableView Cell class, so when you are creating custom cell pass your uitableview controller to that class as parent. Now in your Custom Class you can add singleTap on UIImageView, from tap on it you can call method in your parent class via parent object you have already passed.

allow user to tap label and then tap buttons to edit label.text?

So what I have right now i table with multiple cells. Each cell has two UIlabels. Underneath the table are a bunch of buttons with different int values. I want to allow the user to tap on a label and then tap on the buttons to change the text of the label to whatever buttons they press. Eg if they press buttons, "1","2","3" the label will display 6.
I think i managed to figure out how to find out which label has been touched, but I'm stuck afterwards as i can't figure out how to get the button pressing part to work. Any ideas? thanks in advance!
To know which UILabel has been touched add a tap gesture to each label which triggers an action. In that actions store which label has been touched in e.g. a property.
For the buttons, just connect them to action methods (could also be a single one), inside these methods do your calculation and updated the label indicated by the property described above.

Dealing with keyboard and tableviewcell

The layout for one of my View Controllers is such: I have a scroll view embedded inside my VC. Inside my scroll view, I have a table view that consists of 5 cell. The first 3 cells consist of a textfield thats pulls its text from a dictionary and this changes depending on certain situations. These textfields are editable and so tapping on them brings up the keyboard, the issue however is that I would like my view to scroll when I tap on the text field because right now they keyboard hides the the third editable text field. Another issue is that at the moment, clicking outside teh table view doesnt cause the keyboard to be dismissed and so the only way of dismissing the keyboard is tapping on the return key. What I would like to happen is that when I tap on either one of the 3 editable fields, the scroll view ought to scroll up a certain number that I define (this is so that I can define how much to scroll depending on which row is currently selected). One of the issues I'm facing is that I can't directly reference these textfields in my VC since they're all created through one prototype cell. My thinking was that I could create a dictionary with the 3 textfields as keys and then the scrollview y coordinates as values and then use that. However , I wasn't sure how to do this in my situation (with the prototype cells). Would really appreciate if someone could show me some sample code on how to do this.
You can reference your text fields by calling cellForRowAtIndexPath: to get the UITableViewCell, then calling viewWithTag: to get your UITextField. Just assign the text fields a tag number. Also, set the text field's delegate to be your view controller so that you can respond to a user tapping to edit text.

Resources