Android之自定义侧滑菜单
先来上图:

我们把主界面从左向右拉动,可以看到地下有一层菜单页,从透明渐渐变得不透明,从小渐渐变大,感觉上觉得菜单页是从屏幕外面被拉到屏幕中的。下面的代码实现这个DEMO:
首先是自定义控件SlidingMenu控件的代码:
 public class SlidingMenu extends HorizontalScrollView {
     // 自定义View的步骤:
     // 1、onMeasure():决定子View的宽和高和自己的宽和高
     // 2、onLayout():决定子View放置的位置
     // 3、onTouchEvent:判断用户手指的滑动状态
     // 自定义属性的步骤:
     // 1、书写XML文件(values/attrs.xml)
     // 2、在布局文件中进行使用,注意xmlns命名空间
     // 3、在三个参数的构造方法中获得我们设置的值
     private LinearLayout wrapper; // 总容器
     private ViewGroup menu, content; // 菜单页,内容页
     private int screenWidth; // 屏幕的宽度
     private int menuWidth; // menu的宽度
     private int menuRightPadding = 50; // menu菜单距离屏幕右侧的距离(单位是DIP)
     private boolean once; // onMeasure()方法是不是第一次调用
     private boolean isOpen; // 侧滑菜单是否是开启状态
     // 在界面上通过上下文直接生成控件时,调用这个构造方法
     public SlidingMenu(Context context) {
         this(context, null);
     }
     // 当没有使用自定义属性时,调用这个构造方法
     public SlidingMenu(Context context, AttributeSet attrs) {
         this(context, attrs, 0);
     }
     // 当使用了自定义属性(values/attrs.xml)时,调用这个构造方法
     public SlidingMenu(Context context, AttributeSet attrs, int defStyleAttr) {
         super(context, attrs, defStyleAttr);
         // 获取我们自定义的属性
         TypedArray a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.SlidingMenu, defStyleAttr, 0);
         for (int i = 0; i < a.getIndexCount(); i++) {
             int attr = a.getIndex(i);
             switch (attr) {
             case R.styleable.SlidingMenu_rightPadding:
                 // getDimensionPixelSize:为attr下标的属性设置默认值(第二个参数)
                 menuRightPadding = a.getDimensionPixelSize(attr, (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
                         50, context.getResources().getDisplayMetrics()));
                 break;
             }
         }
         a.recycle();
         // 获取屏幕的宽度
         WindowManager manager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
         DisplayMetrics metrics = new DisplayMetrics();
         manager.getDefaultDisplay().getMetrics(metrics);
         screenWidth = metrics.widthPixels;
     }
     @Override
     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
         if (!once) {
             wrapper = (LinearLayout) getChildAt(0);
             menu = (ViewGroup) wrapper.getChildAt(0);
             content = (ViewGroup) wrapper.getChildAt(1);
             // 设置菜单和主页的宽度
             menuWidth = menu.getLayoutParams().width = screenWidth - menuRightPadding;
             content.getLayoutParams().width = screenWidth;
             once = true;
         }
         super.onMeasure(widthMeasureSpec, heightMeasureSpec);
     }
     // 通过设置偏移量,将Menu隐藏
     @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(menuWidth, 0);
         }
     }
     @Override
     public boolean onTouchEvent(MotionEvent ev) {
         int action = ev.getAction();
         switch (action) {
         case MotionEvent.ACTION_UP:
             int scrollX = getScrollX(); // 隐藏在左边的宽度
             if (scrollX >= menuWidth / 2) {
                 this.smoothScrollTo(menuWidth, 0);
                 isOpen = false;
             } else {
                 this.smoothScrollTo(0, 0);
                 isOpen = true;
             }
             return true;
         }
         return super.onTouchEvent(ev);
     }
     // 打开菜单
     public void openMenu() {
         if (isOpen)
             return;
         this.smoothScrollTo(0, 0);
         isOpen = false;
     }
     // 关闭菜单
     public void closeMenu() {
         if (!isOpen)
             return;
         this.smoothScrollTo(menuWidth, 0);
         isOpen = true;
     }
     // 管理菜单的状态和动作(如果菜单是关闭的就打开它,如果是打开的就关闭它)
     public void toggle() {
         if (isOpen) {
             closeMenu();
         } else {
             openMenu();
         }
     }
     // 抽屉式侧滑(这个方法监听滚动的全过程)
     @Override
     protected void onScrollChanged(int l, int t, int oldl, int oldt) {
         super.onScrollChanged(l, t, oldl, oldt);
         float scale = l * 1.0f / menuWidth;
         // 实现仿QQ5.0的侧滑界面:在滑动时,滑动朝向的ViewGroup不断缩小,另一个ViewGroup不断放大
         float rightScrollScale = 0.85f + 0.15f * scale; // 主界面的滑动缩放比例
         float leftScrollScale = 1.0f - 0.4f * scale; // 菜单的滑动缩放比例
         float leftAlphaScale = 0.6f + 0.4f * (1 - scale); // 菜单透明度的变化比例
         // 调用属性动画(Android3.0时引入),设置TranslationX(这里需要引入nineoldandroids.jar包)
         ViewHelper.setTranslationX(menu, menuWidth * scale * 0.75f);
         // 设置Menu的缩放和透明度
         ViewHelper.setScaleX(menu, leftScrollScale);
         ViewHelper.setScaleY(menu, leftScrollScale);
         ViewHelper.setAlpha(menu, leftAlphaScale);
         // 设置Content的缩放
         ViewHelper.setPivotX(content, 0);
         ViewHelper.setPivotY(content, content.getHeight() / 2);
         ViewHelper.setScaleX(content, rightScrollScale);
         ViewHelper.setScaleY(content, rightScrollScale);
     }
 }
