側(cè)滑菜單在很多應(yīng)用中都會(huì)見(jiàn)到,最近qq5.0側(cè)滑還玩了點(diǎn)花樣~~對(duì)于側(cè)滑菜單,一般大家都會(huì)自定義viewgroup,然后隱藏菜單欄,當(dāng)手指滑動(dòng)時(shí),通過(guò)scroller或者不斷的改變leftmargin等實(shí)現(xiàn);多少都有點(diǎn)復(fù)雜,完成以后還需要對(duì)滑動(dòng)沖突等進(jìn)行處理~~今天給大家?guī)?lái)一個(gè)簡(jiǎn)單的實(shí)現(xiàn),史上最簡(jiǎn)單有點(diǎn)夸張,但是的確是我目前遇到過(guò)的最簡(jiǎn)單的一種實(shí)現(xiàn)~~~
1、原理分析
既然是側(cè)滑,無(wú)非就是在巴掌大的屏幕,塞入大概兩巴掌大的布局,需要滑動(dòng)可以出現(xiàn)另一個(gè),既然這樣,大家為啥不考慮使用android提供的horizontalscrollview呢~
如果使用horizontalscrollview,還需要在action_down , action_move里面去監(jiān)聽(tīng),判斷,不斷改變控件位置了么? no!!!horizontalscrollview本身就帶了滑動(dòng)的功能~~
還需要自己的手動(dòng)處理各種沖突么?no!!!當(dāng)然了,還是需要了解下事件分發(fā)機(jī)制的~~~
2、效果圖
嗯,主界面搞了qq一張圖片,左邊盜用了一兄弟的布局文件~~罪過(guò)~~ 誰(shuí)有好看的布局、圖片、圖標(biāo)神馬的,可以給我發(fā)點(diǎn),感激~
3、布局文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
<com.example.zhy_slidingmenu.slidingmenu xmlns:android= "http://schemas.android.com/apk/res/android" xmlns:tools= "http://schemas.android.com/tools" android:layout_width= "wrap_content" android:layout_height= "fill_parent" android:scrollbars= "none" > <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/qq" > </linearlayout> </linearlayout> </com.example.zhy_slidingmenu.slidingmenu> |
首先是我們的自定義view,里面一個(gè)方向水平的linearlayout,然后就是一個(gè)是菜單的布局,一個(gè)是主布局了~
4、自定義slidingmenu
接下來(lái)就是我們最核心的代碼了~
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
|
package com.example.zhy_slidingmenu; import android.content.context; import android.util.attributeset; import android.util.typedvalue; import android.view.motionevent; import android.view.viewgroup; import android.widget.horizontalscrollview; import android.widget.linearlayout; import com.zhy.utils.screenutils; public class slidingmenu extends horizontalscrollview { /** * 屏幕寬度 */ private int mscreenwidth; /** * dp */ private int mmenurightpadding = 50 ; /** * 菜單的寬度 */ private int mmenuwidth; private int mhalfmenuwidth; private boolean once; public slidingmenu(context context, attributeset attrs) { super (context, attrs); mscreenwidth = screenutils.getscreenwidth(context); } @override protected void onmeasure( int widthmeasurespec, int heightmeasurespec) { /** * 顯示的設(shè)置一個(gè)寬度 */ if (!once) { linearlayout wrapper = (linearlayout) getchildat( 0 ); viewgroup menu = (viewgroup) wrapper.getchildat( 0 ); viewgroup content = (viewgroup) wrapper.getchildat( 1 ); // dp to px mmenurightpadding = ( int ) typedvalue.applydimension( typedvalue.complex_unit_dip, mmenurightpadding, content .getresources().getdisplaymetrics()); mmenuwidth = mscreenwidth - mmenurightpadding; mhalfmenuwidth = mmenuwidth / 2 ; menu.getlayoutparams().width = mmenuwidth; content.getlayoutparams().width = mscreenwidth; } super .onmeasure(widthmeasurespec, heightmeasurespec); } @override protected void onlayout( boolean changed, int l, int t, int r, int b) { super .onlayout(changed, l, t, r, b); if (changed) { // 將菜單隱藏 this .scrollto(mmenuwidth, 0 ); once = true ; } } @override public boolean ontouchevent(motionevent ev) { int action = ev.getaction(); switch (action) { // up時(shí),進(jìn)行判斷,如果顯示區(qū)域大于菜單寬度一半則完全顯示,否則隱藏 case motionevent.action_up: int scrollx = getscrollx(); if (scrollx > mhalfmenuwidth) this .smoothscrollto(mmenuwidth, 0 ); else this .smoothscrollto( 0 , 0 ); return true ; } return super .ontouchevent(ev); } } |
哈哈,完工~上面的演示圖,就用到這么點(diǎn)代碼~~
代碼怎么樣,短不短~除了設(shè)置寬度這些雜七雜八的代碼~正在處理滑動(dòng)的代碼不過(guò)10行~~我說(shuō)史上最簡(jiǎn)單不為過(guò)吧~
嗯,由于代碼過(guò)于短,就不解釋了,大家自己看下注釋~
5、擴(kuò)展
嗯,就下來(lái),我們完善下程序,我準(zhǔn)備首先把菜單布局里面改成listview來(lái)證明我們是沒(méi)有沖突的;然后添加一個(gè)屬性讓用戶配置菜單距離右邊的邊距的值;再對(duì)外公布一個(gè)方法,點(diǎn)擊自動(dòng)打開(kāi)菜單,供用戶點(diǎn)擊某個(gè)按鈕,菜單慢慢滑出來(lái)~
1、添加自定義屬性
a、首先在values文件夾下新建一個(gè)attr.xml,寫(xiě)入以下內(nèi)容:
1
2
3
4
5
6
7
|
<?xml version= "1.0" encoding= "utf-8" ?> <resources> <attr name= "rightpadding" format= "dimension" /> <declare-styleable name= "slidingmenu" > <attr name= "rightpadding" /> </declare-styleable> </resources> |
b、在布局中聲明命名空間和使用屬性
定義完了,肯定要使用么。
1
2
3
4
5
6
7
|
<com.example.zhy_slidingmenu.slidingmenu 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.example.zhy_slidingmenu" android:layout_width= "wrap_content" android:layout_height= "fill_parent" android:scrollbars= "none" zhy:rightpadding= "100dp" > |
可以看到我們的命名空間:xmlns:zhy="http://schemas.android.com/apk/res/com.example.zhy_slidingmenu" 是http://schemas.android.com/apk/res/加上我們的包名;
我們的屬性:zhy:rightpadding="100dp"這里我設(shè)置了100dp;
注:很多人問(wèn)我,沒(méi)有提示咋辦,這樣,你clean下項(xiàng)目,如果你運(yùn)氣好,就有提示了,嗯,運(yùn)氣好~
c、在我們自定義類(lèi)中獲得屬性
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
public slidingmenu(context context, attributeset attrs, int defstyle) { super (context, attrs, defstyle); mscreenwidth = screenutils.getscreenwidth(context); typedarray a = context.gettheme().obtainstyledattributes(attrs, r.styleable.slidingmenu, defstyle, 0 ); int n = a.getindexcount(); for ( int i = 0 ; i < n; i++) { int attr = a.getindex(i); switch (attr) { case r.styleable.slidingmenu_rightpadding: // 默認(rèn)50 mmenurightpadding = a.getdimensionpixelsize(attr, ( int ) typedvalue.applydimension( typedvalue.complex_unit_dip, 50f, getresources().getdisplaymetrics())); // 默認(rèn)為10dp break ; } } a.recycle(); } |
在三個(gè)參數(shù)的構(gòu)造方法中,通過(guò)typearray獲取就行了~
好了,這樣就行了~如果你又很多自定義屬性,按照上面的步驟來(lái)就行了~~
2、對(duì)外公布一個(gè)打開(kāi)菜單的方法
首先定義一個(gè)boolean isopen變量,用來(lái)標(biāo)識(shí)我們當(dāng)前菜單的狀態(tài)~~然后記得在action_up的時(shí)候改變下?tīng)顟B(tài):
1
2
3
4
5
6
7
8
9
10
11
12
13
|
case motionevent.action_up: int scrollx = getscrollx(); if (scrollx > mhalfmenuwidth) { this .smoothscrollto(mmenuwidth, 0 ); isopen = false ; } else { this .smoothscrollto( 0 , 0 ); isopen = true ; } return true ; } |
下面開(kāi)始添加方法:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
|
/** * 打開(kāi)菜單 */ public void openmenu() { if (isopen) return ; this .smoothscrollto( 0 , 0 ); isopen = true ; } /** * 關(guān)閉菜單 */ public void closemenu() { if (isopen) { this .smoothscrollto(mmenuwidth, 0 ); isopen = false ; } } /** * 切換菜單狀態(tài) */ public void toggle() { if (isopen) { closemenu(); } else { openmenu(); } } |
順手多添加了兩個(gè)。。。
下面,我們挑一個(gè)進(jìn)行測(cè)試:
主布局多添加一個(gè)按鈕,用于觸發(fā)togglemenu()方法
主activity
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
public class mainactivity extends activity { private slidingmenu mmenu ; @override protected void oncreate(bundle savedinstancestate) { super .oncreate(savedinstancestate); requestwindowfeature(window.feature_no_title); setcontentview(r.layout.activity_main); mmenu = (slidingmenu) findviewbyid(r.id.id_menu); } public void togglemenu(view view) { mmenu.toggle(); } } |
好了,看下現(xiàn)在的效果圖:
我們把padding改成了100dp~
然后點(diǎn)擊我們的按鈕,看哈效果~~
3、添加listview測(cè)試
好了~~listview也測(cè)試完了~~大家可以根據(jù)自己的需求各種修改~~
對(duì)了,今天測(cè)試用qq的目的是為了,下次我要拿上面的代碼,改造和qq5.0一模一樣的效果,大家有興趣可以提前試一試,qq的菜單好像是隱藏在主界面下面一樣,給人感覺(jué)不是劃出來(lái)的,我們這個(gè)例子也能做出那樣的效果,拭目以待吧;剩下就是各種縮放,透明度的動(dòng)畫(huà)了~~~
以上內(nèi)容是小編給大家分享的android使用自定義控件horizontalscrollview打造史上最簡(jiǎn)單的側(cè)滑菜單,希望對(duì)大家有所幫助。