Showing posts with label focus. Show all posts
Showing posts with label focus. Show all posts

Friday, August 19, 2011

Focus problems with list rows and ImageButtons

There has been lot of discussions on this blog about some widgets that steal focus from others - creating behaviour that sounds completely illogical for the uninitiated. So far we have seen how Buttons steal the focus from list rows. The same monster rears its ugly head in this slightly different example. Here we have a simple ListView with list rows. Each list row has a text widget and an ImageButton in it. Now if we code this example innocently without being aware of the tricky focus-stealing effect of ImageButton, list rows cannot be selected.

Click here to download the example program.



The example program as it is works nicely. If you click the row, you will get one sort of Toast message. If you click the ImageButton within the row, you will get another Toast message. Now let's observe this XML attribute in res/layout/item.xml:

android:descendantFocusability="blocksDescendants"

Try removing this attribute and notice, that selecting list items does not work anymore. What happened? As explained previously, ImageButton steals the focus from the view group (the list row) it is in. This means that when you click the list row, it is always the ImageButton that captures the event but as it is outside of its screen area, the event is discarded. Therefore we prevented the ImageButton to capture the focus.

Previously I recommended preventing the capture of the focus by making the button non-focusable (android:focusable="false"). Curiously, it does not work in this example so I had to find another way. That's why I shared this example.

Tuesday, October 27, 2009

Lists and focuses

I received another seemingly trivial question in a comment. The situation is simple: we have a ListView and it contains TextViews. The user clicks (touches) a list row and the row gets highlighted until the user removes his or her finger (releases the mouse button in case of the emulator). Then comes the mistery. If you put a Button into the row, this highlight does not happen. How come?

Download the example program from here.

The secret is the quite complicated relationship between the ListView's selection algorithm and the focus. Button is focusable, basic TextView is not (Button is really just a specialized TextView). ViewGroup (whose child is LinearLayout which encapsulates one list row) delegates the focus to its first focusable child if it is not prevented to do so. As list row gives away the focus to the first focusable child (the Button) and the user did not touch the Button's area, neither the list row, nor the Button is selected. All this happens in "touch mode", try to select the row with the down/up key and you will see a completely different selection algorithm in action - the row is highlighted but the Button is not.



In order to achieve the selection effect you see in the screenshot, the ViewGroup must be prevented giving away the focus. The example program implements a quick and dirty solution: the Button is not focusable (ButtonListAdapter, line 47). More elegant solution would be to declare the ViewGroup (inflated from the buttonrow.xml layout) with FOCUS_BLOCK_DESCENDANTS flag. Conveniently, not being focusable does not prevent the Button in receiving events, click on the action button and the row counter increases nicely.