1. Overview
About custom control side-slip has written two ~ ~ Today decided to change the one-way to two-way, of course, the simple changes before the code is not interesting, today will not only change the one-way before, but also add a slide-slip effect, to bring a number of different forms of two-way side-by-side menu, but rest assured that The code will be simple ~ ~ Then according to these several kinds, as long as you like, I believe you can create any of the Bian (Tai) effect of the two-way slide menu ~ ~
First of all, the various slide-off menus that have been written before, in order not to occupy space, do not post pictures:
1, the most common side-slip effect, please refer to: Android custom control to create the history of the simplest slide-off menu
2, imitation QQ5.0 side-slip effect, please refer to: Android High imitation QQ5.0 slide menu effect custom control attack
3, the menu after the content of the side-slip effect, please refer to: Android High imitation QQ5.0 slide menu effect custom control attack
2. Target effect
1, the most common two-way slide
is not very vague, well, no way, computer graphics weak ....
2, two-way drawer slide
3, the menu under the content of the two-way slide
Make a look at the end of the article will provide the source code download, you can install the experience a bit ~
All the code content area is a ListView, both sides of the menu contains buttons, the basic conflict has been detected ~ ~ ~ Of course, if there is a bug unavoidable, please leave a message; If you solve some unknown bug, hope you can also leave a message, may help others ~ ~
Let's start with our code here.
3, the code is the best teacher 1, layout file
Since it is a two-way menu, our layout file is like this:
<com.zhy.view.binaryslidingmenu xmlns:android= "http://schemas.android.com/apk/res/android" xmlns:tools= "http ://schemas.android.com/tools "xmlns:zhy=" http://schemas.android.com/apk/res/com.zhy.zhy_bin_slidingmenu02 " Android:id= "@+id/id_menu" android:layout_width= "wrap_content" android:layout_height= "Fill_parent" android:scrollb Ars= "None" zhy:rightpadding= "100DP" > <linearlayout android:layout_width= "wrap_content" Android: layout_height= "fill_parent" android:orientation= "horizontal" > <include layout= "@layout/layout_menu"/ > <linearlayout android:layout_width= "fill_parent" android:layout_height= "Fill_parent" android:background= "@drawable/eee" android:gravity= "center" android:orientation= "Horizont Al "> <listview android:id=" @android: Id/list "android:layout_width=" Fill_pa Rent "Android:layout_height= "Fill_parent" > </ListView> </LinearLayout> <include layout= "@layout/layout_m Enu2 "/> </LinearLayout></com.zhy.view.BinarySlidingMenu>
The outermost layer is our custom binaryslidingmenu, inside a horizontal linearlayout, then the left menu, content area, menu layout on the right ~ ~
The key is our binaryslidingmenu.
2, the construction method of Binaryslidingmenu
/** * screen width */private int mscreenwidth;/** * DP menu distance to the right margin of the screen */private int mmenurightpadding;public binaryslidingmenu (Context Context, AttributeSet attrs, int defstyle) {Super (context, attrs, defstyle); mscreenwidth = Screenutils.getscreenwidth ( context); TypedArray a = Context.gettheme (). Obtainstyledattributes (Attrs,r.styleable.binaryslidingmenu, Defstyle, 0); int n = A.getindexcount (); for (int i = 0, i < n; i++) {int attr = A.getindex (i); switch (attr) {case R.styleable.binaryslidingmenu _rightpadding://Default 50mMenuRightPadding = A.getdimensionpixelsize (attr, (int) typedvalue.applydimension ( Typedvalue.complex_unit_dip, 50f,getresources (). Getdisplaymetrics ()));//default is 10DPbreak;}} A.recycle ();}
In the construction method, we get a custom attribute rightpadding, and assign it to our member variable mmenurightpadding; for the first post on how to customize the properties reference slide-down menu, here's not a list.
3, Onmeasure
The onmeasure must be set to the width, height, etc. of the slide-by menu:
@Overrideprotected void onmeasure (int widthmeasurespec, int heightmeasurespec) {/** * shows the setting of a width */if (!once) {mwrapper = (L inearlayout) Getchildat (0), Mleftmenu = (viewgroup) mwrapper.getchildat (0); mcontent = (ViewGroup) mWrapper.getChildAt ( 1); Mrightmenu = (ViewGroup) mwrapper.getchildat (2); mmenuwidth = Mscreenwidth-mmenurightpadding;mhalfmenuwidth = Mmenuwidth/2;mleftmenu.getlayoutparams (). Width = Mmenuwidth;mcontent.getlayoutparams (). width = mscreenwidth; Mrightmenu.getlayoutparams (). width = mmenuwidth;} Super.onmeasure (Widthmeasurespec, heightmeasurespec);}
You can see that we have set the width (mscreenwidth-mmenurightpadding) to the left and right menu respectively;
After the width setting is complete, must be positioned, the left side of the menu to the left, the right side of the menu is placed to the right, the middle is still our content area, then see OnLayout Method ~
4, OnLayout
@Overrideprotected void OnLayout (Boolean changed, int l, int t, int r, int b) {super.onlayout (changed, L, T, R, b); if (chan GED) {//The menu is hidden This.scrollto (mmenuwidth, 0); once = True;}}
Ha, surprisingly simple, because our interior is a horizontal linear layout, so directly to the left to slide out can ~ ~ Positioning also completed, then this time should be to our processing touch.
5, Ontouchevent
@Overridepublic boolean ontouchevent (motionevent ev) {int action = ev.getaction (); switch (action) {//up), If the display area is larger than half of the menu width, otherwise hide case MotionEvent.ACTION_UP:int scrollx = GETSCROLLX ();//If it is the action left menu if (isoperateleft) {// If the shadow area is larger than half the menu, the Shadow menu if (Scrollx > Mhalfmenuwidth) {this.smoothscrollto (mmenuwidth, 0);//If the current left menu is open, And Monmenuopenlistener is not empty, the callback closes the menu if (isleftmenuopen && monmenuopenlistener! = null) {//First parameter true: Open menu, False: Close menu, second parameter 0 for left, 1 for right Monmenuopenlistener.onmenuopen (false, 0);} Isleftmenuopen = false;} else//Close left menu {this.smoothscrollto (0, 0);//If the current left menu is closed and Monmenuopenlistener is not empty, the callback opens the menu if (!isleftmenuopen & & Monmenuopenlistener! = null) {Monmenuopenlistener.onmenuopen (true, 0);} Isleftmenuopen = True;}} Operation right Side if (isoperateright) {//Open right Side slide menu if (scrollx > mhalfmenuwidth + mmenuwidth) {This.smoothscrollto (mmenuwidth + Mmenuwidth, 0);} else//off the right side slide menu {this.smoothscrollto (mmenuwidth, 0);}} return true;} return super.ontouchevent (EV);}
Still simple ~ ~ ~ We just need to focus on action_up, and then get the SCROLLX after the finger is lifted, and then we pass a Boolean value that determines whether the user is now operating on the left or right menu?
If this is the left side of the operation, determine if the SCORLLX is more than half the width of the menu, and then do the corresponding action.
If the right side of the operation, then Judge Scrollx and Mhalfmenuwidth + mmenuwidth (Note that the right menu is completely hidden when the scrollx equals Mmenuwidth), and then do the corresponding operation.
We also added a callback to the menu on the left:
if (Isleftmenuopen && monmenuopenlistener! = null)
{
First parameter true: Open menu, False: Close menu, second parameter 0 for left; 1 for right
Monmenuopenlistener.onmenuopen (False, 0);
}
A glance at our callback interface:
/** * Callback Interface * @author Zhy * */public Interface onmenuopenlistener{/** * * @param isOpen True Open menu, false close menu * @param fl Ag 0 left, 1 right */void Onmenuopen (boolean isOpen, int flag);}
Right menu I did not add a callback, you follow the form on the left to add their own OK;
OK, next, look at the code where we can tell if the user operation is on the left or the right.
6, Onscrollchanged
@Overrideprotected void onscrollchanged (int l, int t, int oldl, int Oldt) {super.onscrollchanged (L, T, OLDL, Oldt); if (l &G T Mmenuwidth) {isoperateright = True;isoperateleft = false;} Else{isoperateright = False;isoperateleft = true;}}
If you have seen the first two articles, you should look familiar with this method. We directly through the L and menu width comparison, if larger than the menu width, then must be to manipulate the right side of the menu, otherwise you want to manipulate the left menu;
Here, our two-way sliding menu is done, as you believe it or not, anyway I have. Before you look, post the Mainactivity code:
7, Mainactivity
Package Com.zhy.zhy_bin_slidingmenu02;import Java.util.arraylist;import Java.util.list;import Android.app.listactivity;import Android.os.bundle;import Android.view.window;import Android.widget.ArrayAdapter; Import Android.widget.toast;import Com.zhy.view.binaryslidingmenu;import Com.zhy.view.binaryslidingmenu.onmenuopenlistener;public class Mainactivity extends Listactivity{private Binaryslidingmenu mmenu;private list<string> mdatas = new arraylist<string> (); @Overrideprotected void OnCreate (Bundle savedinstancestate) {super.oncreate (savedinstancestate); Requestwindowfeature (Window.feature_no_ TITLE); Setcontentview (r.layout.activity_main); mmenu = (Binaryslidingmenu) Findviewbyid (R.id.id_menu); Mmenu.setonmenuopenlistener (New Onmenuopenlistener () {@Overridepublic void Onmenuopen (boolean isOpen, int flag) {if ( IsOpen) {Toast.maketext (Getapplicationcontext (), flag = = 0? "Leftmenu Open": "Rightmenu Open", Toast.length_short). Show (); Else{toast.maketext (Getapplicationcontext (), flag = = 0 ? "Leftmenu Close": "Rightmenu Close", Toast.length_short). Show ();}}); /Initialize data for (int i = ' A '; I <= ' Z '; i++) {Mdatas.add ((char) i + "");} Set Adapter Setlistadapter (new arrayadapter<string> (this, R.layout.item, Mdatas));}}
Did not say, in order to facilitate the direct inheritance of listactivity, and then set a callback, layout file must have a ListView, in order to test whether we have conflict ~ ~ But we are not afraid of ~
:
Of course, the simplest two-way slide how to meet everyone's good (Zhao) odd (Nue) heart, so we are ready to play some magical tricks ~ ~
4, create two-way drawer slide
We add two lines of code in Onscrollchanged ~ ~ Set a property animation for Mcontent
@Overrideprotected void onscrollchanged (int l, int t, int oldl, int Oldt) {super.onscrollchanged (L, T, OLDL, Oldt); if (l &G T Mmenuwidth) {isoperateright = True;isoperateleft = false;} Else{isoperateright = False;isoperateleft = true;} FLOAT scale = l * 1.0f/mmenuwidth; Viewhelper.settranslationx (Mcontent, Mmenuwidth * (scale-1));}
Simple analysis of HA:
1, scale, when sliding left menu: value is 1.0~0.0;mmenuwidth * (scale-1) value is from 0.0~-mmenuwidth (note: negative); then the left offset of mcontent, is 0 to Mmenuwidth; that is, the entire sliding process, we force the content area to be fixed.
2, scale, when sliding the right menu: The value is: 1.0~2.0;mmenuwidth * (scale-1) value is from 0.0~ mmenuwidth (note: positive number); then the mcontent to the right offset, is 0 to Mmenuwidth; that is, the entire sliding process, we force the content area to be fixed.
OK, the content is fixed, then we now both sides of the menu should be on the content of the show ~ ~ This is not our drawer effect ~
Well, this time the wood has, because the test results found that the left side of the menu will be covered by the content area, not to see, the right side of the menu to meet the desired effect, because, the left side of the menu slide out, is covered by the content area, this is easy to understand, after all, our layout, content on the left side of So, what do we do?
At first, I was going to use the Bringtofont method, when dragging, let the menu on top ~ ~ ~ But, the problem is big, interested can try ~ ~
So, I changed the method, I will binaryslidingmenu the internal linearlayout to customize, now the layout file is this:
<com.zhy.view.binaryslidingmenu xmlns:android= "http://schemas.android.com/apk/res/android" xmlns:tools= "http ://schemas.android.com/tools "xmlns:zhy=" http://schemas.android.com/apk/res/com.zhy.zhy_bin_slidingmenu03 " Android:id= "@+id/id_menu" android:layout_width= "wrap_content" android:layout_height= "Fill_parent" android:scrollb Ars= "None" zhy:rightpadding= "100DP" > <com.zhy.view.mylinearlayout android:layout_width= "wrap_content" android:layout_height= "fill_parent" android:orientation= "horizontal" > <include layout= "@layout /layout_menu "/> <linearlayout android:layout_width=" Fill_parent "android:layout_height = "Fill_parent" android:background= "@drawable/eee" android:gravity= "center" android:orient ation= "Horizontal" > <listview android:id= "@android: Id/list" android:layout _width= "Fill_parent" Android:layout_height= "Fill_parent" > </ListView> </LinearLayout> <include layout= "@ Layout/layout_menu2 "/> </com.zhy.view.MyLinearLayout></com.zhy.view.BinarySlidingMenu>
Mylinearlayout's Code:
Package Com.zhy.view;import Android.content.context;import Android.util.attributeset;import android.util.Log; Import Android.widget.linearlayout;public class Mylinearlayout extends Linearlayout{public mylinearlayout (Context Context, AttributeSet Attrs) {Super (context, attrs);//LOG.E ("TAG", "mylinearlayout"); setchildrendrawingorderenabled (true);} @Overrideprotected int Getchilddrawingorder (int childCount, int i) {//log.e ("tag", "Getchilddrawingorder" + i + "," + Chi Ldcount); if (i = = 0) return 1;if (i = = 2) return 2;if (i = = 1) return 0;return Super.getchilddrawingorder (ChildCount, i);}}
Set setchildrendrawingorderenabled (True) in the construction method, and then getchilddrawingorder the order in which the child view is drawn, so that the content (i==0) is always drawn first.
Now, run it again:
The effect is not very good, please allow me to move the picture ~ ~ ~
Now, there is one last effect, if so, what is the menu under?
5, create a menu under the content of the two-way slide
Needless to say, we can think of, is nothing more than in the onscrollchanged to change the property animation Bai, said right!
1. Rewriting the Onscrollchanged method
@Overrideprotected void onscrollchanged (int l, int t, int oldl, int Oldt) {super.onscrollchanged (L, T, OLDL, Oldt); if (l &G T Mmenuwidth) {//1.0 ~2.0 1.0~0.0//(2-scale) Float scale = l * 1.0f/mmenuwidth;isoperateright = True;isoperateleft = False ; Viewhelper.settranslationx (Mrightmenu,-mmenuwidth * (2-scale));} Else{float scale = l * 1.0f/mmenuwidth;isoperateright = False;isoperateleft = true; Viewhelper.settranslationx (Mleftmenu, mmenuwidth * scale);}}
That is, when you pull, try to make the menu guaranteed under the Content ~ ~ ~ The code itself pondering
2, rewrite mylinearlayout
Of course, this is not enough, and since our style has changed, it is certainly necessary to rewrite the view's drawing order.
Look at our mylinearlayout.
Package Com.zhy.view;import Android.content.context;import Android.util.attributeset;import android.util.Log; Import Android.widget.linearlayout;public class Mylinearlayout extends Linearlayout{public mylinearlayout (Context Context, AttributeSet Attrs) {Super (context, attrs); LOG.E ("TAG", "mylinearlayout"); setchildrendrawingorderenabled (true);} @Overrideprotected int Getchilddrawingorder (int childCount, int i) {if (i = = 0) return 0;if (i = = 2) return 1;if (i = = 1) retu RN 2;return Super.getchilddrawingorder (ChildCount, i);}}
:
Here, we have a different form of two-way side-slip is over ~ ~ ~
From the most common two-way, to the drawer-style, and our menu under the content of the slide has been done; I hope you through the three slide, you can extrapolate, to create a variety of abnormal side effects ~ ~ ~
Android implements a variety of bidirectional side-by-Side slide menu custom controls to attack