iOS Accessibility Tutorial: Making Custom Controls Accessible |

In this iOS accessibility tutorial, you’ll learn to make custom controls accessible using VoiceOver, elements group, custom action, traits, frame and more.

This is a companion discussion topic for the original entry at
1 Like

Hi Andrew,

This tutorial is really interesting and well done, thanks a lot. :clap:
However, I have a problem with the custom actions under iOS 13 because you mentioned:

Wait a moment after the first announcement. You’ll hear an announcement about your custom actions being available.

… but this announcement never occurs. :unamused:

I followed the same instructions provided by this a11y dev site but it’s exactly the same result. :cry:

Is there something to add or specify in iOS 13 to make it work because it seems to be working under iOS 12, please? :thinking:

Thanks in advance for your reply.

Hi @capitainecaverne,
I’ve seen some mentions about this on Stack Overflow too, it appears to be an iOS 13 bug, but I need to do some more digging. I’ll let you know what I find.

Hi again @capitainecaverne,

I’ve done some digging and some further testing. I couldn’t find mention of a specific iOS 13 bug anywhere. I’ve tested the tutorial app on my phone and it seems to be working.

VoiceOver tries to be as efficient as possible by changing it’s behaviour to suit your current settings and not repeat announcements if unnecessary, but the way the app main screen is implemented also has an effect.

Here are some patterns I noticed through testing:

If I enable VoiceOver before starting the app, and have the rotor position set to “Headings”, when the app launches it focuses on the first amp name, and adds “Actions Available” after the amp name is read.

But, If I enable VoiceOver before starting the app, and have the rotor position set to “Actions”, it adds “Swipe up or down to select a custom action, then double tap to activate” after the amp name is read. Which is the announcement you hear in the video in the tutorial.

The relationship between the rotor setting and the actions announcement behaves the same if I turn on VoiceOver while the app is running, but the first element focuses is the navigation controller title and I have to swipe right to focus on the amp name label to hear the announcement.

This behaves differently if I run the app from Xcode on my device, or simulator, in which case it seemed random; sometimes it would say it, sometimes not.

Due to the way this screen is implemented, the “Actions available” announcement is only heard on the first launch, I think this is due to the fact that the actions are attached to this view controller, and the view controller doesn’t change. Only the content of the screen is updated.

If you install the app on your device, then launch it fresh (without Xcode) do you see a similar pattern?

Hello Andrew,

I notice the same behaviors but all that is quite different in iOS 12 where nothing works this way: everything is quite more natural for the user and actions available is always announced whatever the kind of environment we’re trying to set up.

That’s really a huge problem unless something new has been introduced in iOS 13 but, according to all the comments seen on the web, I don’t think that’s the case.

Anyway, thanks for your detailed return :+1: and I sincerely hope that this bug will be fixed very soon… I understand better why many of the VoiceOver users prefer staying one version below. :disappointed_relieved:

A good reference (even though I couldn’t find a mention of this specific problem) is the AppleVis blog: The original iOS 13 post on bugs shows the rollercoaster ride:

Thanks Andrew, I wrote a comment about this problem and sent an email to ‘’ I didn’t know before reading this blog page. :wink:

Here’s the answer from ‘’:

This announcement was previously offered on every element where the Actions rotor was available. Now, this announcement will occur when you navigate to a new container or to another elements that contains a different set of actions. This is done to prevent repetitive announcements on elements where the same actions are present as the previous element.

Many things are otherwise incomprehensible at least confused:

  • Q1: when they’re talking of a new container, do they mean navigation/tab bar/split view for instances? Can it be a created accessible element?
  • Q2: when I create a simple accessibility element with custom actions on an iOS 13 blank project, the announcement never occurs and there’s nothing else on screen but this label. I don’t think it’s normal? The user mustn’t check if every element has custom actions, it should be automatically highlighted by VoiceOver. Is it normal?
  • Q3: when I add another accessibility element to the previous screen containing one accessibility element and both with a different set of custom actions, only the first one has an announcement while VoiceOver reads out nothing for the second one. Is it intended because one can’t know that actions are available on the second element?
  • Q4: when the second element is focused, a swipe back to the previous one containing other custom actions isn’t announced anymore while its actions are still present. If many elements are present on the screen, the user mustn’t memorize which one contains what on the different screens. Why is there such a behavior?
  • Q5: “This is done to prevent repetitive announcements on elements where the same actions are present as the previous element.” Following this rationale, how can a user know that actions are available if it’s not announced on an element even if they are the same as the previous element? The user can’t test every element to know if actions are available… it’s already hard enough as it’s for blind people.
  • Q6: is this new behavior exposed anywhere in a WWDC video or on the Apple official website because I must have missed it and, apparently, I’m not the only one? :cry:

It’s completely insane to notice that everybody makes the same observations and nothing seems to move to correct or perfectly explain this new ‘behavior’. :exploding_head:

I have really missed something, it’s not possible otherwise: I can’t imagine that such an important feature may be changed and imposed without clarifications to everyone.

Anyway, I don’t think I will receive an answer to my latest email because it challenges too many principles and involves clear explanations: I hope I’m wrong and will keep you inform. :wink:

Awesome work @capitainecaverne, thanks for posting it.

I think “container” is anything that implements the methods in: which can be just a view containing subviews that are accessibility elements

Otherwise, I’m just as perplexed as you :confused:

As a conclusion, here’s the answer I received from a DTSI (Developer Technical Support Incident) I received from an Apple engineer:

There is no published information.
We intentionally made changes in iOS 13, so that we would only speak actions available if the list of actions had changed from the previous element you were on, or you moved to a different container.
You can do a flash manipulation of the list or bounce quickly between containers but this should just work without code changes.
Unfortunately in currently shipping systems it is a bug.
We are improving our documentation as well so please stay tuned.

Conclusion: a huge modification about the custom actions has been introduced in iOS 13 dealing with more than a simple feature for the VoiceOver users (it’s a necessity for them! :triumph:) with no published information :fearful: (I don’t know how blind people can find out how this works if nothing is explained because it’s definitely not user-friendly :pleading_face:) and, moreover, it’s bugged. :+1:

I always found that Apple was the best for a11y on mobile devices but, now, I reconsider my point of view for sure. :unamused:

Thanks for sharing your knowledge and for your feedback Andrew: keep on working with a11y, that’s the best way of improvement for everyone in my view. :sunny: :wink:

Thanks so much for the update, @capitainecaverne. It’s great to get confirmation from the source. Looking forward to the improved documentation and bug fixes :smirk:

This tutorial is more than six months old so questions are no longer supported at the moment for it. Thank you!