Making UITextfield accessible in a Customised UITableViewCell - ios

I have a UITextfield which is a subview of a UITableViewCell. I have customised the UITableViewCell, where I define the UITextField as a property. In the customised class, I override the UIAccessibilityContainer protocol methods.
However I am unable to set the textfields in my test script. This may be because the UIATableCell recognises its' children as UIAElements and not specifically UIATextFields. I am unable to perform to use the element as receiver for the method setValue.
It seems that the trait setting modulates how UIATableCell recognises its' children. However from the apple docs, a UITextField is best described as having either the UIAccessibilityTraitAllowsDirectInteraction or the UIAccessibilityTraitAdjustable. Neither of these help.
As far as I can tell, I have set the visibility hierachy correctly.
[self.contentView addSubview:self.aTextField];
for (UIView *eachView in self.subviews) {
[eachView setIsAccessibilityElement:NO];
}
[ self.aTextField setIsAccessibilityElement:YES];
[ self.aTextField setAccessibilityLabel:#"textFieldOnCell"];
[self.contentView setAccessibilityElementsHidden:NO];
Have I missed a step in making a UITextField accessible in a customised UITableViewCell ? Any help would be appreciated.

We noticed this problem and worked around it in Illuminator.
The basic idea is to tap the parent element (which should force the keyboard to appear) then use they keyboard to type the desired string.

Related

Can't use UICollectionView in UIInputViewController for keyboard extension

I have created a UICollectionView subclass which I want to use to provide the keys in a UIInputViewController as a keyboard extension. But I have found that attempting to instantiate a UICollectionView will cause the keyboard to crash whenever the user switches to it. Thinking it might be something to do with my UICollectionView subclass, I tried replacing it with a plain UICollectionView, but this caused the same problem. I even tried just instantiating the object but not doing anything with it, as in the extract below, but it still crashed the keyboard.
// KeyboardViewController.m
- (void)viewDidLoad {
[super viewDidLoad];
UICollectionView *collect = [[UICollectionView alloc] initWithFrame:CGRectMake(0, 0, 200, 200)];
}
I can't get any debugging on the keyboard, because the debugger attaches to the main app's process, so I can't tell what is causing the crash. I would really appreciate any input on whether it is possible to use a UICollectionView on a keyboard extension, and if so, how I can get around this issue.
It turns out that the problem was being caused by simply importing the header for the UICollectionView subclass, even though I didn't use it. When I removed the import, I was able to instantiate a plain UICollectionView and add it as a subview of the keyboard.
This meant I had to do some fairly nasty stuff to abstract the delegate and datasource methods into a separate class so that they would be reusable, but it works.

How can I add Apple's source code for UITableViewCell to my project?

Before you tell me that all I need to do is import UIKit, I know all about importing, and NO, that's not what I need to do in this case. Intrigued? Confused? Read on...
I have two different, but similar, custom UITableViewCells. Both have a UILabel and a UISwitch. Version one, DisplayCell, has a second UILabel, while version two, EditCell, has a UIPickerView. How I use them is like this, in a static UITableView that I'm using as a fill-in-the-data form, DisplayCell is the standard view which displays the selected value. The user can tap on DisplayCell to replace it with EditCell, then use the UIPickerView to pick a new value and hit done (button in the nav bar at the top). DisplayCell is then brought back, displaying the newly selected value. In either version the user can tap the switch to toggle whether or not the value from the UIPickerView should be used elsewhere in the form.
When it came time to write the code for the tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> (UITableViewCell) function I decided to rewrite my code so that I have a single class, SwitchCell that inherits from UITableViewCell and contains the IBOutlet and IBAction for the switch, then have DisplayCell and EditCell inherit from SwitchCell.
This works fine, however DisplayCell is now nothing more than a IBOutlet for a UILabel, and UITableViewCell, which DisplayCell inherits from via SwitchCell already has two UILabel IBOutlets, textLabel and detailTextLabel. The whole purpose in creating SwitchCell was to try and minimize code by only ever write any block of code once, something that I'm a bit of a fanatic about. Thus I would very much rather have the UILabel in DisplayCell use the detailTextLabel IBOutlet from UITabelViewCell, rather than having to create a 'redundant' UILabel IBOutlet for it.
In order to link to an IBOutlet in a superclass you must be able to bring up the code for that superclass in the assistant editor. Then you can just control+drag and link like normal. Which means, in theory, I believe it should be possible to link my UILabel to UITableViewCell's detailTextLabel, if I can access the appropriate line from the source code for UITableViewCell in the assistant editor. Is this possible, and if so, how?
Oh, and I'm working exclusively in Swift in this project, FYI.
tl;dr: It's really not anymore efficient to use UITableViewCell's default UILabels than it is to just add your own.
In order to link to an IBOutlet in a superclass you must be able to bring up the code for that superclass in the assistant editor.
Well, that's not correct. The assistant editor is not required to link to an IBOutlet defined in a superclass. But that's not important here anyway.
You can't link to detailTextLabel in Interface Builder because it's not defined with the #IBOutlet attribute. And although it is possible to override properties in Swift (so you can add #IBOutlet to it), that won't work in this case because an IBOutlet has to be mutable, and the superclass has defined the variable as immutable.
Now you could overcome this by adding your own setter method in the subclass to make the property mutable. I was able to do this with the following code:
var _detailTextLabel: UILabel?
#IBOutlet override var detailTextLabel: UILabel? {
get {
return super.detailTextLabel
}
set {
_detailTextLabel = newValue
}
}
I could wire this up in Interface Builder just fine. So perhaps I could tweak this code to actually get an set what I want (I don't think it would work as shown here). We're so far outside the realm of common-sense coding that we just need to stop and give up on this idea.
Thus I would very much rather have the UILabel in DisplayCell use the detailTextLabel IBOutlet from UITabelViewCell, rather than having to create a 'redundant' UILabel IBOutlet for it.
I can relate. I'm just as anal. :-)
However, if you do a little testing (or read the UITableViewCell header file) you'll see that UITableView is smart enough (optimized enough?) to not actually add a UILabel to the content view unless you try to use it. So at worst you have an unused property.
So it's really not inefficient to just add your own UILabel and property.

Does Apple set UIView tags?

I want to set the tag of a UITableViewCell that I, personally, create, with initWithStyle:reuseIdentifier: in tableView:cellForRowAtIndexPath:, to 0 or 1 to indicate whether I should position its subviews to the left or right. Is it safe to do this, or will Apple mess with the value of this cell's tag? I know I could use a separate cell identifier for each type of cell, but both cells are pretty much the same, besides positioning of subviews and some colors. (I'm recreating the native Messages app with the chat bubbles.)
While you can certainly use tags, I'd definitely suggest to be more explicit. You will do yourself a favor when you look at your code a few months from now. I'd create a custom UITableViewCell subclass that has a contentAlignment property that you can explicitly set to left or right. It will be much more readable that (ab)using the cell's tag.
Something like this:
typedef NS_ENUM(NSUInteger, MyTableViewCellContentAlignment) {
MyTableViewCellContentAlignmentLeft,
MyTableViewCellContentAlignmentRight
};
#interface MyTableViewCell : UITableViewCell
#property (assign, nonatomic) enum MyTableViewCellContentAlignment contentAlignment;
#end
Enjoy.
It's okay, but a better place to set the tag would be the tableView:willDisplayCell:forRowAtIndexPath: method of the UITableViewDelegate. According to the docs:
A table view sends this message to its delegate just before it uses cell to draw a row, thereby permitting the delegate to customize the cell object before it is displayed. This method gives the delegate a chance to override state-based properties set earlier by the table view, such as selection and background color. After the delegate returns, the table view sets only the alpha and frame properties, and then only when animating rows as they slide in or out.
It is absolutely safe to set a UITableViewCell's (or any UIView's) tag to whatever value you want. No one (including Apple) will mess with this tag's value outside the control of your application.
I think it's OK to give UITableViewCell a tag. Interface Builder lets you do it. Still, feeling shaky about doing so is understandable. Normally, you'd give a tag to a view that you're explicitly adding to another view via addSubview:. But, think about it. If Apple messed with the values of any of the tags of the views within your view controller's view, then that could break the functionality of something like [self.view viewWithTag:TEXT_FIELD_TAG]. So, I doubt they would. I have heard once that Apple reserves the tag integers <= 10, and therefore, you should use integers > 10 for tag values, but I don't see how that could be true.

