Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Set contentDescription dynamically when populating list of TextViews

Tags:

android

I'm trying to update Android's sample code "API Demos" application so that TextView items in the list of the default activity have the "content description" needed for accessibility. This is what the initialization looks like for the list in this activity:

public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    Intent intent = getIntent();
    String path = intent.getStringExtra("com.example.android.apis.Path");

    if (path == null) {
        path = "";
    }

    setListAdapter(new SimpleAdapter(this, getData(path),
            android.R.layout.simple_list_item_1, new String[] { "title" },
            new int[] { android.R.id.text1 }));
    getListView().setTextFilterEnabled(true);
}

And the getData function creates a Map with the appropriate intentions specified for when someone taps on one of the TextView list elements. Internally, it uses this function:

protected void addItem(List<Map<String, Object>> data, String name, Intent intent) {
    Map<String, Object> temp = new HashMap<String, Object>();
    temp.put("title", name);
    temp.put("intent", intent);
    data.add(temp);
}

This is how the Map is populated with title, which as you can see above is mapped to @android/text1 in the layout XML.

I want to set the content description of each of the TextViews with the same value as name. Things I've tried:

(1): Looping through child items of the ListView that is generated and calling item.setContentDescription(xxx) on each of them. This didn't work; apparently at the point I'm looping through the items they're not visible/accessible/existent and either way trying to call setContentDescription blows up.

(2): Creating a new layout XML for this modified TextView, that includes android:contentDescription. The layout XML looked like this

<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android" 
    android:id="@android:id/text1" 
    android:contentDescription="@android:id/text2"
    android:layout_width="fill_parent" 
    android:layout_height="wrap_content" 
    android:textAppearance="?android:attr/textAppearanceLarge" 
    android:gravity="center_vertical" 
    android:paddingLeft="6dip" 
    android:minHeight="?android:attr/listPreferredItemHeight">
</TextView>

I then made sure that "contentDescription" was added to the Map returned by addItem, and changed the initialization code to look like this:

    setListAdapter(new SimpleAdapter(this, getData(path),
            R.layout.simple_list_item_with_desc, new String[] { "title", "contentDescription" },
            new int[] { android.R.id.text1, android.R.id.text2 }));

In other words, I was trying to get "contentDescription" from my static data map to populate the field in the layout XML defined by android.R.id.text2.

This also didn't work--no failure, but when I examine the list in uiautomatorviewer, no content description is available. It could be because I don't understand what android.R.id.text2 means, other than being a placeholder for a value of some kind. I also tried android.R.id.content with the same result.

So my question is, how do I set the contentDescription of these TextViews dynamically?

like image 420
Jonathan Lipps Avatar asked Nov 20 '25 12:11

Jonathan Lipps


2 Answers

I want to set the content description of each of the TextViews with the same value as name. Things I've tried:

(1): Looping through child items of the ListView that is generated and calling item.setContentDescription(xxx) on each of them. This didn't work; apparently at the point I'm looping through the items they're not visible/accessible/existent and either way trying to call setContentDescription blows up.

You are correct, your first method failed because none of the TextViews have been created yet. The problem is they are never visible all at the same time (unless you only have a handful of rows and they fit on the screen without scrolling.)

Solution: Extend SimpleAdapter and override getView(). This method is called each time a row is displayed. It gives you access to the TextView so you can call setContentDescription() here.

like image 137
Sam Avatar answered Nov 23 '25 00:11

Sam


@Sam provided a solution, and I wanted to also contribute back the code to my extension class in case it's useful to anyone else:

package com.example.android.apis;

import java.util.List;
import java.util.Map;

import android.content.Context;
import android.view.View;
import android.view.ViewGroup;
import android.widget.SimpleAdapter;
import android.widget.TextView;

public class SimpleAdapterWithDesc extends SimpleAdapter {

    public SimpleAdapterWithDesc(Context context,
            List<? extends Map<String, ?>> data, int resource, String[] from,
            int[] to) {
        super(context, data, resource, from, to);
    }

    public View getView(int position, View convertView, ViewGroup parent) {
        TextView myView = (TextView)super.getView(position, convertView, parent);
        myView.setContentDescription(myView.getText());
        return myView;
    }

}
like image 35
Jonathan Lipps Avatar answered Nov 23 '25 00:11

Jonathan Lipps