下面是主界面布局的代码:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:xgz="http://schemas.android.com/apk/res/com.activity"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/menu_bg" > <com.view.SlidingMenu
android:id="@+id/main_slidingmenu"
android:layout_width="match_parent"
android:layout_height="match_parent"
xgz:rightPadding="75.0dip" > <LinearLayout
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:orientation="horizontal" > <include layout="@layout/sideworks_menu" /> <LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/main_bg" > <Button
android:id="@+id/main_togglebtn"
android:layout_width="wrap_content"
android:layout_height="30.0dip"
android:layout_marginLeft="10.0dip"
android:layout_marginTop="10.0dip"
android:background="#00000000"
android:text="@string/main_toggle_btn"
android:textColor="#ffffff"
android:textSize="16.0sp" />
</LinearLayout>
</LinearLayout>
</com.view.SlidingMenu> </RelativeLayout>
下面是主界面中引用的菜单页的布局代码:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#00000000"
android:gravity="center_vertical"
android:orientation="vertical" > <RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content" > <ImageView
android:id="@+id/menu_icon1"
android:layout_width="40.0dip"
android:layout_height="40.0dip"
android:layout_marginLeft="10.0dip"
android:contentDescription="@string/app_name"
android:src="@drawable/img_1" /> <TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_marginLeft="10.0dip"
android:layout_toRightOf="@id/menu_icon1"
android:text="@string/menu_icon1_text"
android:textColor="#ffffff"
android:textSize="15.0sp" />
</RelativeLayout> <RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="15.0dip" > <ImageView
android:id="@+id/menu_icon2"
android:layout_width="40.0dip"
android:layout_height="40.0dip"
android:layout_marginLeft="10.0dip"
android:contentDescription="@string/app_name"
android:src="@drawable/img_2" /> <TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_marginLeft="10.0dip"
android:layout_toRightOf="@id/menu_icon2"
android:text="@string/menu_icon2_text"
android:textColor="#ffffff"
android:textSize="15.0sp" />
</RelativeLayout> <RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="15.0dip" > <ImageView
android:id="@+id/menu_icon3"
android:layout_width="40.0dip"
android:layout_height="40.0dip"
android:layout_marginLeft="10.0dip"
android:contentDescription="@string/app_name"
android:src="@drawable/img_3" /> <TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_marginLeft="10.0dip"
android:layout_toRightOf="@id/menu_icon3"
android:text="@string/menu_icon3_text"
android:textColor="#ffffff"
android:textSize="15.0sp" />
</RelativeLayout> <RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="15.0dip" > <ImageView
android:id="@+id/menu_icon4"
android:layout_width="40.0dip"
android:layout_height="40.0dip"
android:layout_marginLeft="10.0dip"
android:contentDescription="@string/app_name"
android:src="@drawable/img_4" /> <TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_marginLeft="10.0dip"
android:layout_toRightOf="@id/menu_icon4"
android:text="@string/menu_icon4_text"
android:textColor="#ffffff"
android:textSize="15.0sp" />
</RelativeLayout> <RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="15.0dip" > <ImageView
android:id="@+id/menu_icon5"
android:layout_width="40.0dip"
android:layout_height="40.0dip"
android:layout_marginLeft="10.0dip"
android:contentDescription="@string/app_name"
android:src="@drawable/img_5" /> <TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_marginLeft="10.0dip"
android:layout_toRightOf="@id/menu_icon5"
android:text="@string/menu_icon5_text"
android:textColor="#ffffff"
android:textSize="15.0sp" />
</RelativeLayout> </LinearLayout>
下面是自定义属性attrs.xml文件中的代码:
<?xml version="1.0" encoding="utf-8"?>
<resources> <!-- 自定义属性:菜单离屏幕右侧的间距 -->
<attr name="rightPadding" format="dimension"></attr> <declare-styleable name="SlidingMenu">
<attr name="rightPadding"></attr>
</declare-styleable> </resources>
下面是主界面MainActivity.java中的代码:
 public class MainActivity extends Activity {
     private SlidingMenu slidingMenu;
     private Button toggleBtn;
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
         setContentView(R.layout.activity_main);
         slidingMenu = (SlidingMenu) findViewById(R.id.main_slidingmenu);
         toggleBtn = (Button) findViewById(R.id.main_togglebtn);
         toggleBtn.setOnClickListener(new OnClickListener() {
             @Override
             public void onClick(View v) {
                 slidingMenu.toggle();
             }
         });
     }
 }
