先来上图:
我们把主界面从左向右拉动,可以看到地下有一层菜单页,从透明渐渐变得不透明,从小渐渐变大,感觉上觉得菜单页是从屏幕外面被拉到屏幕中的。下面的代码实现这个DEMO:
首先是自定义控件SlidingMenu控件的代码:
1 public class SlidingMenu extends HorizontalScrollView {
2 // 自定义View的步骤:
3 // 1、onMeasure():决定子View的宽和高和自己的宽和高
4 // 2、onLayout():决定子View放置的位置
5 // 3、onTouchEvent:判断用户手指的滑动状态
6 // 自定义属性的步骤:
7 // 1、书写XML文件(values/attrs.xml)
8 // 2、在布局文件中进行使用,注意xmlns命名空间
9 // 3、在三个参数的构造方法中获得我们设置的值
10
11 private LinearLayout wrapper; // 总容器
12 private ViewGroup menu, content; // 菜单页,内容页
13 private int screenWidth; // 屏幕的宽度
14 private int menuWidth; // menu的宽度
15 private int menuRightPadding = 50; // menu菜单距离屏幕右侧的距离(单位是DIP)
16 private boolean once; // onMeasure()方法是不是第一次调用
17 private boolean isOpen; // 侧滑菜单是否是开启状态
18
19 // 在界面上通过上下文直接生成控件时,调用这个构造方法
20 public SlidingMenu(Context context) {
21 this(context, null);
22 }
23
24 // 当没有使用自定义属性时,调用这个构造方法
25 public SlidingMenu(Context context, AttributeSet attrs) {
26 this(context, attrs, 0);
27 }
28
29 // 当使用了自定义属性(values/attrs.xml)时,调用这个构造方法
30 public SlidingMenu(Context context, AttributeSet attrs, int defStyleAttr) {
31 super(context, attrs, defStyleAttr);
32 // 获取我们自定义的属性
33 TypedArray a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.SlidingMenu, defStyleAttr, 0);
34 for (int i = 0; i < a.getIndexCount(); i++) {
35 int attr = a.getIndex(i);
36 switch (attr) {
37 case R.styleable.SlidingMenu_rightPadding:
38 // getDimensionPixelSize:为attr下标的属性设置默认值(第二个参数)
39 menuRightPadding = a.getDimensionPixelSize(attr, (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
40 50, context.getResources().getDisplayMetrics()));
41 break;
42 }
43 }
44 a.recycle();
45
46 // 获取屏幕的宽度
47 WindowManager manager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
48 DisplayMetrics metrics = new DisplayMetrics();
49 manager.getDefaultDisplay().getMetrics(metrics);
50 screenWidth = metrics.widthPixels;
51 }
52
53 @Override
54 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
55 if (!once) {
56 wrapper = (LinearLayout) getChildAt(0);
57 menu = (ViewGroup) wrapper.getChildAt(0);
58 content = (ViewGroup) wrapper.getChildAt(1);
59 // 设置菜单和主页的宽度
60 menuWidth = menu.getLayoutParams().width = screenWidth - menuRightPadding;
61 content.getLayoutParams().width = screenWidth;
62
63 once = true;
64 }
65 super.onMeasure(widthMeasureSpec, heightMeasureSpec);
66 }
67
68 // 通过设置偏移量,将Menu隐藏
69 @Override
70 protected void onLayout(boolean changed, int l, int t, int r, int b) {
71 super.onLayout(changed, l, t, r, b);
72 if (changed) {
73 this.scrollTo(menuWidth, 0);
74 }
75 }
76
77 @Override
78 public boolean onTouchEvent(MotionEvent ev) {
79 int action = ev.getAction();
80 switch (action) {
81 case MotionEvent.ACTION_UP:
82 int scrollX = getScrollX(); // 隐藏在左边的宽度
83 if (scrollX >= menuWidth / 2) {
84 this.smoothScrollTo(menuWidth, 0);
85 isOpen = false;
86 } else {
87 this.smoothScrollTo(0, 0);
88 isOpen = true;
89 }
90 return true;
91 }
92 return super.onTouchEvent(ev);
93 }
94
95 // 打开菜单
96 public void openMenu() {
97 if (isOpen)
98 return;
99 this.smoothScrollTo(0, 0);
100 isOpen = false;
101 }
102
103 // 关闭菜单
104 public void closeMenu() {
105 if (!isOpen)
106 return;
107 this.smoothScrollTo(menuWidth, 0);
108 isOpen = true;
109 }
110
111 // 管理菜单的状态和动作(如果菜单是关闭的就打开它,如果是打开的就关闭它)
112 public void toggle() {
113 if (isOpen) {
114 closeMenu();
115 } else {
116 openMenu();
117 }
118 }
119
120 // 抽屉式侧滑(这个方法监听滚动的全过程)
121 @Override
122 protected void onScrollChanged(int l, int t, int oldl, int oldt) {
123 super.onScrollChanged(l, t, oldl, oldt);
124 float scale = l * 1.0f / menuWidth;
125 // 实现仿QQ5.0的侧滑界面:在滑动时,滑动朝向的ViewGroup不断缩小,另一个ViewGroup不断放大
126 float rightScrollScale = 0.85f + 0.15f * scale; // 主界面的滑动缩放比例
127 float leftScrollScale = 1.0f - 0.4f * scale; // 菜单的滑动缩放比例
128 float leftAlphaScale = 0.6f + 0.4f * (1 - scale); // 菜单透明度的变化比例
129 // 调用属性动画(Android3.0时引入),设置TranslationX(这里需要引入nineoldandroids.jar包)
130 ViewHelper.setTranslationX(menu, menuWidth * scale * 0.75f);
131 // 设置Menu的缩放和透明度
132 ViewHelper.setScaleX(menu, leftScrollScale);
133 ViewHelper.setScaleY(menu, leftScrollScale);
134 ViewHelper.setAlpha(menu, leftAlphaScale);
135 // 设置Content的缩放
136 ViewHelper.setPivotX(content, 0);
137 ViewHelper.setPivotY(content, content.getHeight() / 2);
138 ViewHelper.setScaleX(content, rightScrollScale);
139 ViewHelper.setScaleY(content, rightScrollScale);
140 }
141 }
下面是主界面布局的代码:
1 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
2 xmlns:tools="http://schemas.android.com/tools"
3 xmlns:xgz="http://schemas.android.com/apk/res/com.activity"
4 android:layout_width="match_parent"
5 android:layout_height="match_parent"
6 android:background="@drawable/menu_bg" >
7
8 <com.view.SlidingMenu
9 android:id="@+id/main_slidingmenu"
10 android:layout_width="match_parent"
11 android:layout_height="match_parent"
12 xgz:rightPadding="75.0dip" >
13
14 <LinearLayout
15 android:layout_width="wrap_content"
16 android:layout_height="match_parent"
17 android:orientation="horizontal" >
18
19 <include layout="@layout/sideworks_menu" />
20
21 <LinearLayout
22 android:layout_width="match_parent"
23 android:layout_height="match_parent"
24 android:background="@drawable/main_bg" >
25
26 <Button
27 android:id="@+id/main_togglebtn"
28 android:layout_width="wrap_content"
29 android:layout_height="30.0dip"
30 android:layout_marginLeft="10.0dip"
31 android:layout_marginTop="10.0dip"
32 android:background="#00000000"
33 android:text="@string/main_toggle_btn"
34 android:textColor="#ffffff"
35 android:textSize="16.0sp" />
36 </LinearLayout>
37 </LinearLayout>
38 </com.view.SlidingMenu>
39
40 </RelativeLayout>
下面是主界面中引用的菜单页的布局代码:
1 <?xml version="1.0" encoding="utf-8"?>
2 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
3 android:layout_width="match_parent"
4 android:layout_height="match_parent"
5 android:background="#00000000"
6 android:gravity="center_vertical"
7 android:orientation="vertical" >
8
9 <RelativeLayout
10 android:layout_width="match_parent"
11 android:layout_height="wrap_content" >
12
13 <ImageView
14 android:id="@+id/menu_icon1"
15 android:layout_width="40.0dip"
16 android:layout_height="40.0dip"
17 android:layout_marginLeft="10.0dip"
18 android:contentDescription="@string/app_name"
19 android:src="@drawable/img_1" />
20
21 <TextView
22 android:layout_width="wrap_content"
23 android:layout_height="wrap_content"
24 android:layout_centerVertical="true"
25 android:layout_marginLeft="10.0dip"
26 android:layout_toRightOf="@id/menu_icon1"
27 android:text="@string/menu_icon1_text"
28 android:textColor="#ffffff"
29 android:textSize="15.0sp" />
30 </RelativeLayout>
31
32 <RelativeLayout
33 android:layout_width="match_parent"
34 android:layout_height="wrap_content"
35 android:layout_marginTop="15.0dip" >
36
37 <ImageView
38 android:id="@+id/menu_icon2"
39 android:layout_width="40.0dip"
40 android:layout_height="40.0dip"
41 android:layout_marginLeft="10.0dip"
42 android:contentDescription="@string/app_name"
43 android:src="@drawable/img_2" />
44
45 <TextView
46 android:layout_width="wrap_content"
47 android:layout_height="wrap_content"
48 android:layout_centerVertical="true"
49 android:layout_marginLeft="10.0dip"
50 android:layout_toRightOf="@id/menu_icon2"
51 android:text="@string/menu_icon2_text"
52 android:textColor="#ffffff"
53 android:textSize="15.0sp" />
54 </RelativeLayout>
55
56 <RelativeLayout
57 android:layout_width="match_parent"
58 android:layout_height="wrap_content"
59 android:layout_marginTop="15.0dip" >
60
61 <ImageView
62 android:id="@+id/menu_icon3"
63 android:layout_width="40.0dip"
64 android:layout_height="40.0dip"
65 android:layout_marginLeft="10.0dip"
66 android:contentDescription="@string/app_name"
67 android:src="@drawable/img_3" />
68
69 <TextView
70 android:layout_width="wrap_content"
71 android:layout_height="wrap_content"
72 android:layout_centerVertical="true"
73 android:layout_marginLeft="10.0dip"
74 android:layout_toRightOf="@id/menu_icon3"
75 android:text="@string/menu_icon3_text"
76 android:textColor="#ffffff"
77 android:textSize="15.0sp" />
78 </RelativeLayout>
79
80 <RelativeLayout
81 android:layout_width="match_parent"
82 android:layout_height="wrap_content"
83 android:layout_marginTop="15.0dip" >
84
85 <ImageView
86 android:id="@+id/menu_icon4"
87 android:layout_width="40.0dip"
88 android:layout_height="40.0dip"
89 android:layout_marginLeft="10.0dip"
90 android:contentDescription="@string/app_name"
91 android:src="@drawable/img_4" />
92
93 <TextView
94 android:layout_width="wrap_content"
95 android:layout_height="wrap_content"
96 android:layout_centerVertical="true"
97 android:layout_marginLeft="10.0dip"
98 android:layout_toRightOf="@id/menu_icon4"
99 android:text="@string/menu_icon4_text"
100 android:textColor="#ffffff"
101 android:textSize="15.0sp" />
102 </RelativeLayout>
103
104 <RelativeLayout
105 android:layout_width="match_parent"
106 android:layout_height="wrap_content"
107 android:layout_marginTop="15.0dip" >
108
109 <ImageView
110 android:id="@+id/menu_icon5"
111 android:layout_width="40.0dip"
112 android:layout_height="40.0dip"
113 android:layout_marginLeft="10.0dip"
114 android:contentDescription="@string/app_name"
115 android:src="@drawable/img_5" />
116
117 <TextView
118 android:layout_width="wrap_content"
119 android:layout_height="wrap_content"
120 android:layout_centerVertical="true"
121 android:layout_marginLeft="10.0dip"
122 android:layout_toRightOf="@id/menu_icon5"
123 android:text="@string/menu_icon5_text"
124 android:textColor="#ffffff"
125 android:textSize="15.0sp" />
126 </RelativeLayout>
127
128 </LinearLayout>
下面是自定义属性attrs.xml文件中的代码:
1 <?xml version="1.0" encoding="utf-8"?>
2 <resources>
3
4 <!-- 自定义属性:菜单离屏幕右侧的间距 -->
5 <attr name="rightPadding" format="dimension"></attr>
6
7 <declare-styleable name="SlidingMenu">
8 <attr name="rightPadding"></attr>
9 </declare-styleable>
10
11 </resources>
下面是主界面MainActivity.java中的代码:
1 public class MainActivity extends Activity {
2 private SlidingMenu slidingMenu;
3 private Button toggleBtn;
4
5 @Override
6 protected void onCreate(Bundle savedInstanceState) {
7 super.onCreate(savedInstanceState);
8 setContentView(R.layout.activity_main);
9 slidingMenu = (SlidingMenu) findViewById(R.id.main_slidingmenu);
10 toggleBtn = (Button) findViewById(R.id.main_togglebtn);
11
12 toggleBtn.setOnClickListener(new OnClickListener() {
13 @Override
14 public void onClick(View v) {
15 slidingMenu.toggle();
16 }
17 });
18 }
19 }