With the launch of Material Design at I/O 2014, Google made a bold statement that beautiful Android design is here to stay. As a user I was excited to see some beautiful designs come to my platform. As a developer, I was excited to see designers get excited about Android designs independently (vs designing for iOS and ‘porting’ to Android). However, as I began to dig into coding Material, I soon found that not all of the design paradigms are accessible. Here are the top offenders, from least bad to most bad.
Animations
Animations are a huge part of Material Design. The design docs break animation into 4 main categories:
- Authentic motion
- Responsive interaction
- Meaningful transitions
- Delightful details
In my opinion these categories fall into 2 major motivations:
- To delight the user (Design Doc Item #4)
- To convey information (Design Doc Item #1-3)
Using animations under the first motivation (delight user) doesn’t cause too much of an issue for accessibility. Visually impaired users won’t experience your extra flair, but it won’t hinder them from using your application.
However, the second motivation is a bit trickier. In fact, one of the three main Material principles states: Motion Provides Meaning.
Consider how colors and animations together might be subtly transferring information to visual users, while visually impaired users are left out. This part of the documentation shows a great example of this. The user is presented with a gridview of musical artists and selects the album cover for Pharell Williams’ “Girl”, which has minor tones of yellow. A yellow circle expands from the album art and briefly fills the entire screen, as the album art slides to the side and the song list populates on the screen. The animations provide strong representation that you’ve moved from a screen with several albums, to just a single album. The animated colors also provide context for what album you’ve selected. If you implement a visual design pattern like this, you need to make sure you’re offering meaningful audio cues via TalkBack to visually impaired users to convey important information about this transition.
Motion should be intentional, and provide meaning to the user. Just make sure that you have sufficient audio cues in TalkBack so visual impaired users don’t get lost in your app.
Floating Action Button
The floating action button (FAB) is one of the most prominent features in Material Design. This is the the small circular button that floats above content, typically in the lower right corner. Per the docs, “A floating action button represents the primary action in an application.” As the most important action, you want it front and center in the user’s mind. But you could be completely hiding this action from users of TalkBack, Switch Access, and directional controllers.
Consider a list view with a floating action button, like the Google Inbox app:
TalkBack and Switch Access screen readers always start at the top of the screen, and move down through view elements. Once you reach the last item in the list, then you will be able to access the FAB. In this screenshot, you might assume that you would need to navigate 4 emails before reaching the FAB. That’s pretty bad UX, but it gets worse. Once you reach the 4th list item, TalkBack and Switch Access have “Automatically scroll lists” turned on by default. This means that once you reach the end of the list on the screen, you jump to the next set of list items! You would have to make it all the way to the end of your entire inbox before you ever could access the FAB. Ugh.
There is a relatively simple way around this, but unfortunately it is only available for devices running Lollipop and higher. Just set the accessibility traversal order on your FAB in onCreate():
// Set Traversal Order for Accessibility so FAB isn't hard to access FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.floating_action_button); if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP_MR1) { fab.setAccessibilityTraversalAfter(R.id.toolbar); }
Here I have set the traversal order for the FAB to be spoken after the Toolbar, but before the rest of the content on the screen. This seems like the perfect spot for such a prominent action. This code does not change the visual appearance of the FAB.
Note that android:nextFocus* attributes only affect the order of access when the user is using a directional control, and don’t control the order that TalkBack speaks.
Snackbar
Snackbar is the new UI widget that should be replacing Toast in your applications. From the docs, “Snackbars provide lightweight feedback about an operation by showing a brief message at the bottom of the screen. Snackbars can contain an action.”
Toasts were one of my favorite UI widgets for accessibility, because they were the only items that could appear and disappear where the OS handled TalkBack automatically for you. Text of a toast is announced automatically when the Toast appears, and developers don’t have to add any extra code. I was really surprised to hear that Snackbar does not automatically announce itself.
Now developers need to remember to add extra code to announce for accessibility. My first thought was to implement the announcement like this:
Snackbar snackbar = Snackbar.make(mParentLayout, "Action", Snackbar.LENGTH_LONG); View snackbarView = snackbar.getView(); snackbarView.announceForAccessibility("Archived"); snackbar.show();
This should work (as long as your on API 16+), according to the Snackbar docs and View docs. Unfortunately, nothing gets announced if its attached to the Snackbar’s view. I’m really not sure why this is the case at all, and I’m on a mission to figure it out. But I did manage a workaround. When using announceForAccessibility, you can technically attach the method to any view, regardless of what view you are talking about. The announcement is purely contextual and only occurs in the specified moment (so you won’t have any text permanently attaching itself to random views). I decided to attach the announcement to the main wrapping layout of my screen, mParentLayout.
Snackbar snackbar = Snackbar.make(mParentLayout, "Action", Snackbar.LENGTH_LONG); View snackbarView = snackbar.getView(); mParentLayout.announceForAccessibility("Archived"); snackbar.show();
Okay, so we’ve resolved that issue with a little code. But the biggest issue by far is the fact that Snackbars can contain an action. If you take a look at the video above, you can see that the Snackbar and its action appear and disappear rather quickly, just like a Toast.
If you are using a directional controller and are currently at the top of your screen, how are you going to make it down to the bottom of the screen in time to access the action? If you are visually impaired and are using TalkBack, there is no way you could access that action button before it disappears.
Snackbar can be displayed for 3 different time lengths:
- LENGTH_INDEFINITE
- LENGTH_LONG
- LENGTH_SHORT
A potential workaround could be to set your display time length to LENGTH_INDEFINITE, meaning the Snackbar is not hidden until a user exits the screen, or another Snackbar is fired. Because the Snackbar persists on the screen indefinitely, it is more likely that users could find and access the action. However, this also presents problems. The Snackbar is intended as “lightweight feedback about an operation,” and is extremely contextual. A Snackbar with text “Archived” and action “Undo” makes sense immediately after you’ve archived an item, but loses its meaning (and may even become more confusing) within minutes after you’ve taken the initial action. By the time a user comes across the Snackbar action, they may not recall what the Snackbar even refers to! I’m still trying to find a way around this issue. For now I’m just adding in code to announce Snackbars, and not putting actions in them. I will certainly post when / if I do find a solution to the Snackbar action issue.
Material design is exciting and beautiful, and its certainly possible to have a great Material app that is also accessible if you follow these tips. 🙂
Thank you for posting this great information.