Android之自定义侧滑菜单

先来上图:

我们把主界面从左向右拉动,可以看到地下有一层菜单页,从透明渐渐变得不透明,从小渐渐变大,感觉上觉得菜单页是从屏幕外面被拉到屏幕中的。下面的代码实现这个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 }
原文地址:https://www.cnblogs.com/blog-wzy/p/5268735.html