I recently had to implement swipe to dismiss (or delete). The items should get dismissed immediately without a delete button. For Android I used a
MvxRecyclerView and on iOS the good old
UITableView. The example code is available on github.
The impulse for writing this blog post was a tweet by @waniste, who thought it is uncomfortable to implement it with a
MvxRecyclerView. I had to convince him of the opposite, because MvvmCross is awesome and not uncomfortable :P
Seems like implementing "SwipeToDismiss" functionality for MvxRecyclerView isn't very comfortable. Will dig into it another day. #MvvmCross— Stefan (@waniste) 22. Mai 2016
The ViewModel for our view creates the
MyItemViewModels and passes a
deleteCommand that calls
deleteCommand is a command that takes a
MyItemViewModel as parameter. This is the item that should get deleted when the command gets executed.
InvokeOnMainThread is needed, because of iOS.
MyItemViewModel is simple, too. It contains only a Text property, and a
Delete() method, that should be called when the swipe gesture has been executed.
Given you have setup a MvxRecyclerView, then it’s pretty easy to implement it. All you need is to inherit a class from
ItemTouchHelper.SimpleCallback and call the
Delete method of your ItemViewModel.
In the constructor we call the base constructor with the allowed directions (
ItemTouchHelper.Left | ItemTouchHelper.Right). In this example you can move the items left and right and you are not allowed to drag it. For the same reason, we simply return
OnSwiped, the callback that is called, when the swipe gesture has been recognized, we have to call
Delete() on the currently swiped item. The
MvxRecyclerView is implementing the ViewHolder pattern. This means the
DataContext of the holder is our ViewModel.
Finally, we have to attach it to our recycler view via an
iOS has a built in swipe to dismiss mechanism (
UITableView.CommitEditingStyle(...)). Unfortunately it shows a delete button when swiped, that has to be pressed to actually delete the item. But we want to delete the item immediately. We have to implement our own
UIPanGestureRecognizer for it.
Somewhere in our
UITableViewCell, we attach it to our cell.
Then we need to implement
SwipeHandler that gets called for each swipe interaction of the recognizer.
- When the swipe begins (
UIGestureRecognizerState.Began) we save the original center of our cell.
- When its in between the gesture (
UIGestureRecognizerState.Changed), we update the center of our cell. We translate it.
- When the gesture finishes, we have two options:
- if the cell has not moved more than a defined way, we animate it back
- if the cell has moved more than the defined way, we animate it away and call
ViewModel is the casted
DataContext of the cell.
And for some practice, I want to allow only swipes to the left on iOS. Therefore we need to override
ShouldBegin where we check if the initial translation goes left and it goes more horizontal then vertical (else it might be the scroll swipe of the table).
Found a typo? Send me a pull request!