Author Topic: Swipeable ListView tips  (Read 3728 times)

pineappleCake

  • Newbie
  • *
  • Posts: 4
Swipeable ListView tips
« on: June 09, 2015, 06:24:11 pm »
I am attempting to implement a swipe listview in an app like described on the Jay Rambhia blog article titled "Inbox Style Swipe ListView" (I cannot post external links).

The end result is really terrible and flaky, though. I noticed AquaMail has a wonderfully smooth swipe to mark read and swipe to delete. Could you share some advice on how you implemented this?

I solemnly swear I am not making a mail app :p

Kostya Vasilyev

  • Hero Member
  • *****
  • Posts: 12740
Re: Swipeable ListView tips
« Reply #1 on: June 10, 2015, 01:14:20 am »
Um, it's not much really, I guess "devil is in the details" and maybe I'm not fully aware of them all -- I don't write blog posts, because I just don't have the talent for that...

But in a nutshell --

Each list item is a separate layout, obviously. It takes care of its own drawing (overriding draw()... can't remember why not onDraw).

To render swiping state (shifting the content to the side), I use scrollTo() on the list item layout. This automatically applies the scroll position to the Canvas that's passed into draw().

Drawing the icons is the only difference -- draw() takes note when getScrollX() is non-zero, and draws the icons and their backgrounds (being careful about clipping and overdraw).

These changes in backgrounds behind swipe action icons are animated (faded in and out), another animation is edge effects (overscroll glow) if you drag your finger too far.

When draw() leaves uncompleted (in-progress) animation, I just call postInvalidateOnAnimation() asking for draw() to be called again, until all animations are done.

Touch events are handled by a separate view, the parent of the ListView, a FrameLayout subclass.

This way, as you drag your finger, and the code changes the list item layout's horizontal scroll position, there is no effect on the coordinates in subsequent events passed into onTouch, and so there is no jumping back and forth during swiping.

The mechanics behind it is your basic onInterceptTouchEvent and onTouchEvent (take a look at ScrollView, that's just one example).

So it's like this:

<TouchDetectView fill_parent, fill_parent>
<ListView fill_parent, fill_parent>
... individual item layouts, created by the ListView's adapter
</ListView>
</TouchDetectView>

TouchDetectView onInterceptTouchEvent, onTouchEvent:

ACTION_DOWN: save coordinates

ACTION_MOVE: check if the finger has moved far enough ( get it from ViewConfiguration.getScaledTouchSlop )

If so, enter "tracking swipe" state, on each ACTION_MOVE, compute the swipe distance as current event's X - original event's X, call scrollTo (dx, 0) on the list item layout.
« Last Edit: June 10, 2015, 01:17:17 am by Kostya Vasilyev, Aqua Mail »
Creating debug logs for diagnostics: https://www.aqua-mail.com/troubleshooting/

The official FAQ: https://www.aqua-mail.com/faq/

Лог-файлы для диагностики: https://www.aqua-mail.com/ru/troubleshooting/

Вопросы и ответы: https://www.aqua-mail.com/ru/faq/

pineappleCake

  • Newbie
  • *
  • Posts: 4
Re: Swipeable ListView tips
« Reply #2 on: June 10, 2015, 04:52:06 am »
You are truly awesome. Thanks for sharing your nuggets of information.

I really appreciate the clean apps you make. You seem to do it as a living as a one-man shop. I admire that. You should really write a book about it (or just share some of your secrets to success on the forum  ;) )
« Last Edit: June 10, 2015, 04:56:34 am by pineappleCake »