Android Wallet Cards Manager

Creating a sliding card wallet layout for Android (updated)

Elia Spiga
6 min readSep 20, 2021
Photo by David Clode on Unsplash

by Elia Spiga and Giampietro Fronteddu, Android Developers at OverApp.

Introduction

Recently in OverApp I found myself in the situation of developing a view, a kind of main menu consisting of draggable tabs like a wallet with particular states and animations. Since I had no experience with this type of layout it was a new challenge for me.

This example project is the result I obtained.

Composition of the layout

To implement the layout you has seen I have provided three cards called Back, Middle and Front as in the following figure:

Home screen layout code

For the Middle and Front fragments I have used a FrameLayout because it’s one of the most simple layouts to work with to obtain translations and animations.

Project organization

Every card is identified by a fragment. The logic for the behaviour of the views is managed in the WalletCardsManager library, that contains:

  • CardsManager : an object that contain all the parameters for the position of the cards.
  • Controllers : a package that contain the controllers of the Middle and Front cards. Every controller contains the logic to listen the drag events.
  • A file for the constants to use in some points of the project.

Initial configuration

An initial layout configuration is defined, most of this work is made in the CardsManager’s init.

Link to the fragments

The functioning of the communication system between CardsManager and fragments can be divided in two phases:

  • 1) The fragments inform the CardsManager about their status and about the actions they have performed by calling the functions of the object.
  • 2) The CardsManager sends the orders to the fragments with the actions to be performed based on the information that has arrived previously.

Dimensions retrievement

In order to work with the layout we need to know its characteristics like heights, positions, and borders of all graphical components used in it, like in this example:

These functions must be called once the view of the fragment or activity in which the component resides has been created. This is the example with the Front card:

It is important to obtain the values of the view inside the post block which ensures that everything defined inside it is called only when the layout has been drawn on the screen so its properties are not null and can be read.

At the end of each assignment in the variables, the initialSetup() function is called. This ensures that all views are populated before performing the calculations.

Although it may be inefficient to call the initialSetup() function every time a value is obtained from a layout object, this system completely avoids the synchronization problems between displaying all elements of the layout and reading their parameters. Plus it doesn’t even require reading to be done in a specific order across layouts.

The results of the initialSetup() function are then passed to the MainActivity to be applied to the fragments.

Careful! There are different layoutParams for each type of Android SDK layout. In our case the layoutParams refer to those of the FrameLayout.

Scrolling and animations (updated)

These tasks are carried out by the controllers present in the library. In this example the FrontController manage the events and the dragging of the Front card.

The VelocityTracker object is what allows us to derive data on the speed of dragging on the screen.

The onTouchListener interface allows us to listen to pressure events on the screen. The management of the MotionEvent that indicates the type of event that is taking place is divided into four blocks:

  • ACTION_DOWN : is the event that identifies the initial pressure on the view.
  • ACTION_MOVE : is performed while sliding a finger on the screen. In this block there are two fundamental conditions: one that verifies that scrolling always occurs within the vertical limits imposed on the view and one that manages the event in which the dragging of a card changes direction.
  • ACTION_UP : the code is executed when you release the pressure on the screen.
  • ACTION_CANCEL : manages the cancellation of the event by resetting the VelocityTracker.

To obtain a good functioning of the animation that brings the cards to their destination above a certain scrolling speed it is necessary to take into account not only the vertical speed but also the horizontal one. Let’s take for example a user who holds the phone with one hand, in these cases he will look for a scrolling as comfortable as possible, usually with his thumb, and for convenience he will tend to scroll also horizontally as well as vertically. Therefore it is also good to take into account the horizontal component during a sliding of this type. In this way the speed value obtained will be more precise because it will trace the natural scrolling performed on the screen and we could better calibrate the activation threshold of the animation, in our case set to 1800. To take into account the two components X and Y in the speed of scrolling we can use this formula:

https://en.wikipedia.org/wiki/Pythagorean_theorem

We can represent the vertical and horizontal sliding velocity components as the length of the legs of a right triangle and apply the Pythagorean Theorem to derive the length of the hypotenuse of our triangle. We will consider the length of the hypotenuse as the V velocity of the scroll containing both the velocity components in the X and Y axes.
It is then on this value that we will impose the condition for the choice of the animations to be performed (continue towards the destination for V> 1800 or return to the starting point for V ≤ 1800). The speed is independent of the direction so it must be unsigned.

Vertical translation occurs directly in the controller using the translationY reference of the view passed to the FrontController constructor.
These are the functions that perform the movements of the cards:

The translationY property is a FrameLayout parameter used to perform this type of animations. Other layout types may not have this property…

Advanced animations

In this layout there is an additional view to derive the measurements to be used when resizing the horizontal edges of the view.

The new margin sizes are applied directly in the MiddleFragment via the viewBinding.

The onCardsChangeOpenRatio(ratio: Float) function is the point where, given the ratio between the distance of the Front and Middle card headers, the size of the edges and the font of the displayed text are calculated.

The rateo is calculated in the CardsManager

The topMargin, horizontalMargin, and fontSize results are assigned to the layout and text parameters. This function is called whenever a scrolling of the Front or Middle cards is detected, giving the animated effect during the entire duration of the scrolling event.

Conclusions

I have not used the animation libraries already present in the Android SDK. I preferred to create a custom behaviour logic for the layout, listening to user input and running the animations directly by translating the view.

This project opens up the possibility of any kind of modification to the layout and its behaviour. In fact, playing on the basic logic of the CardController and on the commands given by the CardsManager, it is possible to define many animations for this or other views.

If you want to experiment with the animations in the layouts for Android you can take a cue from this project or use the libraries ready in the Android SDK that you find on this page. If, on the other hand, you are using the new UI development tools for Android I recommend the API for animations in Jetpack Compose.

by Elia Spiga and Giampietro Fronteddu, Android Developers at OverApp.

--

--