views:

143

answers:

2

The code below does NOT change the text of all of a ListView's rows because "getChildCount()" does not get all of a ListView's rows, but just the rows that are visible.

for (int i = 0; i < listView.getChildCount(); i++)
{
    View v = listView.getChildAt(i);
    TextView tx = (TextView) v.findViewById(R.id.mytext);
    tx.setTextSize(newTextSize);
}

So, what SHOULD I do? Is there code for getting a notification when a ListView's row becomes visible, so I can set its text size then?

A: 

List13 from the API Demos does something similar using OnScrollStateChanged. There may be a better way, though:

public void onScrollStateChanged(AbsListView view, int scrollState) {
    switch (scrollState) {
    case OnScrollListener.SCROLL_STATE_IDLE:
        mBusy = false;

        int first = view.getFirstVisiblePosition();
        int count = view.getChildCount();
        for (int i=0; i<count; i++) {
            TextView t = (TextView)view.getChildAt(i);
            if (t.getTag() != null) {
                t.setText(mStrings[first + i]);
                t.setTag(null);
            }
        }

        mStatus.setText("Idle");
        break;

. . .

EDIT BY Corey Trager:

The above definitely pointed me in the right direction. I found handling OnScrollListener.onScroll worked better than onScrollStateChanged. Even if I removed the case statement in onScrollSgtaetChanged and handled every state change, some text wasn't getting resized. But with onScroll, things seem to work.

So, my seemingly working code looks like this:

public void onScroll(AbsListView v, int firstVisibleItem, int visibleCount, int totalItemCount)
{
    ListView lv = this.getListView();
    int childCount = lv.getChildCount();

    for (int i = 0; i < childCount; i++)
    {
        View v = lv.getChildAt(i);
        TextView tx = (TextView) v.findViewById(R.id.mytext);
        tx.setTextSize(textSize);
    }
}
RickNotFred
This will probably work but it will also be very very very costly. You're doing the same work on every scroll event, of which you can receive many (and not necessarily only when a new item becomes visible.)
Romain Guy
@Romain - "costly" only matters if there is some effect that the user himself can see. And there isn't. Computers are faster than you give them credit for and they don't mind the hard work. Hey, think of any sort of paint program that reacts to every mouse movement event by extending the visible stroke.
Corey Trager
No they're not. We are dealing with phones and *everything* you do costs *battery*. There is absolutely NO REASON to be a lazy programmer and waste battery. The reason why Android is usable on phones is because we spend a lot of time worrying about performance and battery life. We still have lots to do but your point of view is certainly flawed. There are situations where there's no need to worry much about performance (button click for instance), but doing what you do for every pixel scrolled is just stupid.
Romain Guy
@Romain - Ok, ok, you convinced me that I SHOULD care, so now I DO. So, what SHOULD my code do? @RickNotFred's code, which we got from a SDK sample app, did *NOT* work. That is, some text got changed, but as I scrolled other items into view, they had not gotten the message. What works?
Corey Trager
+2  A: 

In a ListView the only children are the visible ones. If you want to do something with "all the children," do it in the adapter. That's the best place.

Romain Guy
"all the children" means the TextViews. I'm changing their font-size. Are the TextViews children of the adapter or children of the listview itself?
Corey Trager
They're children of the ListView.
Romain Guy