Android Side Slide Menu QQ5.0 Custom Control

Posted by SaMike on Fri, 14 Jun 2019 02:19:58 +0200

 

Android High Imitation Q QQ5.0 Side Slide Menu Effect Custom Control Invasion


This article is from [Zhang Hongyang's blog]

In the last blog, we realized that: Android Custom Controls Create the Simplest Side-Slide Menu in History Some brothers said after reading it, your sliding menu is out of date. ~QQ5.0's effect is not bad. ~Well, indeed, the last one also promised to slightly modify the code of the previous one to realize the QQ5.0 sliding menu. ~ Well, here we begin to show you how easy it is to write a sliding menu like QQ.

1. Principle analysis

Firstly, how far is the implementation of QQ from the next one?

The gap is still considerable.

Distinguish 1. The content area of QQ will be reduced with the appearance of menus.

The difference between QQ and QQ is that the sideslip menu gives the impression that it is hidden behind the content, not dragged out.

Distinguish 3. QQ's sideslip menu has a zoom and transparency effect~


So how can we do that?

For the difference 1: This is easy to do, we can constantly change the size of the content area while sliding; how to change it? During the whole process of menu appearing, it is a process from 0 to 1 to record the ratio of the width displayed by the menu to its total width, and then transform 0 to 1 to 0.7 (assuming that the content area is reduced to 0.7), and constantly reduce the content area.

For the difference 3: It's easier to do, the above can already get the value of 0 to 1, then zoom and transparency of the animation is not the case;

For Distinction 2: We use Horizontal ScrollView and then place menus and content horizontally. How can we hide menus behind content? In fact, it is also relatively simple. In the process of menu appearing, the offset of x direction of menu is set constantly; when 0 is completely hidden, when 0.3 is hidden, the offset of x direction is 0.7 width, and so on.~~~


Well, after the analysis, what is the best way to achieve these animations?

Don't even think about it. Attribute animation. If you don't know about attribute animation, you can refer to: Android Property Animation Complete Resolution (Part I) and Android Property Animation Complete Resolution (Part 2)

2. Realization


1. Preliminary code

The layout files are exactly the same as the last one. There will be no repetition of the code posting here. If you don't understand it, read the last one first.

Let's first look at the complete code we implemented in the previous article:

  1. package com.example.zhy_slidingmenu;  
  2.   
  3. import android.content.Context;  
  4. import android.content.res.TypedArray;  
  5. import android.util.AttributeSet;  
  6. import android.util.TypedValue;  
  7. import android.view.MotionEvent;  
  8. import android.view.ViewGroup;  
  9. import android.widget.HorizontalScrollView;  
  10. import android.widget.LinearLayout;  
  11.   
  12. import com.zhy.utils.ScreenUtils;  
  13.   
  14. public class SlidingMenu extends HorizontalScrollView  
  15. {  
  16.     /** 
  17.      * Screen width 
  18.      */  
  19.     private int mScreenWidth;  
  20.     /** 
  21.      * dp 
  22.      */  
  23.     private int mMenuRightPadding;  
  24.     /** 
  25.      * Width of menu 
  26.      */  
  27.     private int mMenuWidth;  
  28.     private int mHalfMenuWidth;  
  29.   
  30.     private boolean isOpen;  
  31.   
  32.     private boolean once;  
  33.   
  34.     public SlidingMenu(Context context, AttributeSet attrs)  
  35.     {  
  36.         this(context, attrs, 0);  
  37.   
  38.     }  
  39.   
  40.     public SlidingMenu(Context context, AttributeSet attrs, int defStyle)  
  41.     {  
  42.         super(context, attrs, defStyle);  
  43.         mScreenWidth = ScreenUtils.getScreenWidth(context);  
  44.   
  45.         TypedArray a = context.getTheme().obtainStyledAttributes(attrs,  
  46.                 R.styleable.SlidingMenu, defStyle, 0);  
  47.         int n = a.getIndexCount();  
  48.         for (int i = 0; i < n; i++)  
  49.         {  
  50.             int attr = a.getIndex(i);  
  51.             switch (attr)  
  52.             {  
  53.             case R.styleable.SlidingMenu_rightPadding:  
  54.                 //Default 50  
  55.                 mMenuRightPadding = a.getDimensionPixelSize(attr,  
  56.                         (int) TypedValue.applyDimension(  
  57.                                 TypedValue.COMPLEX_UNIT_DIP, 50f,  
  58.                                 getResources().getDisplayMetrics()));//Default is 10DP  
  59.                 break;  
  60.             }  
  61.         }  
  62.         a.recycle();  
  63.     }  
  64.   
  65.     public SlidingMenu(Context context)  
  66.     {  
  67.         this(context, null0);  
  68.     }  
  69.   
  70.     @Override  
  71.     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)  
  72.     {  
  73.         /** 
  74.          * Set a width for display 
  75.          */  
  76.         if (!once)  
  77.         {  
  78.             LinearLayout wrapper = (LinearLayout) getChildAt(0);  
  79.             ViewGroup menu = (ViewGroup) wrapper.getChildAt(0);  
  80.             ViewGroup content = (ViewGroup) wrapper.getChildAt(1);  
  81.   
  82.             mMenuWidth = mScreenWidth - mMenuRightPadding;  
  83.             mHalfMenuWidth = mMenuWidth / 2;  
  84.             menu.getLayoutParams().width = mMenuWidth;  
  85.             content.getLayoutParams().width = mScreenWidth;  
  86.   
  87.         }  
  88.         super.onMeasure(widthMeasureSpec, heightMeasureSpec);  
  89.   
  90.     }  
  91.   
  92.     @Override  
  93.     protected void onLayout(boolean changed, int l, int t, int r, int b)  
  94.     {  
  95.         super.onLayout(changed, l, t, r, b);  
  96.         if (changed)  
  97.         {  
  98.             //Hide menus  
  99.             this.scrollTo(mMenuWidth, 0);  
  100.             once = true;  
  101.         }  
  102.     }  
  103.   
  104.     @Override  
  105.     public boolean onTouchEvent(MotionEvent ev)  
  106.     {  
  107.         int action = ev.getAction();  
  108.         switch (action)  
  109.         {  
  110.         //Up, if the display area is larger than half the width of the menu, it will be fully displayed, otherwise it will be hidden  
  111.         case MotionEvent.ACTION_UP:  
  112.             int scrollX = getScrollX();  
  113.             if (scrollX > mHalfMenuWidth)  
  114.             {  
  115.                 this.smoothScrollTo(mMenuWidth, 0);  
  116.                 isOpen = false;  
  117.             } else  
  118.             {  
  119.                 this.smoothScrollTo(00);  
  120.                 isOpen = true;  
  121.             }  
  122.             return true;  
  123.         }  
  124.         return super.onTouchEvent(ev);  
  125.     }  
  126.   
  127.     /** 
  128.      * open a menu 
  129.      */  
  130.     public void openMenu()  
  131.     {  
  132.         if (isOpen)  
  133.             return;  
  134.         this.smoothScrollTo(00);  
  135.         isOpen = true;  
  136.     }  
  137.   
  138.     /** 
  139.      * Close the menu 
  140.      */  
  141.     public void closeMenu()  
  142.     {  
  143.         if (isOpen)  
  144.         {  
  145.             this.smoothScrollTo(mMenuWidth, 0);  
  146.             isOpen = false;  
  147.         }  
  148.     }  
  149.   
  150.     /** 
  151.      * Switch menu status 
  152.      */  
  153.     public void toggle()  
  154.     {  
  155.         if (isOpen)  
  156.         {  
  157.             closeMenu();  
  158.         } else  
  159.         {  
  160.             openMenu();  
  161.         }  
  162.     }  
  163.       
  164.       
  165.   
  166. }  