if scrollview inherits from UIView how come my code below doesn't work?

if scrollview inherits from UIView how come my code below doesn't work?
DOBMonthTextField us an an IBOutlet for a UITextField.
[DOBMonthTextField setHidden:YES];
It stopped working when I made my UIVIEW underneath the text field a scrollview. The text field use to hide when I executed the code above. Now it doesn't hide.
While changing the views in nib files via cut-paste, the IBoutlet connections of those views go missing (disconnected), so you always have to reconnect them after pasting.
Check your connections whenever some code for a view created in nib/storyboards used to work earlier but does not after some modifications.
Because hidden (or its setter, setHidden:) is a property of an instance of DOBMonthTextField, not the class itself. Classes don't have properties in Objective C. Here's an example of roughly what you should be doing instead:
DOBMonthTextField *someInstance = [[DOBMonthTextField alloc] init];
[someInstance setHidden:YES];

Is it possible to access a property in the superclass from a subclass that belong to subclassed element?

I am sub-classing a UIScrollView element in response to a previous question suggestion.
In my subclass I have a few methods that are triggered by touch and keyboard events. Those events need to interact in various ways with variables that are in my superview.
I've tried accessing them via _myVar.text = #"smth" but that doesnt compile.
I know I could play back and forth with NSNotifications but is there a way to access the variables in my superview / class from my UISCrollView subclass?
I've tried self.myVar = #"" but it says that it is not recgonised. I am subclassing an UIScrollView element but then my view that hold all my variables is a UIViewController. just the UISCroll element was subclassed
Everything that is a #property in your superclass is accessible in your subclass, but not in the other way
It sounds like you're a little confused here. Are you sure you're talking about the superview? Or are you talking about the superclass from which you derived your subclass? If superview, and if you know the type of the superview, get a pointer to it, cast it to the appropriate class type, then call methods on it or access its visible properties.
UIButton* superButton = (UIButton*)[self superview];
superButton.visible = NO; // Assign to superview property
If you're talking about the superclass (in your case UIScrollView), then yes of course you can use any of its visible methods and properties.
self.bounces = YES; // Assign to superclass property
In case it's not clear what the difference is, you should really do some more reading about the basics of Objective-C and object oriented programming.
Superview: the view relative to which this view is laid out. This view is a subview of the superview. UIView and all derived classes have this hierarchical relationship.
Superclass: the class whose functionality you are extending to define your subclass. Your subclass inherits all visible properties and methods.
So much confusion, where to start? I really don't know. For what it's worth,
_myVar.text = "#"smth"
will obviously not compile, note the stray ".
_myVar.text = "#smth"
has a better chance of compiling.

Resources