androidlistviewconvertview

SwipeListView stays in "swiped state" after deleting a row


I'm using SwipeListView library for my list. List adapter is using ViewHolder Pattern, everything is working fine. I set up swipe left and there's a back view under my list item view. On this back view I have a text view "Delete". After click, delete operation is being performed. Data in adapter is being refreshed. Row is deleted ..but "swiped state" is being set on a row which has position close to that row which was deleted. I believie it happens because "swiped state" is remembered by convertview. When I comment out checking if convertview is null, problem is gone, but list scroll performance is unacceptable. Is there any way to clear convertview after delete action? Or is there any other work around?

My ViewHolder:

public static <T extends View> T get(View view, int id) {
SparseArray<View> viewHolder = (SparseArray<View>) view.getTag();
    if (viewHolder == null) {
    viewHolder = new SparseArray<View>();
    view.setTag(viewHolder);
    }
View childView = viewHolder.get(id);
if (childView == null) {
    childView = view.findViewById(id);
    viewHolder.put(id, childView);
    }
return (T) childView;
}

My adapter's getView():

@Override
public View getView(final int position, View convertView, ViewGroup parent) {

    if (convertView == null) {
        convertView = LayoutInflater.from(context)
                .inflate(R.layout.level_item, parent, false);
    }

    ...
    ...
    del = ViewHolderNew.get(convertView, R.id.del);

    del.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {

            Level level = list.get(position);
            long id = level.getId();
            Level leveltoDelete = Level.load(Level.class, id);

            new Delete().from(Recipient.class).where("level = ?", id).execute();
            leveltoDelete.delete();

            remove(level);
            notifyDataSetInvalidated();

        }
    }); 

And my xml file:

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="0dp"
android:background="@color/white_background"
>
//item back layout
<LinearLayout
    android:id="@+id/item_back"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

<TextView
    android:id="@+id/del"
    android:layout_width="match_parent"
    android:layout_height="180dp"
    android:gravity="center_vertical|right"
    android:layout_marginTop="10dp"
    android:layout_marginBottom="10dp"
    android:background="@color/delete_background"
    android:layout_alignParentRight="true"
    android:layout_centerVertical="true"
    android:paddingRight="30dp"
    android:textColor="@color/white_background"
    android:text="Delete"
    android:textAppearance="?android:attr/textAppearanceMedium" />

</LinearLayout>

//item front layout
<RelativeLayout
android:id="@+id/item_front"
android:layout_width="match_parent"
android:layout_height="match_parent">
...

Solution

  • I don't know that library, but I assume that it changes visibility of row item's children.

    After delete and refresh, ListView requests new rows, passing you the old views as convertViews - and one of them is the "swiped" view. Probably the same behaviour you will observe after scrolling down the list, as it's also reuses views not visible anymore.

    If you can say that the view is after swipe, probably you could apply reverse transformation before reuse (or just inflate the new one, one row per page shouldnt be very bad for performance).

    However, this soultion won't maintain swiped state if you scroll down and go back. If you need to track swiped position, you should consider adding additional view type (see getViewType(position) and getViewTypeCount()).