Android UI Tutorial #1 | Move A View On UI By Dragging It With Your Finger
What Will I Learn?
- teach you how to create a sliding layout move out of UI when you swipe it upward, and the layout behind it will come out of darkness.
- Android Studio
- Java Programming Experience.
- Android Device/Virtual Device.
- willingness to learn
Welcome. In this tutorial I will teach you how to create a sliding layout, so it would move out of UI when you swipe it upward, and the layout behind it will come out of darkness.
All we'll cover here will be creating the GIF you see, but once you learn how, you will be able to create some neat and awesome stuff with the knowledge.
Before we code
Start a new project, head to 'res/values/styles'
change <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar"> to <style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar"> so the Toolbar would hide. change <item name="colorPrimaryDark">@color/colorPrimaryDark</item> to <item name="colorPrimaryDark">#E91E63</item> to change the color of the status bar.
We'll start by creating the layout, then move to java.
- Creating the layout
- Creating the layout
Our layout has 4 main Views inside it, which are divided into two groups.
The first group includes a RelativeLayout, which holds all the views behind our draggableLayout. Inside it there is a GIF and a Button.
The second group includes an ImageView, a LinearLayout, and a View. The LinearLayout named linDraggable is the layout that will be dragged. The View named viewTouchListener is a transparent but clickable View, that is
responsible for registering the user's clicks. The ImageView named imgDarkOverlay with a semi-transparent black background, is the darkness behind the linDraggable!
- Writing the Java code
Before we start with writing our java code I should explain that for the sake of keeping our code clean, we create multiple methods in our MainActivity class, each responsible for something, and we call them from the onCreate() method. For example we initialize our UI components like this:
Then we add these variables just above the onCreate() method:
Now we create another method in our class named getHeight and call it from onCreate() method:
In this method we wait for the linDraggable to get drawn on the UI so we can get it's height value and store it in linHeight.
After we get the height, we start listening for touches on the UI through listenForDrag() method:
In this method, we listen for the touches being registered on viewTouchListener, and as you can see, they are divided to three parts.
case MotionEvent.ACTION_DOWN: which runs when the user puts finger on the viewTouchListener. All we do here is getting the start position of the touch. case MotionEvent.ACTION_MOVE: which runs when user drags finger on the view. In here we call performCalculations() and pass the touch event through it which calculates how much the finger has been dragged on the view, and where our linDraggable should be. case MotionEvent.ACTION_UP: which runs when the user lifts finger off the view. In here we call checkWhatShouldHappen() (don't judge me, naming is hard) which decides how the elements on the UI should lay out, based on the amount of drag on the screen
Doing the magic
The performCalculations() method is where the magic happens:
This method executes whenever user swipes on the screen. even if the swipe amount is as small as 1 pixel.
First we calculate the difference between start touch position (startY and X) and the amount of touch movement, and store them inside deltaX and deltaY.
Then we calculate "From zero to one, how much the layout has been moved" and "From one to zero, how much the layout has been moved" and store them inside factorFromZero and factorFromOne. In this project we wont use factorFromZero, but it can be very useful inside the projects you may build upon this. (Note that the values for both variables may exceed 1 and deceed 0)
Now that we have enough data, we move(translate) our linDraggable.
As we want our linDraggable to go upwards, we check if deltaY is bigger or equal to 0.
Now to move the linDraggable, all we have to do is: linDraggable.setTranslationY(-deltaY); but as you have noticed, instead of -deltaY, i have put -(int) (deltaY * ((float) 4 / 5)). This decreases the value of deltaY a little, and gives a feeling of linDraggable being a little heavy when user drags it up. It is optional and you may not want to use it in your own projects based on the view you want to move.
Then we decrease the alpha value of imgDarkOverlay, so the views in the back would brighten as we drag linDraggable up. For this all we need to do is imgDarkOverlay.setAlpha(factorFromOne);. That's it!
Laying out components in proper location
Now we should see where the user lifts up finger, and decide what should happen to linDraggable, imgDarkOverlay and viewTouchListener. And by that I mean:
IF, the user has dragged a total of one third of linDraggable's height, then after user lifts finger, linDraggable should go all the way up until its out of the view, imgDarkOverlay should completely fade out, and viewTouchListener's visibility should be set to View.GONE so it wouldn't consume any other touches registered on the UI, and any view behind it would be interactive.
ELSE, linDraggable should come back to it's original location, imgDarkOverlay should get it's original alpha of 1. and nothing would happen to viewTouchListener.
We use ViewAnimator to animate any changes we want to make, and apply them in checkWhatShouldHappen() method:
In the code above, if user has dragged the linDraggable enough:
we will set linDraggable's translationY to -linHeight which is the necessary amount it has to go to completely move out of screen. we execute imgDarkAnimation with .withEndAction() so we know when the animation has finished, so we can runFinishingCode():
I have optionally added a button to my layout that would reveal the linDraggable again, which resides in a method named onClicks(), and is called in onCreate():
Thats it !