Android 自定义控件打造史上最简单的侧滑菜单

转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/39185641 ,本文出自【张鸿洋的博客】

侧滑菜单在很多应用中都会见到,最近QQ5.0侧滑还玩了点花样~~对于侧滑菜单,一般大家都会自定义ViewGroup,然后隐藏菜单栏,当手指滑动时,通过Scroller或者不断的改变leftMargin等实现;多少都有点复杂,完成以后还需要对滑动冲突等进行处理~~今天给大家带来一个简单的实现,史上最简单有点夸张,但是的确是我目前遇到过的最简单的一种实现~~~

1、原理分析

既然是侧滑,无非就是在巴掌大的屏幕,塞入两个大概两巴掌大的布局,需要需要滑动可以出现另一个,既然这样,大家为啥不考虑使用Android提供的HorizontalScrollView呢~

如果使用HorizontalScrollView,还需要在ACTION_DOWN , ACTION_MOVE里面去监听,判断,不断改变控件位置了么? NO!!!HorizontalScrollView本身就带了滑动的功能~~

还需要自己的手动处理各种冲突么?NO!!!当然了,还是需要了解下事件分发机制的~~~

2、效果图

嗯,主界面搞了QQ一张图片,左边盗用了一兄弟的布局文件~~罪过~~ 谁有好看的布局、图片、图标神马的,可以给我发点,感激~

3、布局文件

<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,里面一个方向水平的LinearLayout,然后就是一个是菜单的布局,一个是主布局了~

4、自定义SlidingMenu

接下来就是我们最核心的代码了~

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)
	{
		/**
		 * 显示的设置一个宽度
		 */
		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时,进行判断,如果显示区域大于菜单宽度一半则完全显示,否则隐藏
		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);
	}

}

哈哈,完工~上面的演示图,就用到这么点代码~~

代码怎么样,短不短~除了设置宽度这些杂七杂八的代码~正在处理滑动的代码不过10行~~我说史上最简单不为过吧~

嗯,由于代码过于短,就不解释了,大家自己看下注释~

5、扩展

嗯,就下来,我们完善下程序,我准备首先把菜单布局里面改成ListView来证明我们是没有冲突的;然后添加一个属性让用户配置菜单距离右边的边距的值;再对外公布一个方法,点击自动打开菜单,供用户点击某个按钮,菜单慢慢滑出来~

1、添加自定义属性

a、首先在values文件夹下新建一个attr.xml,写入以下内容:

<?xml version="1.0" encoding="utf-8"?>
<resources>

    <attr name="rightPadding" format="dimension" />

    <declare-styleable name="SlidingMenu">
        <attr name="rightPadding" />
    </declare-styleable>

</resources>

b、在布局中声明命名空间和使用属性

定义完了,肯定要使用么。

<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"这里我设置了100dp;

注:很多人问我,没有提示咋办,这样,你clean下项目,如果你运气好,就有提示了,嗯,运气好~

c、在我们自定义类中获得属性

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:
				// 默认50
				mMenuRightPadding = a.getDimensionPixelSize(attr,
						(int) TypedValue.applyDimension(
								TypedValue.COMPLEX_UNIT_DIP, 50f,
								getResources().getDisplayMetrics()));// 默认为10DP
				break;
			}
		}
		a.recycle();
	}

在三个参数的构造方法中,通过TypeArray获取就行了~

好了,这样就行了~如果你又很多自定义属性,按照上面的步骤来就行了~~

2、对外公布一个打开菜单的方法

首先定义一个boolean isOpen变量,用来标识我们当前菜单的状态~~然后记得在ACTION_UP的时候改变下状态:

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;
		}

下面开始添加方法:

/**
	 * 打开菜单
	 */
	public void openMenu()
	{
		if (isOpen)
			return;
		this.smoothScrollTo(0, 0);
		isOpen = true;
	}

	/**
	 * 关闭菜单
	 */
	public void closeMenu()
	{
		if (isOpen)
		{
			this.smoothScrollTo(mMenuWidth, 0);
			isOpen = false;
		}
	}

	/**
	 * 切换菜单状态
	 */
	public void toggle()
	{
		if (isOpen)
		{
			closeMenu();
		} else
		{
			openMenu();
		}
	}

顺手多添加了两个。。。

下面,我们挑一个进行测试:

主布局多添加一个按钮,用于触发toggleMenu()方法

主Activity

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();
	}
}

好了,看下现在的效果图:

我们把padding改成了100dp~

然后点击我们的按钮,看哈效果~~

3、添加ListView测试

好了~~ListView也测试完了~~大家可以根据自己的需求各种修改~~

对了,今天测试用QQ的目的是为了,下次我要拿上面的代码,改造和QQ5.0一模一样的效果,大家有兴趣可以提前试一试,QQ的菜单好像是隐藏在主界面下面一样,给人感觉不是划出来的,我们这个例子也能做出那样的效果,拭目以待吧;剩下就是各种缩放,透明度的动画了~~~

源码点击下载

如果觉得不错,评价下~哈~

时间: 2024-10-13 01:02:43

