SwipeListView only one item opened at a time
Asked Answered
T

5

13

This question refers to the SwipeListView component found here: https://github.com/47deg/android-swipelistview

After trying out several implementations and fixes I found on the web I decided to modify the sources a little.

I will post this here since i know it's a known issue and all the versions I found proved to have some issues eventually.

SwipeListViewTouchListener.java has suffered the following changes:

...
/**
     * Create reveal animation
     *
     * @param view      affected view
     * @param swap      If will change state. If "false" returns to the original
     *                  position
     * @param swapRight If swap is true, this parameter tells if movement is toward
     *                  right or left
     * @param position  list position
     */
    private void generateRevealAnimate(final View view, final boolean swap, final boolean swapRight, final int position) {
        int moveTo = 0;
        if (opened.get(position)) {
            if (!swap) {
                moveTo = openedRight.get(position) ? (int) (viewWidth - rightOffset) : (int) (-viewWidth + leftOffset);
            }
        } else {
            if (swap) {
                moveTo = swapRight ? (int) (viewWidth - rightOffset) : (int) (-viewWidth + leftOffset);
            }
        }
        final boolean aux = !opened.get(position);
        if(swap) {
            opened.set(position, aux);
            openedRight.set(position, swapRight);
        }

        animate(view).translationX(moveTo).setDuration(animationTime).setListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationEnd(Animator animation) {
                swipeListView.resetScrolling();

                if (swap) {
                    if (aux) {
                        swipeListView.onOpened(position, swapRight);
                    } else {
                        swipeListView.onClosed(position, openedRight.get(position));
                    }
                }
                // if (aux || !swap) {
                // resetCell();
                // }
            }
        });
    }
...

/**
     * Close all opened items
     */

    void closeOtherOpenedItems() {
        if (opened != null && downPosition != SwipeListView.INVALID_POSITION) {
            int start = swipeListView.getFirstVisiblePosition();
            int end = swipeListView.getLastVisiblePosition();
            for (int i = start; i <= end; i++) {
                if (opened.get(i) && i != downPosition) {
                    closeAnimate(swipeListView.getChildAt(i - start).findViewById(swipeFrontView), i);
                }
            }
        }

    }
...

/**
     * @see View.OnTouchListener#onTouch(android.view.View,
     * android.view.MotionEvent)
     */
    @Override
    public boolean onTouch(View view, MotionEvent motionEvent) {
...
closeOtherOpenedItems();
view.onTouchEvent(motionEvent);
return true;
}

The rest of the code not mentioned is the same.

Any comments highly appreciated, this changes prevent you from having to implement the SwipeListViewOnTouchListener in the activity which inflates the list.

Tolentino answered 24/3, 2014 at 8:27 Comment(6)
Amazing, thanks! It resolves other issues also, like this one: github.com/47deg/android-swipelistview/issues/131Signory
Works nicely without any issues.Haloid
tnx solved my issue...Dinnage
what kinds of changes should i do on "OnTouch" ? where should i add the codes ?Turbellarian
Hi Adrian, I'd really like this code to be part of the 47deg project. If you don't have time, would toy mind if I submit a PR with this in (I will credit you however you want)Minnaminnaminnie
If I recall correctly I actually think I did that, however I am not sure of it. If you want you can check it.Tolentino
P
3

Cons: doesn't close the row opened by openAnimate()

   BaseSwipeListViewListener swipeListViewListener = new BaseSwipeListViewListener() {
    int openItem = -1;

    @Override
    public void onStartOpen(int position, int action, boolean right) {
        super.onStartOpen(position, action, right);

        if (openItem > -1)
            swipeListView.closeAnimate(openItem);

        openItem = position;
    }
   }

Or better way:

 @Override
    public void onStartOpen(int position, int action, boolean right) {
        super.onStartOpen(position, action, right);
        swipeListView.closeOpenedItems();
    }

And set the listener to the listView:

   swipeListView.setSwipeListViewListener(swipeListViewListener);
Promise answered 13/1, 2015 at 12:35 Comment(0)
T
2

Your fix worked, but there is a way to do it without affecting the original code:

swipeListView.setSwipeListViewListener(new BaseSwipeListViewListener() {
    int openItem = -1;
    int lastOpenedItem = -1;
    int lastClosedItem = -1;

    @Override
    public void onOpened(int position, boolean toRight) {
        lastOpenedItem = position;
        if (openItem > -1 && lastOpenedItem != lastClosedItem) {
            swipeListView.closeAnimate(openItem);
        }
        openItem = position;
    }

    @Override
    public void onStartClose(int position, boolean right) {
        Log.d("swipe", String.format("onStartClose %d", position));
        lastClosedItem = position;
    }
}

You should however, send a pull request to apply your code as that would fix the bug.

Source: https://github.com/47deg/android-swipelistview/issues/46

Terminology answered 3/9, 2014 at 1:31 Comment(2)
Thanks for your suggestions, since this isn't a recent post I don't remember now but it's highly possible that I have tried your fix also, worked at first but then failed along the way, so far what I posted didn't seem to show errors.Tolentino
@spacebiker: Hi, is it possible to close a particular item, which is already opened in list. i used closeAnimate(postion) but its not working.Cacao
P
1

If you're going to modify the swipelistview library itself I have a simpler solution.

Add the following if block to SwipeListViewTouchListener.java in the onTouch method right at the beginning of case MotionEvent.ACTION_DOWN:

if(lastOpenedPosition != downPosition && opened.get(lastOpenedPosition)) {
    closeAnimate(lastOpenedPosition);
    return false;
}

Create an int lastOpenedPosition field and initialize it to 0, and in the generateRevealAnimate method inside the if (aux) block add:

lastOpenedPosition = position;

I would also add config variable (in res/values/swipelistview_attrs.xml) to SwipeListView and add it to the onTouch if block, to add the ability to turn this feature off and on. This basically results in if the list is touched while a row is open, than the row will close. Which, imho, is better functionality than the row closing only after you finished opening another row.

Pagan answered 22/10, 2014 at 20:20 Comment(3)
Hi, thank you for your reply, I actually did come across your solution previously, it works, but not all the time. I needed something that would work with a higher accuracy. The one I gave here is the one that works best for me.Tolentino
Interesting, do you remember what kind of situations this does not work in?Pagan
It's not something recent, as you can see the post is very old. Problems I encountered were random crashes and bugs with the animation for the list.Tolentino
C
1
swipeListView.setSwipeListViewListener(new BaseSwipeListViewListener() {
//...
  @Override
  public void onClickBackView(int position) {
    //DELETE ITEM
    adapter.notifyDataSetChanged();
    swipeListView.closeOpenedItems();
  }
//...
});
Caravel answered 25/12, 2014 at 10:2 Comment(0)
M
-1

Yeah, the SwipeListView of the original codes can open many items at the same time. Your code segment here can open one item at one time? Or when open another item, the opened items will be closed?

Marjorie answered 21/4, 2014 at 6:14 Comment(1)
After one item is open and you try to open another one, the previous item will close s you open the other one.Tolentino

© 2022 - 2024 — McMap. All rights reserved.