Horizontal ScrollView is used to monitor the ACTION_UP event. When the user raises his finger, he judges whether the menu is retracted or fully unfolded according to the width value displayed in the current menu; provides a right Padding attribute for the user to set the distance between the menu and the right screen; and provides several methods to open, close and switch out; and gives a detailed explanation of the next blog;

2. Ideas for Realization

Now we begin to solve those three differences. We have chosen to use attribute animation. Now we decide where the animation effect should be added.

Needless to say, I use my thighs to think that it should be in ACTION_MOVE. Yes, ACTION_MOVE can get the current getScrollX/mMenuWidth, constantly change the transparency of menus, zoom, X-direction offset, and constantly change the width and height of content area.

Say, I did it in MOVE at first, but there are two problems:

1. The animation effect is not very smooth, especially the menu, which has the effect of shaking.

2. After the user lifts it, it is necessary to continue the unfinished animation in UP. That is to say, your transparency and zooming Magic Horse need to change automatically after the user lifts it.

So, I started to change direction. Since it's SrollView, there must be a ScrollChanged method. It's really a good way to do it.

  1. @Override  
  2.     protected void onScrollChanged(int l, int t, int oldl, int oldt)  
  3.     {  
  4.           
  5.     }  
This method will trigger as long as scrollChanged, l is the scrollX we need. That's great.~~~

3. Calculation of Animation Proportion

In onScrollChanged, we get l, which is getScrollX, the width value that the menu has displayed.

  1. float scale = l * 1.0f / mMenuWidth;  

