I have a ListView (set to CHOICE_MODE_SINGLE)
I have a SimpleCursorAdapter who fill my ListView. Now i work on selection.
serviceListView.setAdapter(
new SimpleCursorAdapter(this, R.layout.service_listitem, cursor, new String[] { "name" }, new int[] { R.id.service_name }) {
#Override
public View getView(int position, View convertView, ViewGroup parent) {
final View renderer = super.getView(position, convertView, parent);
if (position == newSelectedPosition) {
renderer.setBackgroundResource(R.layout.list_view_layer_list);
} else {
renderer.setBackgroundResource(android.R.color.transparent);
}
return renderer;
}
}
);
So i want when i select a row my layout to be applied. This works fine.
But in some cases when i push for 2-3 secs a row and then drag a little bit and release the row i obtain 2 rows selected.
I try several ways to get ride of the initial selection, overwriting OnTouchListener, OnScrollListener, OnLongClickListener. No results.
Any help is welcome
Thanks
Have you tried calling notifyDataSetChanged() on your Adapter after the selection has been changed? That should cause all the rows to be rebound again, and all the views (except for the selected one) to revert back to the transparent background.
I quit this implementation.
I will try to "simulate" ListView by using a ScrollView with TextView-s for each row
Related
I have a ListView populated from a database using a customized ResourceCursorAdapter with a bindView to format each list item. The items are displayed in descending chronological order and I need to hightlight the first future event. Unfortunately I only know that it is the first future event when I process the next entry and find that it is in the past. What I really need is the ability to 'look ahead' in the bindView processing but that is not there.
The only alternative (that I can think of) is to process all items and then go back to change the background of the first future event (which I would then know).
The code I'm using is
EventsAdapter db = new EventsAdapter(this);
db.open();
Cursor cursor = db.fetchAllRecords();
final MyAdapter listitems = new MyAdapter(this,R.layout.timeline_detail, cursor, 0);
timeline.setAdapter(listitems);
db.close();
View v = timeline.getChildAt(firstEvent); // firstevent is set in the bindView
v.setBackgroundColor(Color.parseColor("#ffd1d1"));
However the View v is always null and, when I run it in debug mode with a breakpoint at the View statement, the listview has not yet rendered on the screen. I'm assuming, therefore, that that is why the view is still null.
How can I get and changeView the ListView item that needs to be changed at the time that the ListView is first displayed?
Try and extend your adapter and override getView.
final MyAdapter listitems = new MyAdapter(this,R.layout.timeline_detail, cursor, 0){
public View getView(int position, View convertView, ViewGroup parent){
View v = super.getView(position, convertView, parent);
if (position==0){
//Do something to the first item (v)
}else{
//Revert what you did above, since views get recycled.
}
return v;
}
};
or just include that in your MyAdapter class.
What I'm trying to do is to have all the rows in the listview translate to the right in order to expose a checkbox for multi-selection. And actually it works ok beside this:
the animation on the visible rows is ok, but there are like 2-3 rows, created in advance (before starting to recycle them) so the scroll is smooth, in which the translation starts when those become visible (onscreen).
I know this is normal behaviour but could there be any way to have those rows translated before they become onscreen? I was thinking of something like setting the translation time to those to 1 but can't know where the returned view will be used by the list.
public View getView(int position, View convertView, ViewGroup viewGroup) {
View view = convertView;
if (view == null) {
view = LayoutInflater.from(context).inflate(R.layout.item_conversation, null);
}
final AQuery aq = new AQuery(view);
// multiSelect
if(multiSelect) {
aq.id(R.id.row);
if((int) aq.getView().getX() == 0) {
animate(aq.getView())
.translationX(marginLeftWhenMultiSelect)
.setDuration(300);
}
} else {...
I want to add some animation to my ListView with SimpleCursorAdapter when my DB data changes.
I am using SimpleCursorAdapter with LoaderManager
I tried to add animation in getView method
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View view=super.getView(position, convertView, parent);
//My animation(nineoldandroid)
ObjectAnimator.ofFloat(view,"alpha",0,1).setDuration(500).start();
return view;
}
But this method animates all items, although some items were the same before updating.
Does Android have methods to detect which items need update, remove or add?
For example, maybe there are methods for getting changes between old and new cursor before calling myAdapter.swapCursor(newCursor); It would be possible to mark items(removed, updated, new) and make removing animation before swapping and ither animation in getView.
How can I solve this problem?
There are many ways to achieve this, you can try the answers in this question :
How to Animate Addition or Removal of Android ListView Rows
The 1st answer is working
No, at least I haven't found that Android can report to me if there are new or deleted items. I made something similar where the items of the ListView animate to their new positions and I had to track their positions myself to do that.
For your use case, it is probably easier to put the fading animation just before you delete the row from the database. So wherever in your code it is that you delete the row from the database and trigger a refresh, you do the fade animation on the item and on completion of the animation you delete the row and trigger a refresh.
Update
Hmmm, I read too quickly. Your example is not a fade-out on deleted items, but a fade-in on new items.
You will have to track item IDs yourself in your adapter. This approach can only work if you have a limited number of items to show because the list of previous item IDs will have to be stored in memory. If you can not be certain the list is never too large then you'll have to find a way to add the 'newness' information to the cursor itself.
Let me see if I can cook something up. Be back later...
Update 2
Below is a SimpleCursorAdapter that keeps track of the item ID from the previous cursor. In getView() it kicks of the fade-in animation if the requested view is for an item that was not present before.
private static class FadeInAdapter extends SimpleCursorAdapter {
private List<Long> previousItemIds = new ArrayList<Long>();
private FadeInAdapter(Context context, int layout, Cursor c, String[] from, int[] to, int flags) {
super(context, layout, c, from, to, flags);
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View result = super.getView(position, convertView, parent);
// check if this view is for an item that is new
long itemId = getItemId(position);
if (!previousItemIds.contains(itemId)) {
// do the fade-in animation
result.setAlpha(0);
result.animate().alpha(1).setDuration(500).start();
}
return result;
}
#Override
public void changeCursor(Cursor cursor) {
Cursor oldCursor = getCursor();
if (oldCursor != null) {
// store previous item IDs to check against for newness with the new cursor
final int idColumnIndex = oldCursor.getColumnIndexOrThrow(DatabaseContract._ID);
previousItemIds.clear();
for (oldCursor.moveToFirst(); !oldCursor.isAfterLast(); oldCursor.moveToNext()) {
previousItemIds.add(oldCursor.getLong(idColumnIndex));
}
}
super.changeCursor(cursor);
}
}
Maybe RecyclerView helps. Try notifyItemChanged
I overwrite the behavior of a spinner, to add odd and even colors to the drop down list, in this way.
SimpleCursorAdapter productsListAdapter = new SimpleCursorAdapter(MyActivity.this, R.layout.spinner_drop_down_products, cursor, column, viewIds) {
#Override
public View getDropDownView(int position, View convertView, ViewGroup parent) {
View view = super.getDropDownView(position, convertView, parent);
if (position % 2 == 0) {
view.setBackgroundColor(android.graphics.Color.rgb(255, 255, 255));
} else {
view.setBackgroundColor(android.graphics.Color.rgb(214, 214, 214));
}
return view;
}
};
The dropdown rows look as i expected ... but i loose the highlight on pressing each row.
What i forget to add to the code?
Thanks
Actually android framework uses selectors for all states like:
normal enabled
pressed
highlight
focused
The default selector for list is list_selector_background.xml You can see here.
You have to provide this by yourself. Say you have made a you_own_selector.xml
then you will give this as a background of your View like this:
view.setBackgroundColor(R.drawable.you_own_selector);
Here is another nice post about using selectors in android.
I have a strange problem. I am setting the background color of the items of a listview like so:
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View row = convertView;
...
if (status == true) {
row.setBackgroundColor(Color.argb(255,0,85,187));
}
else {
if (morestuff) {
row.setBackgroundColor(Color.argb(128,255,0,0));
}
}
...
}
This seems to work. However, when i scroll on the listview, and then back, some of the rows have acquired a color from another row without being set by this code. I suspect the listview is recycling the views as an optimization.
How can I fix this?
The getView will be called all the time when the listview is drawn. Simply taking it will be called when we do a small change example do a small scroll
If you want to set color to a specific row, Just do it by checking the position (First argument of getview).
The list view is definately recycling views as an optimization. You should look at the efficient list view example for ideas.