I optimizing an application for use with the trackball. I have a ListView with rows that contain three buttons. Here is my problem: whenever I move the trackball to the child buttons of the row, the focus disappears from the parent container (the row). I want to keep the focus on the entire row, as well as whatever button is currently selected for the given row.
Basically, what I need is an attribute opposite to android:duplicateParentState, something called "android:duplicateChildState." Unfortunately, android:duplicateChildState does not exist.
At the moment I have hacked it in a way such that I set an onFocusChangedListener and force the parent container to also be selected with the ListView.setSelected method. This works, but unfortunately there is a flicker as this setSelected message is posted and run to the UI thread.
Does anybody know of a way that I can keep this focus on the parent, as I traverse the children widgets?
Related
I have a details fragment that is using a DetailsOverviewRow and FullWidthDetailsOverviewRowPresenter. When the page first loads the action buttons are selected. When I press down once, focus leaves the buttons and nothing else happens. When I press down a second time focus moves to a ListRow that is further down the page. I'm trying to figure out why the overview, or body as it's called in the presenter, section doesn't focus.
Should there not be a second 'state' between the two screenshots where the overview/body is readable?
Possibly of note. The DetailsFragment isn't declared in an activities xml, I'm changing fragments manually using FragmentTransactions. Also, the Fragment is instantiated using a static create method (source below).
Thanks in advance.
Activity xml
DetailsFragment java
I haven't tried this example in particular, but from my time spent with Leanback support library, I learned that even though a lot of helpful stuff is indeed provided, a lot is not :D
So I would try these things:
1) Make sure that something in the area you want visible is focusable. (Clickable elements should be focusable by default, but better check too) What I mean is that on the screenshot, there is just text, no buttons or editable content in that area. So when you press down, there is nothing to focus. What happens if you make the body TextView focusable?
(Yes, one would expect that the support library would take care of that, but that might not be the case.)
2) Find out what actually gets focused when you press down, since as you said, the focus leaves the buttons - but where does it go? (How to find out which view is focused?) You might have a "direction problem" somewhere. That is - the focus travels based on the view hierarchy tree, not based on what we see on the screen. In some cases, it is possible to skip some elements or get stuck somewhere by moving focus through an unexpected part of the view tree, that makes sense for the algorithm, but isn't logical from the human perspective.
The details presenter focus works this way :
1) First focus is given to Action buttons. Right/left nav press shifts the focus right/left between action buttons.
2) Down nav press from actions row shifts the focus from actions row to details row (individual details items itself are not focusable), this is achieved by shifting the Thumbnail anchoring position to further south.
3) Down nav press from details row shifts the focus from details row to related row.
So the details row gains focus by changing the anchoring position of Thumbnail image. Is your thumbnail image changing its anchoring position when pressing down from actions row?
Hate to answer my own question. This was due to my failure to RTFM. I was creating the fragment UI after a network request completes. For the FullWidthDetailsPresenter to work properly it and the ClassPresenterSelector() should be initialized in the fragments onCreate() method.
I have a button in each item of a ListView whose background is defined by an XML, one background when enabled and another when disabled. When the ListView loads, it comes out correct. But, for some reason I can't figure out, if I scroll down and then scroll back up, the wrong background shows up.
I'd like to know the solution to this problem, but besides that, in general what I want to accomplish is this:
I have a button in the ListView to take the user to the website for the given item. If there is no website, I want the button to disappear, or be disabled. I seem to have the same problem with both options.
Thanks in advance for your efforts
It seems most likely that the problem lies with your getView() method. Android recycles views to save memory, so, for example, when you scroll down, it calls getView(int, View, ViewGroup) on your adapter where View is the item that just left the top of the screen. If you're not re-populating the item with the new data from the adapter, (ie, just returning convertView) it will put the View that left the top of the screen where the "new" one should be.
There is a LinearLayout with a lot of child elements. When a user touches any of those child elements, the same method will be invoked. In order not to implement the same onClickListener for each element, I implemented the onClickListener for the parent LinearLayout ONLY.
Now, when I click anywhere within the parent layout's borders, the desired method is being invoked just as I have implemented the listener for all child elements.
Q: Can I rely that anytime I implement onClickListener for the parent, all of its child elements will react to the click event?
Q: What would happen if any child element has its own onClickListener? Would there be a collision or clicking on that element would fire its own click event only?
You answered your first question with your second question. A clickEvent will be delivered to the lowest child element in the layout hierarchy. If this element does not have an onClick behaviour it will pass the event up to its parent until the event gets handled.
Therefore you can treat the LinearLayout as one single block for your onClick behaviour.
If you create another clickable element inside the layout be sure to make it big enough to reduce the chance of the user missing the correct item.
I have an activity with an EditText on top and a ScrollView with a LinearLayout inside it.
The LinearLayout is populated in the onCreate method with a set of dynamic views based on an object passed with the initiating Intent. This is typically a set of EditTexts.
The result is a list of EditTexts each corresponding to a different piece of data (and the dataset being edited is quite variable, so the list needs to be created dynamically like this).
The problem is, when one of these views has focus, and the orientation changes (say the user flips out the keyboard to type), the focus snaps to the EditText at the very top of the Activity. This is certainly undesired behavior as the user didn't intend to type in the top EditText when he/she flipped out the keyboard.
How can I dynamically create my list of views like this and not have this undesirable focus changing behavior?
Turns out I needed to assign a unique and consistent id to each of my dynamic EditTexts.
The reason the activity couldn't retain focus properly is it had no way of relocating the view because it had no id.
When an orientation change occurs, onDestroy() is called, and the activity will be created again using onCreate(). That's why the focus is snapped at the first EditText that it finds.
You might want to have a look at this: Handling Runtime changes.
Specifically, this topic: Retain an object during configuration change
I've got a ListView that works just great, except for this minor annoyance. I can use the trackball/dpad to move up and down my list, and the background changes according to which row has focus. But when I touch the row (click or long click), there's no background change letting me know what's been focused. I've tried setting 'focusable' and 'focusable in touch mode' to true on the rows, but it still doesn't work.
Just in case it matters somehow:
I am setting onClickListeners for
each row.
The row is comprised of
LinearLayouts, TextViews, and a
single ImageView.
Focusable/clickable is 'true' for each row. Have not specified values for these on the ListView.
Trackable does act funny. I can only move between rows after touching inside the ListView. If I scroll trackball above the first item, it's impossible for me to scroll back into the list.
Any thoughts?
I can use the trackball/dpad to move
up and down my list, and the
background changes according to which
row has focus.
No, it doesn't. The background changes according to which row is selected. Selection and focus are not quite the same thing.
But when I touch the row (click or
long click), there's no background
change letting me know what's been
focused.
"In touch mode, there is no focus and no selection."