I've an app displaying a list of presets items in a ListView.
It's possible to add, modify and remove each of these items, most often by clicking on an item (becoming selected) and then on a button to do the desired operation.
The items are then sorted and the new list is displayed, showing the result of the operation.
Rendering problems come when I keep wanting to see the initial item as selected in the new list (except in case of removing), without having to click on it, and even without operation (in case of switching between apps). So I had to use postDelay at two places in the code.
So here is my code until now, on rebuilding the list:
...
String presetId = presetsHandler.getPresetId(listIndex); // listIndex is the initial position of the selected item
presetsHandler.sortPresets();
listIndex = presetsHandler.getIndex(presetId); // New position
...
lvAdapter.setTextItems(presetsHandler.getConcatenatedDisplayPresetDataList()); // Replace all the items
listView.setAdapter(lvAdapter); // Attach the new preset list to the ListView
...
if (listIndex != LIST_INDEX_DEFAULT_VALUE) { // Need to keep initial item as selected
final long RENDERING_DELAY_MILLIS = 200;
listView.postDelayed(new Runnable() { // Delay to besure that listView is ready (after the setAdapter)
@Override
public void run() {
if (listIndex < listView.getFirstVisiblePosition() || listIndex > listView.getLastVisiblePosition()) { // Invisible
listView.setSelection(listIndex); // To see the item at position listIndex (without selecting it yet)
}
listView.postDelayed(new Runnable() { // Delay to besure that listView is ready (after the possible setSelection)
@Override
public void run() {
View view = listView.getChildAt(listIndex - listView.getFirstVisiblePosition()); // The item at position listIndex was surely visible
view.setSelected(true); // and we can make it appear as selected
}
}, RENDERING_DELAY_MILLIS);
}
}, RENDERING_DELAY_MILLIS);
}
I'd like to know if it's a good way of doing it, particularly as for the postDelayed and Runnable.
Thanks
CodePudding user response:
After a moment, I found this solution, a bit stressful for the OS (10 ms between calls to the runnable), but only during the time needed to finish rendering.
The benefit of this solution is that you don't need to estimate that time lapse and it keeps the things simple.
What do you think ?
Thanks
if (listIndex != LIST_INDEX_DEFAULT_VALUE) { // Need to keep initial item as selected
final long MINIMAL_DELAY_MILLIS = 10;
final Runnable runnable = new Runnable() {
boolean isFirstTime = true;
public void run() {
if (listView.getChildCount() == 0) { // listView is not ready yet
listView.postDelayed(this, MINIMAL_DELAY_MILLIS); // Wait until ready (after setAdapter)
} else { // listView is now ready
if ((listIndex < listView.getFirstVisiblePosition()) || (listIndex > listView.getLastVisiblePosition())) { // The item at position listIndex is not visible
if (isFirstTime) {
isFirstTime = false; // Do setSelection only once !
listView.setSelection(listIndex); // To see the item at position istIndex, without selecting it yet
}
listView.postDelayed(this, MINIMAL_DELAY_MILLIS); // Wait until visible (after setSelection)
} else { // The item at position listIndex is now visible
View view = listView.getChildAt(listIndex - listView.getFirstVisiblePosition());
view.setSelected(true); // and we can make it appear as selected; There's no need to call the runnable anymore
}
}
}
};
listView.postDelayed(runnable, MINIMAL_DELAY_MILLIS); // Run it!
}