Android 自定义控件打造史上最简单的侧滑菜单的相关文章

Android滑动菜单特效实现,仿人人客户端侧滑效果,史上最简单的侧滑实现

本文首发于CSDN博客,转载请注明出处:http://blog.csdn.net/guolin_blog/article/details/8714621 人人客户端有一个特效还是挺吸引人的,在主界面手指向右滑动,就可以将菜单展示出来,而主界面会被隐藏大部分,但是仍有左侧的一小部分同菜单一起展示. 据说人人客户端的这个特效是从facebook客户端模仿来的,至于facebook是不是又从其它地方模仿来的就不得而知了.好,今天我们就一起来实现这个效果,总之我第一次看到这个特效是在人人客户端看到的,我

Android开发:史上最简单方便的viewpager加indicator的方法

开发Android应用的时候,每次给viewpager加indicator的时候,是不是感觉到很无力呢,看看JakeWharton大神的github,要么要应用library,要么把code加到自己的项目中,还要加attrs,加各种value,比如colors,strings,其实超过90%以上的时候,我们的需要其实很简单,只是在底部的中间加上指示圆点,而且JakeWharton大神的默认的是空心圆圈,还要在onDraw中改成实心的圆形,是不是厌烦啦,每次都要这么麻烦,好了,终极简单的解决方法出

【Android】史上最简单,一步集成侧滑(删除)菜单,高仿QQ、IOS

本篇文章已授权微信公众号 guolin_blog (郭霖)独家发布 转载请标明出处: http://blog.csdn.net/zxt0601/article/details/53157090 本文出自:[张旭童的博客](http://blog.csdn.net/zxt0601) 代码传送门:喜欢的话,随手点个star.多谢 https://github.com/mcxtzhang/SwipeDelMenuLayout 重要的话 开头说,not for the RecyclerView or L

史上最简单的个人移动APP开发入门--jQuery Mobile版跨平台APP开发

书是人类进步的阶梯. ——高尔基 习大大要求新新人类要有中国梦,鼓励大学生们一毕业就创业.那最好的创业途径是什么呢?就是APP.<构建跨平台APP-jQuery Mobile移动应用实战>就是一本写给没钱没身份没资历的创业小白看的APP书,看完这本书你可以拥有自己的一个APP,不用花钱就能移植到其他移动平台,支持iOS,Android,Windows Phone!!!!!!!!找个最便宜的来练手吧!  小白APP交流Q群:  348632872 清华大学出版社推出的<构建跨平台APP:j

史上最简单,一步集成侧滑(删除)菜单,高仿QQ、IOS。

重要的话 开头说,not for the RecyclerView or ListView, for the Any ViewGroup. 本控件不依赖任何父布局,不是针对 RecyclerView.ListView,而是任意的ViewGroup里的childView都可以使用侧滑(删除)菜单.支持任意ViewGroup.0耦合.史上最简单. 概述 本控件从撸出来在项目使用至今已经过去7个月,距离第一次将它push至github上,也已经2月+.(之前,我发表过一篇文章.传送门:http://b

史上最简单的 Spring MVC 教程(十)

1 前言 在史上最简单的 Spring MVC 教程(九)中,咱们已经实现了图片的上传及显示功能,那么接下来,在本篇博文中,咱们更进一步,以实体类(Person)中的字段"name"和控制器(PersonController)中的方法 updatePersonList 为例,实现参数的校验功能. 2 注解示例 - 参数校验 老规矩,首先给出项目结构图: 在给出代码之前, 咱们先明确参数校验的步骤: 导入参数校验的 jar 包: 在实体上配置需要校验的属性: 在控制器的方法中用注解 @V

史上最简单的带流控功能的http server

s.py import time import SimpleHTTPServer import SocketServer BYTES_PER_SECOND=160*1024 class MyHTTPRequestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler): def do_GET(self): """Serve a GET request.""" f = self.send_head() i

史上最简单的软件破解——5行脚本代码完美破解99%的过期软件

如果你看到了这篇博文,绝对保证不虚此行.仅仅5行脚本代码,即可破解99%的过期软件. 这件事的背景:最近在找了一些学习资料,其中有Rational Rose画的图,好久没用过它了.今天安装好,导入许可文件,结果问题出现了,提示没有激活.怎么回事??仔细一看,原来许可文件到2013年12月份就过期了(乌鸦飘过...) 在网上找了半天也没有找到一个新的许可文件,结果一狠心,手动改了一下日期,再启动,ok了,把时间再改回来.本来事儿到这儿就完了.但是结果光今天一天就手动改了好几次系统时间,这就太让人无

史上最简单的 MyBatis 教程

1 前言 MyBatis 源于 Apache 的一个开源项目 iBatis,而 iBatis 一词则来源于"internet"和"abatis"的组合,2010年这个项目由 Apache Software Foundation 迁移到了 Google Code,并且改名为MyBatis ,2013年11月其又迁移到 Github.MyBatis 是一个基于 Java 的支持普通 SQL 查询,存储过程和高级映射的优秀持久层框架,相比于基于面向对象使用 HQL 语言的