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.

Bart Kiers
  • 166,582
  • 36
  • 299
  • 288
Adrian Olar
  • 2,883
  • 4
  • 35
  • 63

5 Answers5

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);
lordmegamax
  • 2,684
  • 2
  • 26
  • 29
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

spacebiker
  • 3,777
  • 4
  • 30
  • 49
  • 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. – Adrian Olar Sep 03 '14 at 04:03
  • @spacebiker: Hi, is it possible to close a particular item, which is already opened in list. i used closeAnimate(postion) but its not working. – Aerrow Nov 14 '14 at 13:21
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.

Leo K
  • 808
  • 1
  • 9
  • 24
  • 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. – Adrian Olar Oct 23 '14 at 04:40
  • Interesting, do you remember what kind of situations this does not work in? – Leo K Oct 23 '14 at 08:08
  • 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. – Adrian Olar Oct 23 '14 at 09:45
1
swipeListView.setSwipeListViewListener(new BaseSwipeListViewListener() {
//...
  @Override
  public void onClickBackView(int position) {
    //DELETE ITEM
    adapter.notifyDataSetChanged();
    swipeListView.closeOpenedItems();
  }
//...
});
Volodymyr Kulyk
  • 6,455
  • 3
  • 36
  • 63
-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?