By dividing with the width of the menu and hiding it in the menu to show the whole process, we can get a range of 1.0 to 0.0.

With this interval, you can set the animation according to this interval.

1. First, the scaling ratio of the content area is calculated.

We're going to let the content area change from 1.0 to 0.8 as the menu appears.~~

So how to convert 1.0-0.0 into 1.0-0.8 is very simple.

float rightScale = 0.8f + scale * 0.2f; (scale from 1 to 0), is that oh yeah?

Then there are three animations:

2. Calculating the Scaling Proportion of Menu

Looking closely at the next QQ, the menu scaling change is about 0.7-1.0.

float leftScale = 1 - 0.3f * scale;

3. The transparency ratio of menus:

We set it to 0.6 - 1.0; that is, 0.6f + 0.4f* (1 - scale)

4. The x-direction offset of the menu:

Look at QQ, not completely covered by the content area, or a little dragged out, so we set the offset as follows:

tranlateX = mMenuWidth * scale * 0.6f; let it hide a little at first~~~

4. Complete Implementation

Having said so much, it only takes a few lines of code to move from the simplest Sideslip in history to the effect of QQ5.0.~~

  1. @Override  
  2.     protected void onScrollChanged(int l, int t, int oldl, int oldt)  
  3.     {  
  4.         super.onScrollChanged(l, t, oldl, oldt);  
  5.         float scale = l * 1.0f / mMenuWidth;  
  6.         float leftScale = 1 - 0.3f * scale;  
  7.         float rightScale = 0.8f + scale * 0.2f;  
  8.           
  9.         ViewHelper.setScaleX(mMenu, leftScale);  
  10.         ViewHelper.setScaleY(mMenu, leftScale);  
  11.         ViewHelper.setAlpha(mMenu, 0.6f + 0.4f * (1 - scale));  
  12.         ViewHelper.setTranslationX(mMenu, mMenuWidth * scale * 0.6f);  
  13.   
  14.         ViewHelper.setPivotX(mContent, 0);  
  15.         ViewHelper.setPivotY(mContent, mContent.getHeight() / 2);  
  16.         ViewHelper.setScaleX(mContent, rightScale);  
  17.         ViewHelper.setScaleY(mContent, rightScale);  
  18.   
  19.     }  

That's just a few lines. Nineold and ROIDS are used for attribute animation to maintain downward compatibility; the main thing is to set up various animations, which are described in detail above.~~~
Then, remember to declare the layout of our menu and content separately as our mMenu, mContent ~is gone, and change a few lines.~

3. Effect Map

A mule is a horse, pull it out and run away


The drag of ListView on the menu bar is not conflicting, as we have seen in the previous section. test ;

About the scope of animation attributes: the above description is particularly clear, such as content we are the smallest display 0.8, if you like 0.6, to modify it yourself; including offset, transparency and other areas;

Because the last article has written how to extract attributes into custom attributes; so there is no extraction here, otherwise it always feels like repetition.~


Well, recently there has been a sideslip for writing APP. It's like this: the menu bar is completely hidden under the content area, if you need to:


In fact, I like the effect.

Implemented by annotating a few lines of code:

  1. @Override  
  2.     protected void onScrollChanged(int l, int t, int oldl, int oldt)  
  3.     {  
  4.         super.onScrollChanged(l, t, oldl, oldt);  
  5.         float scale = l * 1.0f / mMenuWidth;  
  6. //      float leftScale = 1 - 0.3f * scale;  
  7. //      float rightScale = 0.8f + scale * 0.2f;  
  8. //        
  9. //      ViewHelper.setScaleX(mMenu, leftScale);  
  10. //      ViewHelper.setScaleY(mMenu, leftScale);  
  11. //      ViewHelper.setAlpha(mMenu, 0.6f + 0.4f * (1 - scale));  
  12.         ViewHelper.setTranslationX(mMenu, mMenuWidth * scale );  
  13.   
  14. //      ViewHelper.setPivotX(mContent, 0);  
  15. //      ViewHelper.setPivotY(mContent, mContent.getHeight() / 2);  
  16. //      ViewHelper.setScaleX(mContent, rightScale);  
  17. //      ViewHelper.setScaleY(mContent, rightScale);  
  18.   
  19.     }  


Okay, although the final implementation looks very simple, it looks like, uh ~, but the process from scratch is not easy ~ ~various attempts, I can say that I even squat pit in QQ menu observation ~ha, laughed; blog also wrote out the failed attempts in the process, hoping to better let you learn some useful things in it ~ ~YEAH!! Let's leave a message. No more. I'll get a source code. Please leave your mailbox. Hey, hey, kidding.~


Topics: Android Attribute