Android Custom ViewGroup Create various styles of slidingmenu_android

Source: Internet
Author: User
Tags abs gety

On the article to introduce QQ5.0 sideslip menu video course, for sideslip animation effect of the realization of a new understanding, seems to get through the two veins, now can achieve any effect of the Sideslip menu, thank you big!!

With the Horizontalscrollview to achieve the Sideslip menu function, Horizontalscrollview benefits are for us to solve the sliding function, dealing with the sliding conflict problem, let us use it very convenient, But sliding and conflict processing are the difficulties of Android, we should grasp the knowledge point, mastered these, we can not rely on the system's API, do whatever we want to create the effect, so this article I will directly customize the ViewGroup to achieve the Sideslip menu function

First we take a look at the effect of the picture, the first effect picture is a most common side of the Sideslip menu, we will first make this slip menu, and then on this basis to achieve the other two effects

First Kind

Second Kind

Third Kind

Implementation of the first Sideslip menu, inherited from ViewGroup

Inherit from ViewGroup need us to measure, layout, realize the effect of sliding, deal with sliding conflict, these are some novice can not know the point of knowledge, I hope to read this article will have a help for everyone

The general idea of custom ViewGroup is to rewrite the Onmeasure method, call Measurechild in the Onmeasure method to measure the child view, and then call Setmeasureddimension to measure its size. Then rewrite the OnLayout method, call the layout method of the child view in OnLayout to determine the position of the child view, and let's do the two things first.

Initially our content should be displayed on the screen, and menu should be displayed outside the screen. When the menu is open, it should look like this


The

Mmenurightpadding is a distance from the menu to the right of the screen, because when we open the menu, the content still leaves a part, not completely hidden