Android之自定义侧滑菜单的更多相关文章
- Android 自定义View修炼-打造完美的自定义侧滑菜单/侧滑View控件
		一.概述 在App中,经常会出现侧滑菜单,侧滑滑出View等效果,虽然说Android有很多第三方开源库,但是实际上 咱们可以自己也写一个自定义的侧滑View控件,其实不难,主要涉及到以下几个要点: ... 
- Android 高大上的侧滑菜单DrawerLayout,解决了不能全屏滑动的问题
		DrawerLayout预览 DrawerLayout主要功能就是 实现侧滑菜单效果的功能,并且可以通过增加一些设置来实现高大上的效果,那么就请看动态图: 注意左上角那个图标,有木有很好玩,哈哈. ... 
- vue2.X  自定义  侧滑菜单  组件
		1.vue2.0 封装 侧滑菜单组件 Sidebar.vue <!-- 侧滑菜单 组件 --> <template> <div> <transition na ... 
- android 实现自定义卫星菜单
		看了hyman老师的视频,听起来有点迷糊,所以就想把实现卫星菜单的实现总结一下.长话短说,下面总结一下: 一.自定义ViewGroup1).自定义属性文件 属性的定义: <attr name=& ... 
- android的左右侧滑菜单实现
		最近看了很多app应用都采用的是左右侧滑,比如网易新闻.凡客等 这里也试着写一下侧滑 首先看一下效果 然后给出xml布局代码 <RelativeLayout xmlns:android=&quo ... 
- android文章学习 侧滑菜单实现
		http://blog.csdn.net/jj120522/article/details/8075249 http://blog.csdn.net/lilybaobei/article/detail ... 
- Android 自定义View修炼-仿QQ5.0 的侧滑菜单效果的实现
		有一段时间没有写博客了,最近比较忙,没什么时间写,刚好今天有点时间, 我就分享下,侧滑菜单的实现原理,一般android侧滑的实现原理和步骤如下:(源码下载在下面最后给出哈) 1.使用ViewGrou ... 
- Android带侧滑菜单和ToolBar的BaseActivity
		写Android的时候,可能有多个界面.在风格统一的软件中,写Activity时会有很多重复.例如我所在软工课程小组的项目:Github链接 ,里面的TaskListActivity和TeacherL ... 
- Android-自定义侧滑菜单
		效果图: 需要继承ViewGroup,因为包含了子控件,菜单子控件 与 主页面子控件 Activity Xml布局相关: <!-- 自定义侧滑菜单 SlideMenu --> <Li ... 
随机推荐
- 记录 git 常用的操作命令总结
			记录 git 常用的操作命令总结 2016-12-15 16:44:04 作为一名开发者,熟悉使用 git 代码管理工具是一项必备的基本技能.git 相较 SVN 而言,其优点不言而喻.git 的功能 ... 
- socket Bio demo
			最近在做socket通信,最开始是基于Bio开发(其实开发的时候也不知道这种是基于BIO).但是问题来了,客户端发的报文,服务端接收会少,为了解决问题,只能恶补一下相关知识. 服务端: import ... 
- 【IScroll深入学习】解决IScroll疑难杂症
			前言 在去年,我们对IScroll的源码进行了学习,并且分离出了一段代码自己使用,在使用学习过程中发现几个致命问题: ① 光标移位 ② 文本框找不到(先让文本框获取焦点,再滑动一下,输入文字便可重现) ... 
- C++基本数据类型总结
			一.整形 1.整形有char.short.int.long.long long,这5个也默认为signed XX ; 规则:short至少16位:int至少和short一样:long至少32位,且至少 ... 
- 解读ASP.NET 5 & MVC6系列(9):日志框架
			框架介绍 在之前的.NET中,微软还没有提供过像样的日志框架,目前能用的一些框架比如Log4Net.NLog.CommonLogging使用起来多多少少都有些费劲,和java的SLF4J根本无法相比. ... 
- [LeetCode] Longest Consecutive Sequence 求最长连续序列
			Given an unsorted array of integers, find the length of the longest consecutive elements sequence. F ... 
- WPF实现三星手机充电界面
			GitHub地址:https://github.com/ptddqr/wpf-samsung-phone-s5-charging-ui/tree/master 先上效果图 这个效果来自于三星S5的充电 ... 
- CSS优先级
			一.CSS代码出现的几个位置 多重样式(Multiple Styles):如果外部样式.内部样式和内联样式同时应用于同一个元素,就是使多重样式的情况. 一般情况下,优先级如下:(外部样式)Extern ... 
- bzoj3223
			3223: Tyvj 1729 文艺平衡树 Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 3700 Solved: 2097[Submit][Sta ... 
- java中静态方法和静态类的学习
			静态内部类可以有静态成员,而非静态类 则不能有静态成员 静态内部类的非静态成员可以访问外部类的静态成员,而不可以访问外部类的非静态成员 非静态方法与对象相关,而静态方法属于类的方法, 总上所述:静态方 ... 
