Hector
Hector

Reputation: 5354

Android layout resources for Accessibility vision impairment

Android applications currently support different layout resources based on orientation, screen size, day and night etc.

However, I would like to provide layouts targeted at users with vision impairments, for instance use layouts with YELLOW background and BLACK text.

Have I missed something that Android already supports?

Can I implement custom res/layout-WAI or res/layout-DDA folders?

Upvotes: 3

Views: 224

Answers (3)

azizbekian
azizbekian

Reputation: 62189

Instead of providing two different layouts, you can parametrize views in a single layout. Thus, views of your layout would take parameters (e.g. background color, text color) from the context theme they are inflated in.

So, this is what we want to achieve:

<android.support.constraint.ConstraintLayout
    android:background="?attr/bgColor"
    ... >

    <TextView
        android:textColor="?attr/textColor"
        ... />

</android.support.constraint.ConstraintLayout>

?attr/someAttribute would be taken from the theme of the current context.

Create attributes at attrs.xml in values/:

<?xml version="1.0" encoding="utf-8"?>
<resources>

    <declare-styleable name="MyAttrs">
        <attr name="bgColor" format="reference|color"/>
        <attr name="textColor" format="color"/>
    </declare-styleable>

</resources>

In styles.xml declaring two themes extending from a common theme:

<resources>

    <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
        ...
    </style>

    <style name="AppTheme.Default">
        <item name="bgColor">@color/red</item>
        <item name="textColor">@color/blue</item>
    </style>

    <style name="AppTheme.Accessibility">
        <item name="bgColor">@color/orange</item>
        <item name="textColor">@color/yellow</item>
    </style>

</resources>

Then, in your activity perform the assertion and set a correct theme:

@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
    setTheme(isAccessibility ? R.style.AppTheme_Accessibility : R.style.AppTheme_Default);

    super.onCreate(savedInstanceState);
    setContentView(R.layout.main_activity);
    ...
}

Or, if you have to do it on runtime, you may use ContextThemeWrapper to inflate specific view with appropriate theme.

Context wrapper = new ContextThemeWrapper(MyFragment.this.getContext(), R.style.AppTheme_Accessibility);
// inflating with a `wrapper`, not with the activity's theme
View themedView = View.inflate(wrapper, R.layout.some_layout, parent);

This is much better approach then providing two separate layouts, because it refrains you from maintaining two layouts when a change happens in UI.

Upvotes: 1

k3b
k3b

Reputation: 14755

Color (YELLOW background and BLACK text), fonts and font size is a topic for Styles and Themes.

Unless visually imapaired people need own layouts (arrangement, ordering of gui elements) you can implement a setting with a style chooser that can be applied to every layout

Upvotes: 1

Eyal Biran
Eyal Biran

Reputation: 5746

You can't create custom configuration qualifiers. The current supported qualifiers are listed here.

I will suggest the following workaround (Example):

  1. Create a special layout for WAI for each existing layout, with the same name, but with the suffix "_wai"

    example_layout.xml
    example_layout_wai.xml
    
  2. Create a method to resolve the appropriate layout based on system needs. Say we have a method isWAI(), resolve method will look something like:

    public int resolveLayoutResourceID(int layoutResID) {
        int newLayoutResID = layoutResID;
        if (isWAI()) {
            String layoutResName = getResources().getResourceEntryName(layoutResID);
            String newLayoutResName = layoutResName + "_wai";
            newLayoutResID = getResources().getIdentifier(newLayoutResName, "layout", getPackageName());
        }
        return newLayoutResID;
    }
    
  3. Create a BaseActivity class for all your classes (or use a utility static function), that will override the setContentView method. There you will add a logic to select the layout.

    @Override
    public void setContentView(int layoutResID) {
        int newLayoutResID = resolveLayoutResourceID(layoutResID)
        super.setContentView(newLayoutResID);
    }
    

Upvotes: 1

Related Questions