public class Myslidingmenu extends ViewGroup {public Myslidingmenu (context, NULL, 0); Yslidingmenu (context, AttributeSet attrs) {This (context, attrs, 0);} public Myslidingmenu (context, Attri
Buteset attrs, int defstyleattr) {Super (context, attrs, defstyleattr);
Displaymetrics metrics = new Displaymetrics ();
WindowManager wm = (WindowManager) context.getsystemservice (Context.window_service);
Wm.getdefaultdisplay (). Getmetrics (metrics);
Get the width and height of the screen mscreenwidth = Metrics.widthpixels; 
Mscreenheight = Metrics.heightpixels; 
Set menu distance to the right of the screen, CONVERTTODP converts 100 in the code to 100DP mmenurightpadding = CONVERTTODP (context,100); @Override protected void onmeasure (int widthmeasurespec, int heightmeasurespec) {//Get Menu,menu is No. 0 child Mmenu = (viewgroup
) Getchildat (0);
Get Content,content is 1th child mcontent = (viewgroup) getchildat (1);
Set the width of the menu to the width of the screen minus the distance from the menu to the right of the screen mmenuwidth = Mmenu.getlayoutparams (). width = mscreenwidth-mmenurightpadding; Sets the width of the content toThe width of the screen mcontentwidth = Mcontent.getlayoutparams (). width = mscreenwidth;
Measuring menu Measurechild (MMENU,WIDTHMEASURESPEC,HEIGHTMEASURESPEC);
Measurement content Measurechild (mcontent, Widthmeasurespec, Heightmeasurespec);
Measure yourself, the width of the menu plus the content width, height for screen height setmeasureddimension (mmenuwidth + mcontentwidth, mscreenheight); @Override protected void OnLayout (Boolean changed, int l, int t, int r, int b) {//Position menu, according to the above figure can determine the coordinates of the top and bottom Mmenu.layo
UT (-mmenuwidth, 0, 0, mscreenheight);
Placement of content mcontent.layout (0, 0, mscreenwidth, mscreenheight); /** * Converts incoming numbers into DP/private int CONVERTTODP (context, int num) {return (int) typedvalue.applydimension Typedva Lue.
Complex_unit_dip,num,context.getresources (). Getdisplaymetrics ()); }
}

Currently, the position of the two sub view in our Sideslip menu should look like this


The left menu is hidden on the left side of the screen, but it can't be slid now, and if you want to implement the sliding function, we can use the Scrollto and Scrollby methods of the view, the difference being that Scrollto is directly moving the view to the specified location. Scrollby is moving an offset relative to the current position, so we should rewrite the Ontouchevent method to compute an offset of the current finger and then use the Scrollby method to move 1.1 points, The animation effect of a view that can follow the finger movement is formed

Before we write the code, let's clear the barriers and we'll figure out what these coordinates are.




Well, after we figure out these coordinates, we'll be much simpler, and look directly at the Ontouchevent method.

 @Override public boolean ontouchevent (Motionevent event) {int action = Event.getaction (
); Switch (action) {Case MotionEvent.ACTION_DOWN:mLastX = (int) event.getx (); mlasty = (int) event.gety ();
NEvent.ACTION_MOVE:int currentx = (int) event.getx ();
int currenty = (int) event.gety ();
Gets the offset int dx = CURRENTX-MLASTX in the x direction; if (DX < 0) {//left sliding//border control, if the menu is fully displayed and then slides, the white edge will appear on the left side of the//menu, and the boundary control if (GETSCROLLX () + math.abs (dx) >= 0) {//moved directly to (
0,0) position, does not appear white edge scrollto (0, 0); else {//menu not fully displayed//In fact, here DX or-DX, we do not have to remember//everyone can first use DX, and then run, find//move direction is the opposite, then decisive here add a minus sign can be Scrollby (-DX, 0);} else{//to the right sliding//border control, if the content has been fully displayed, and then slide the//content on the right side will appear white edge, the boundary control if (GETSCROLLX ()-DX <=-mmenuwidth) {//
Move directly to (-mmenuwidth,0) position, do not appear white edge Scrollto (-mmenuwidth, 0);
else {//content not fully displayed//Scrollby (-DX, 0) by finger movement;}
MLASTX = CurrentX;
Mlasty = CurrentY;
Break
return true; }

Now our slidingmenu is still not able to slide horizontally, but ListView can slide vertically because our slidingmenu does not intercept the event by default, and the event is passed to his child view for execution, That is, the ListView that is passed to the content is executed, so the ListView can be slid, in order to be simple, we rewrite the Onintercepttouchevent method first, we return true, let Slidingmenu intercept the event, Our slidingmenu will be able to slide, but the ListView is not able to slide, and so we will do the sliding conflict processing, now first realize the function of Slidingmenu

@Override Public
Boolean onintercepttouchevent (motionevent ev) {return
true;
}

OK, now that we are free to slide our slidingmenu and have a good border control, now we add a feature that when the menu opens more than One-second, loosen the finger and the menu opens automatically. When the menu opens less than One-second, loosen the finger and the menu closes automatically. The function of automatic sliding we have to use scroller to realize

We initialize a scroller in the constructor method

Public Myslidingmenu (context, AttributeSet attrs, int defstyleattr) {
Super (context, attrs, defstyleattr);
c6/> ... Mscroller = new Scroller (context);
...
}

And then rewrite the Computescroll method, which is the necessary way to ensure that the scroller automatically slides, which is a template method, which is just fine.

@Override public
void Computescroll () {
if (Mscroller.computescrolloffset ()) {
Scrollto ( Mscroller.getcurrx (), Mscroller.getcurry ());
Invalidate ();
}

We then judge in the Ontouchevent action_up to determine how much of the current menu is open.

Case MOTIONEVENT.ACTION_UP:
if (GETSCROLLX () <-MMENUWIDTH/2) {//Open menu
//Call Startscroll method, first parameter is start x coordinate, The second argument
//is the starting Y coordinate, the third parameter is the X direction offset, and the fourth parameter is the Y-direction offset
Mscroller.startscroll (GETSCROLLX (), 0,-mmenuwidth-getscrollx (), 0,);
Set an already opened identity, when the implementation of the click Switch automatically turn off function will be used to
IsOpen = true;
Be sure not to forget to call this method redraw, otherwise there is no animation effect
invalidate ();
} else{//closes menu
//ditto
Mscroller.startscroll (GETSCROLLX (), 0,-getscrollx (), 0,);
IsOpen = false;
Invalidate ();
}
Break

As for the StartX and Starty in Startscroll, how do dx and dy calculate? Actually very simple, for example, we startx coordinates 30, we want to move to-100, then startx+dx = -100–> dx = -100-startx–> DX =-130

Okay, now we're going to be able to animate the slide automatically after we release our fingers.
Now we also need to click on a triangle in the upper-left corner of content, if the current menu is not open, then automatically open, if it is turned on, automatically turn off the function, the effect of automatic sliding we have to use the Scroller.startscroll method

/**
* Click on the switch, open and close menu, if the current menu has been turned off, if the current menu has been turned off, turn on
/public void Togglemenu () {if
(isOpen) {
Closemenu ();
} else{
Openmenu ();
}
/**
* Close menu
/private void Closemenu () {
//also use the Startscroll method, dx and dy calculation method
Mscroller.startscroll (Getscrollx (), 0,-getscrollx (), 0,500);
Invalidate ();
IsOpen = false;
}
/**
* Open Menu */
private void Openmenu () {
mscroller.startscroll (GETSCROLLX (), 0,- MMENUWIDTH-GETSCROLLX (), 0,500);
Invalidate ();
IsOpen = true;
}

Then we can get our content in the upper left corner of the mainactivity Triangle ImageView, and then give him a click event, call our Togglemenu method

Mmenutoggle.setonclicklistener (New View.onclicklistener () {
@Override public
void OnClick (View v) {
Mslidingmenu.togglemenu ();
}
);

Handling Sliding conflicts

Since our menu and content are listview,listview to support vertical sliding, and our slidingmenu support horizontal sliding, there will be sliding conflicts. Just now we have returned true directly in Onintercepttouchevent, so Slidingmenu will intercept all events, and ListView can't receive any events, so ListView can't slide, so we have to solve this sliding conflict is very simple, Only need to determine whether the current horizontal slide or vertical slide, if it is horizontal sliding then let Slidingmenu intercept the event, if it is vertical sliding, do not intercept the event, the incident to the ListView to implement

@Override Public
Boolean onintercepttouchevent (motionevent ev) {
Boolean intercept = false;
int x = (int) ev.getx ();
int y = (int) ev.gety ();
Switch (ev.getaction ()) {case
motionevent.action_down:
intercept = false;
break;
Case motionevent.action_move:
int deltax = (int) ev.getx ()-mlastxintercept;
int deltay = (int) ev.gety ()-mlastyintercept;
if (Math.Abs (deltax) > Math.Abs (DeltaY)) {//horizontal slide
intercept = true;
} else{//longitudinal slide
intercept = false;
}
break;
Case MOTIONEVENT.ACTION_UP:
intercept = false;
break;
MLASTX = x;
Mlasty = y;
mlastxintercept = x;
mlastyintercept = y;
return intercept;
}

OK, now our sliding conflict is resolved, we can both horizontal sliding slidingmenu, and can be vertical sliding listview, then the first slidingmenu has been achieved, we have to see how the other two to achieve

Realize the second kind of QQ V6.2.3 style Slidingmenu


This slidingmenu is the same as the QQ v6.2.3 sideslip menu style, we found that the sliding speed of menu and content is a poor speed, in fact, we can modify the menu offset to achieve this effect


At this point the menu offset is mmenuwidth 2/3, when we slowly open the menu, modify the menu offset, and finally modified to 0

This achieves a kind of speed difference effect, we only need to add a line to the Ontouchevent Action_move and computescroll the following code can

Mmenu.settranslationx (2* (MMENUWIDTH+GETSCROLLX ())/3);

We analyze, at the very beginning, mmenuwidth+getscrollx=mmenuwidth, multiplied by 2/3, gets the Mmenuwidth 2/3, and when we slide to the menu completely open, mmenuwidth+getscrollx= 0, that's what we're doing.

Why add this line of code to the Computescroll, because when we're slipping, if our fingers leave the screen, Action_move definitely won't do it, but when our fingers leave the screen, there's an animation that turns on or off automatically, So the animation should continue to set the menu offset, so we'll add this line of code to the Computescroll.

Well, the effect we have achieved, just to set the menu offset can be, is not very simple

Realize the third kind of QQ V5.0 style Slidingmenu


In this effect, the menu has an offset effect, a change in transparency, and a magnification effect. There is a narrowing effect in the content.
First we need to have a variable that records how many percentages the current menu has opened.



Here we have to note that the getscrollx gets exactly the negative value, so we calculate the value of the GETSCROLLX, and then we compute the value in the ontouchevent move. This value is also computed in the Computescroll method, because when we raise our fingers, we may perform an animation that is automatically turned on or off, so our calculations in move must stop, but in the process of animation, it is scroller that works, Then the Computescroll will execute until the animation is finished, so we're going to do the same in the Computescroll.

Scale = Math.Abs ((float) getscrollx ())/(float) mmenuwidth;

The value of scale is [0,1], so we can set the offset of the menu according to this value.
We can zoom in on the view by setting the view Setscalex and Setscaley, of course, this scaling is based on our scale value to change, first of all, our menu has a magnifying effect, We specify that the menu should be enlarged from 0.7 to 1.0 so that we can write

Mmenu.setscalex (0.7f + 0.3f*scale);
Mmenu.setscaley (0.7f + 0.3f*scale);

The transparency is from 0 to 1, so we'll just use the scale value.

Mmenu.setalpha (scale);

I also set an offset to the menu that you can calculate for yourself.

Mmenu.settranslationx (Mmenuwidth + GETSCROLLX ()-(MMENUWIDTH/2) * (1.0f-scale));

After the menu is set, we'll set the size of the content,content from 1.0 to 0.7, so we write

Mcontent.setscalex (1-0.3f*scale);
Mcontent.setpivotx (0);
Mcontent.setscaley (1.0f-0.3f * scale);

where Mcontent.setpivotx (0) is the Zoom Center store for content with an x-axis coordinate of 0 points

We can extract the process of this change into a method

private void SlidingMode3 () {
Mmenu.settranslationx (mmenuwidth + GETSCROLLX ()-(MMENUWIDTH/2) * (1.0f-scale));
Mmenu.setscalex (0.7f + 0.3f*scale);
Mmenu.setscaley (0.7f + 0.3f*scale);
Mmenu.setalpha (scale);

Mcontent.setscalex (1-0.3f*scale);
Mcontent.setpivotx (0);
Mcontent.setscaley (1.0f-0.3f * scale);
}

Adding this method to Ontouchevent's Action_move and Computescroll is OK.

We see that all of the sliding styles are based on the first, modifying the Translationx or ScaleX ScaleY values of the menu or content, so we can create all kinds of slidingmenu.

The above is a small set to introduce the Android custom ViewGroup to create a variety of styles of slidingmenu knowledge, hope to help you!

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.