Skip to content

Custom Controls with Xamarin Studio, and Accessibility for Calabash iOS

Joshua Moody edited this page Jun 17, 2015 · 3 revisions

Xamarin Framework

The Xamarin cross-platform framework provides many features, but custom controls need to be set up for accessibility.

Also be sure to check out Instrumenting your Application for Calabash iOS.

No info in, no info out

If nothing is specified for accessibility in your code, then there will be nothing displayed in the output. For our project, a custom control was created. While our code utilized the control and it was able to get and set its value and correctly display it, there was nothing picked up for its value! A query looked like this:

irb(main):057:0> query("view:'Adapx.Capturx.Tablet.ipad.Checkbox' index:0")
[
    [0] {
              "class" => "Adapx.Capturx.Tablet.ipad.Checkbox",
                 "id" => nil,
              "label" => nil,
        "description" => "<Adapx.Capturx.Tablet.ipad.Checkbox: 0x173ca990; baseClass = UIControl; frame = (461.55 586.131; 7.65 7.65628); layer = <CALayer: 0x173ca820>>"
    }
]

While the control could be changed through touch(), nothing was communicated about its state. Was it checked? Unchecked? And there's lots of them in the view. However, the control inherits from UIControl, which inherits from UIView, and UIView contains most of the accessibility properties.

"label" and AccessibilityLabel property

Here's the easiest to implement, just set the property with a value:

this.AccessibilityLabel = "Checkbox 1234";

This sets the language-specific label. If this was French instead of English, it might be "Case à cocher 1234." Now the query returns:

irb(main):058:0> query("view:'Adapx.Capturx.Tablet.ipad.Checkbox' index:0")
[
    [0] {
              "class" => "Adapx.Capturx.Tablet.ipad.Checkbox",
                 "id" => nil,
              "label" => "Checkbox 1234",
        "description" => "<Adapx.Capturx.Tablet.ipad.Checkbox: 0x173ca990; baseClass = UIControl; frame = (461.55 586.131; 7.65 7.65628); layer = <CALayer: 0x173ca820>>"
    }
]

"description" and Description property

Hey, great, we're getting somewhere! But what's the value? Is that check box checked or not? The description can be updated for that. Just override the property. You can put in anything you like in the description text.

public override string Description
{
    get
    {
        return base.Description + string.Format("; text = Checkbox is {0}", this.IsChecked ? "checked" : "unchecked");
    }
}

Now the query returns:

irb(main):059:0> query("view:'Adapx.Capturx.Tablet.ipad.Checkbox' index:0")
[
    [0] {
              "class" => "Adapx.Capturx.Tablet.ipad.Checkbox",
                 "id" => nil,
              "label" => "Checkbox 1234",
        "description" => "<Adapx.Capturx.Tablet.ipad.Checkbox: 0x173ca990; baseClass = UIControl; frame = (461.55 586.131; 7.65 7.65628); layer = <CALayer: 0x173ca820>>; text = Checkbox is checked"
    }
]

"id" and AccessibilityIdentifier

But what about the id? This is what Apple uses for automation. Setting id takes a little more work, but not much. The Mono framework will map the property to the Apple [UIAccessibilityIdentification] (https://developer.apple.com/library/ios/documentation/uikit/reference/UIAccessibilityIdentification_Protocol/Introduction/Introduction.html) protocol, and set the accessibilityIdentifier element identifier.

[Export("accessibilityIdentifier")]
public string AccessibilityIdentifier { get { return "checkbox5678"; } }

Visual Studio can add the appropriate using statement for you, just right-click and select resolve. Now the query returns:

irb(main):060:0> query("view:'Adapx.Capturx.Tablet.ipad.Checkbox' index:0")
[
    [0] {
              "class" => "Adapx.Capturx.Tablet.ipad.Checkbox",
                 "id" => "checkbox5678",
              "label" => "Checkbox 1234",
        "description" => "<Adapx.Capturx.Tablet.ipad.Checkbox: 0x173ca990; baseClass = UIControl; frame = (461.55 586.131; 7.65 7.65628); layer = <CALayer: 0x173ca820>>; text = Checkbox is checked"
    }
]

Now the control object is fully identified by name, and you don't need to resort to trying to figure out what is displayed where, and hoping that the index to the control doesn't change when the developers change something.

Clone this wiki locally