6

I have a textField with a pickerView as the inputView.

Now when I have the voiceover on and select the textField, the voiceover will read this: "Quantity: 3 (content of the textField)", then "textField", then "Double tap to edit".

Is there anyway to make the voiceover just reads the content and skip the following "textField. Double tap to edit"?

I have tried to give the textField another UIAccessibilityTraits/Hints and they are not working.

Thanks!

Ke MA
  • 761
  • 12
  • 30
  • Why not use a UILabel instead? If the text is editable, you should have these announcements. If not, you're using the wrong type of control... – MobA11y Mar 17 '16 at 03:13
  • Thanks for your reply, again! lol This kind of textField is used everywhere in the app already and there are rightViews etc, so it's a lot of work to change all of them to labels. – Ke MA Mar 17 '16 at 04:22

2 Answers2

11

In Swift

let textField = UITextField()
textField.accessibilityTraits = UIAccessibilityTraitStaticText

*The example code in this answer was written and tested in Swift 3.

 

About the accessibilityTraits Property

The accessibilityTraits property is a UInt64 bitmask. UIKit includes named UInt64 constants such as UIAccessibilityTraitStaticText for ease in remembering which bits represent which settings.

When a UITextField is created, its accessibilityTraits property is set to "262144" which is "1000000000000000000" in binary. That means the 19th bit from the right signifies "text field". There is not a constant for this setting. I tried but could not figure out how to set the 19th bit to zero. This bit appears protected from editing by the implementation for UITextField. You could subclass UITextField and override the accessibilityTraits property to take full control of it like this...

Overriding accessibilityTraits

private var _accessibilityTraits: UInt64 = 0
override var accessibilityTraits: UInt64 {
    get {
        return _accessibilityTraits
    }

    set {
        _accessibilityTraits = newValue
    }
}

 

Using UIAccessibilityTraitStaticText

If the "text field" flag is on or "1" then VoiceOver will announce "text field". As @ChrisCM posted, if the "static text" flag is also on, it cancels out the "Text Field" flag and VoiceOver does not announce anything for the type of control.

The "static text" flag is set by adding decimal "64" doing a bitwise OR of binary "1000000" to the accessibilityTraits property. The UIAccessibilityTraitStaticText constant makes this value easy to remember.

This code illustrates what is happening:

Adding UIAccessibilityTraitStaticText to accessibilityTraits in detail

let textField = UITextField()
print("original textField.accessibilityTraits, binary: \(String(textField.accessibilityTraits, radix: 2)), decimal: \(textField.accessibilityTraits)")

print("UIAccessibilityTraitStaticText, binary: \(String(UIAccessibilityTraitStaticText, radix: 2)), decimal: \(UIAccessibilityTraitStaticText)")
textField.accessibilityTraits = UIAccessibilityTraitStaticText

print("modified textField.accessibilityTraits, binary: \(String(textField.accessibilityTraits, radix: 2)), decimal: \(textField.accessibilityTraits)")

Console Output:

original textField.accessibilityTraits, binary: 1000000000000000000, decimal: 262144
UIAccessibilityTraitStaticText, binary: 1000000, decimal: 64
modified textField.accessibilityTraits, binary: 1000000000001000000, decimal: 262208

 

|= Operator

The following also works. The |= operator takes the existing value and does a bitwise OR with "1000000". Since the original value of the UITextField accessibilityTraits is protected, this is not necessary.

textField.accessibilityTraits |= UIAccessibilityTraitStaticText

 

Assigning a Different Trait

To assign a different trait such as a "button", bitwise OR UIAccessibilityTraitButton like this:

textField.accessibilityTraits = UIAccessibilityTraitStaticText | UIAccessibilityTraitButton

print("modified textField.accessibilityTraits, binary: \(String(textField.accessibilityTraits, radix: 2)), decimal: \(textField.accessibilityTraits)")

Console Output:

modified textField.accessibilityTraits, binary: 1000000000001000001, decimal: 262209

In this case UIAccessibilityTraitStaticText cancels out "text field" while UIAccessibilityTraitButton adds "button"

Mobile Dan
  • 6,444
  • 1
  • 44
  • 44
  • Thanks, great explanation ! Added information about the traits values and their basic operations are available at this a11y site : http://a11y-guidelines.orange.com/mobile_EN/dev-ios.html#element-trait – XLE_22 Mar 06 '19 at 15:52
  • 1
    The `|` syntax doesn't seem to work anymore. I use array `textField.accessibilityTraits = [.button, .staticText]` – Tanin Jun 14 '22 at 15:41
10

Assuming your text field is a subclass of UITextField, you're looking for the static text trait.

UITextField* aTextField = .....
aTextField.accessibilityTraits |= UIAccessibilityTraitStaticText;
MobA11y
  • 18,425
  • 3
  • 49
  • 76
  • 2
    This is the perfect answer! Can't believe it's hiding in the UIAccessibilityTraits. I tried to change the trait to button and it was announcing "button, textfield". Also tried to set it to none and it was still announcing "textfield" Thanks ChrisCM, AccessibilityMaster! – Ke MA Mar 17 '16 at 21:28
  • 1
    this answer should be aTextField.accessibilityTraits |= UIAccessibilityTraitStaticText – Blake Apr 20 '20 at 17:57