使用DrawerLayout实现QQ5.0侧拉菜单效果

在上一篇文章中,我们介绍了怎么使用DrawerLayout来实现一个简单的侧拉菜单(使用DrawerLayout实现侧拉菜单),也就是我们常说的抽屉效果,GitHub上类似效果的实现方式非常多,实现出来的效果也是非常的绚丽,但是万变不离其宗,Google提供给我们的DrawerLayout才是最基本的,我们今天就来介绍一下怎样通过DrawerLayout来实现QQ5.0的侧拉效果。先来看一张效果图:

好,这是一个我们即将要实现的效果图,关于这个效果,大部分都是很简单的,都是使用了我们在上一篇博客中介绍的DrawerLayout技术来做的,所以如果你还没读过上一篇博客,建议先去看一下DrawerLayout的使用方法(使用DrawerLayout实现侧拉菜单),了解了DrawerLayout的使用方法之后,那么要实现QQ5.0的侧拉效果就如同探囊取物一般。

好了,废话不多说,我们就先来看看怎么实现这样一个效果。

先来看看主布局文件:

<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/drawerLayout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@drawable/background" >

    <RelativeLayout
        android:id="@+id/mContent"
        android:layout_width="match_parent"
        android:layout_height="match_parent" >

        <ImageView
            android:id="@+id/mContent_iv"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_margin="0dp"
            android:background="@drawable/content_iv"
            android:padding="0dp" />

        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:background="@null"
            android:onClick="onClick" />
    </RelativeLayout>

    <fragment
        android:id="@+id/left_fragment"
        android:name="com.lenve.qqdrawerlayout.LeftMenuFragment"
        android:layout_width="220dp"
        android:layout_height="match_parent"
        android:layout_gravity="left"
        android:tag="LEFTMENU" />

</android.support.v4.widget.DrawerLayout>

整个布局文件还是比较简单的,DrawerLayout中一共分为两大块,第一块就是主布局文件,先是是一张图片(这里我直接截了QQ页面的一张图),然后就是一个Button,注意这个Button的位置在整个页面的左上角,Button的背景设置为null,所以我们看不到Button,但是这个Button会响应我们的点击事件,第二部分是一个Fragment,这个Fragment我们看android:layout_gravity="left"属性就知道它是左边菜单栏的Fragment,在上一篇博客中,左边的菜单栏我们并没有使用Fragment,而是直接使用了布局文件,其实这里写成Fragment是比较好的,方便扩展,也方便管理。

好了,既然左边是一个Fragment,我们就来看看这个Fragment长什么样子?

先看看Fragment的布局文件:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

    <ListView
        android:id="@+id/left_menu_lv"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_marginTop="150dp" >
    </ListView>

</RelativeLayout>

就一个ListView,够简单吧,再看看listview中item的布局文件:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

    <ImageView
        android:id="@+id/left_iv"
        android:layout_width="48dp"
        android:layout_height="48dp"
        android:layout_marginLeft="20dp"
        android:padding="12dp"
        android:src="@drawable/svip" />

    <TextView
        android:id="@+id/left_tv"
        android:layout_width="wrap_content"
        android:layout_height="48dp"
        android:layout_marginLeft="20dp"
        android:layout_toRightOf="@id/left_iv"
        android:gravity="center"
        android:text="开通会员"
        android:textColor="@android:color/white"
        android:textSize="14sp" />

</RelativeLayout>

item的布局文件也是比较简单的,左边一个ImageView,右边一个TextView,我们再看看Fragment:

public class LeftMenuFragment extends Fragment {

	private List<LeftMenu> list = null;
	private ListView lv;

	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		initData();
	}

	/**
	 * 初始化数据
	 */
	private void initData() {
		list = new ArrayList<LeftMenu>();
		list.add(new LeftMenu(R.drawable.svip, "开通会员"));
		list.add(new LeftMenu(R.drawable.qianbao, "QQ钱包"));
		list.add(new LeftMenu(R.drawable.zhuangban, "个性装扮"));
		list.add(new LeftMenu(R.drawable.shoucang, "我的收藏"));
		list.add(new LeftMenu(R.drawable.xiangce, "我的相册"));
		list.add(new LeftMenu(R.drawable.wenjian, "我的文件"));
	}

	@Override
	public View onCreateView(LayoutInflater inflater, ViewGroup container,
			Bundle savedInstanceState) {
		View view = inflater.inflate(R.layout.left_menu, container, false);
		lv = (ListView) view.findViewById(R.id.left_menu_lv);
		LeftMenuAdapter adapter = new LeftMenuAdapter(list);
		lv.setAdapter(adapter);
		return view;
	}
}

Fragment整体也是比较简单的,在onCreate方法中拿到模拟数据,然后在onCreateView方法中给listview设置Adapter,在这里我们使用了一个JavaBean,这个JavaBean主要用来存储每一个item中的数据:

public class LeftMenu {

	private int imageView;
	private String text;

	public int getImageView() {
		return imageView;
	}

	public void setImageView(int imageView) {
		this.imageView = imageView;
	}

	public String getText() {
		return text;
	}

	public void setText(String text) {
		this.text = text;
	}

	public LeftMenu(int imageView, String text) {
		this.imageView = imageView;
		this.text = text;
	}

	public LeftMenu() {
	}

}

在这个JavaBean中,我们存储Image的资源id,然后在使用的时候直接调用这个资源id即可,再看看Adapter:

public class LeftMenuAdapter extends BaseAdapter {

	private List<LeftMenu> list;

	public LeftMenuAdapter(List<LeftMenu> list) {
		this.list = list;
	}

	@Override
	public int getCount() {
		return list.size();
	}

	@Override
	public Object getItem(int position) {
		return list.get(position);
	}

	@Override
	public long getItemId(int position) {
		return position;
	}

	@Override
	public View getView(int position, View convertView, ViewGroup parent) {
		ViewHolder holder = null;
		if (convertView == null) {
			convertView = LayoutInflater.from(parent.getContext()).inflate(
					R.layout.listview_item, null);
			holder = new ViewHolder();
			holder.iv = (ImageView) convertView.findViewById(R.id.left_iv);
			holder.tv = (TextView) convertView.findViewById(R.id.left_tv);
			convertView.setTag(holder);
		} else {
			holder = (ViewHolder) convertView.getTag();
		}
		holder.iv.setImageResource(list.get(position).getImageView());
		holder.tv.setText(list.get(position).getText());
		return convertView;
	}

	class ViewHolder {
		ImageView iv;
		TextView tv;
	}
}

这个Adapter很简单,我就不多说了。

nineoldandroids

这些都看完了,就该说说我们的MainActivity,首先我们得大概说说这种效果是怎么实现的,说到这里,我就得给大家介绍一个非常非常出名的动画类了,那就是nineoldandroids,我们在GitHub上可以直接下载到这个动画类的源码(https://github.com/JakeWharton/NineOldAndroids),如果你想用jar包,一会直接下载本项目源码就能拿到了。

nineoldandroids中有一些非常好用的方法,比如:

ViewHelper.setScaleX(View view, float scaleX)
ViewHelper.setScaleY(View view, float scaleY)

通过这个方法,我们可以对一个View进行缩放,第一个参数是我们要缩放的View,第二个参数是缩放比例,还有一个方法:

ViewHelper.setAlpha(View view, float alpha)

通过这个方法,我们可以设置一个View的透明度,第一个参数是我们要改变透明度的View,第二个参数是透明度。还有一个方法:

ViewHelper.setTranslationX(View view, float translationX)

通过这个方法,我们可以对一个View进行平移操作,第一个参数是要平移的View,第二参数是在X轴平移多少。还有一个方法:

ViewHelper.setScaleX(View view, float scaleX)
ViewHelper.setScaleY(View view, float scaleY)

通过这个方法,我们可以设置View变化时的一个轴心。

为什么介绍这几个方法呢?原因很简单,因为我们即将用到。

好了,介绍完这几个方法之后,我们的MainActivity就可以登场了。只需要简单的几个动画我们就可以实现QQ的这种侧拉效果了。

在MainActivity中我们先拿到DrawerLayout的一个实例:

drawerLayout = (DrawerLayout) this.findViewById(R.id.drawerLayout);

然后我们要给DrawerLayout设置一个监听事件,当菜单出场的时候我们调整主布局的位置:

		drawerLayout.setDrawerListener(new DrawerListener() {
			@Override
			public void onDrawerStateChanged(int newState) {
				Log.i("lenve", "onDrawerStateChanged");
			}

			@Override
			public void onDrawerSlide(View drawerView, float slideOffset) {
				slideAnim(drawerView, slideOffset);
				Log.i("lenve", "onDrawerSlide");
			}

			@Override
			public void onDrawerOpened(View drawerView) {
				Log.i("lenve", "onDrawerOpened");
			}

			@Override
			public void onDrawerClosed(View drawerView) {
				Log.i("lenve", "onDrawerClosed");
			}
		});

这个监听事件一共要实现其中的四个方法,看名字我们大概也知道这四个方法是干什么的,那我们看看这四个方法的执行时机:

当我们打开菜单的时候,先执行onDrawerStateChanged,然后不断执行onDrawerSlide,第三步会执行onDrawerOpened,最后执行onDrawerStateChanged,当我们关闭菜单的时候,先执行onDrawerStateChanged,然后不断执行onDrawerSlide,第三步会执行onDrawerClosed,最后执行onDrawerStateChanged,好了,方法的执行时机如果大家还有疑问可以通过打印日志来查看各个方法的执行时机。好了,我们的动画逻辑要在onDrawerSlide方法中来完成,先来说说这个方法的这两个参数,第一个参数是一个View,这个View其实就是左边侧拉菜单的View,第二参数是偏移量,可以简单理解为左边菜单拉出来的比例,它的取值是从0到1。介绍完这个之后,我们来看看slideAnim(drawerView, slideOffset);方法,看看最核心的代码有多么简单:

	private void slideAnim(View drawerView, float slideOffset) {
		View contentView = drawerLayout.getChildAt(0);
		// slideOffset表示菜单项滑出来的比例,打开菜单时取值为0->1,关闭菜单时取值为1->0
		float scale = 1 - slideOffset;
		float rightScale = 0.8f + scale * 0.2f;
		float leftScale = 1 - 0.3f * scale;

		ViewHelper.setScaleX(drawerView, leftScale);
		ViewHelper.setScaleY(drawerView, leftScale);
		ViewHelper.setAlpha(drawerView, 0.6f + 0.4f * (1 - scale));
		ViewHelper.setTranslationX(contentView, drawerView.getMeasuredWidth()
				* (1 - scale));
		ViewHelper.setPivotX(contentView, 0);
		ViewHelper.setPivotY(contentView, contentView.getMeasuredHeight() / 2);
		contentView.invalidate();
		ViewHelper.setScaleX(contentView, rightScale);
		ViewHelper.setScaleY(contentView, rightScale);
	}

好了,我们可以看到rightScale取值是从1到0.8,那么大家注意rightScale最后用在了contentView上,所以对应的一个显示效果就是contentView从最初大小变为最初大小的0.8倍,leftScale取值是从0.7到1。leftScale最后用在了drawerView,也就是左边的侧拉菜单View,那么对应的显示效果就是左边的菜单View一开始只有原本布局的0.7倍,在菜单慢慢往出滑动的时候,它逐渐变大,直到变为原本的大小(这个时候菜单View已经完全显示出来了)。另外几个动画设置都比较简单,大家参照我们上面对这几个方法的讲解来理解。

好了,搞定这些之后,还剩最后一个东东,就是左上角的点击事件,这个我们在上一篇博客中已经介绍过了,这里我就直接贴代码:

	public void onClick(View v) {
		drawerLayout.openDrawer(Gravity.LEFT);
	}

所有这些工作做完之后,一个仿QQ5.0侧拉的Demo已经出炉了。。。。

好了,今天就说到这里,大家有什么问题,可以留言讨论。

Demo下载https://github.com/lenve/QQDrawerLayout

版权声明:本文为博主原创文章,未经博主允许不得转载。若有错误地方,还望批评指正,不胜感激。

时间: 2024-10-12 21:51:40

使用DrawerLayout实现QQ5.0侧拉菜单效果的相关文章

Android 高仿 QQ5.0 侧滑菜单效果 自定义控件来袭【学习鸿洋_视频博客笔记总结】

学习鸿洋博客:http://blog.csdn.net/lmj623565791/article/details/39257409 学习鸿洋视频:慕课网视频 看看Android 高仿 QQ5.0 侧滑菜单效果 自定义控件实现效果: 技术上,继承HorizontalScrollView 加上自定义ViewGroup来实现: 1.onMeasure:决定内部View(子View)的宽和高,以及自己的宽和高 2.onLayout:决定子View的放置位置 3.onTouchEvent[监听动作] 自定

DragLayout: QQ5.0侧拉菜单的新特效

一.项目概要 1.1 项目效果如图: 1.2 需要使用到的技术   ViewDragHelper: 要实现和QQ5.0侧滑的特效,需要借助谷歌在2013年I/O大会上发布的ViewDragHelper类,提供这个类目的就是为了解决拖拽滑动问题 1.3 侧滑菜单的实现方式 1. SlidingMenu 第三方库 2. DrawerLayout v4包中的类 3. 自定义控件 1.4 一些回调方法 - tryCaptureView: 用来决定是否可以拖动 - clampViewPositionHor

Android 高仿 QQ5.0 侧滑菜单效果 自定义控件来袭

1.原理分析 首先对比一下我们上篇的实现距离QQ的效果还有多远: 差距还是蛮大的 区别1.QQ的内容区域会伴随菜单的出现而缩小 区别2.QQ的侧滑菜单给人的感觉是隐藏在内容的后面,而不是拖出来的感觉 区别3.QQ的侧滑菜单有一个缩放以及透明度的效果~ 那么我们如何能做到呢: 对于区别1:这个好办,我们可以在滑动的时候,不断的改变内容区域的大小:如何改变呢?我们在菜单出现的整个过程中,不断记录菜单显示的宽度与其总宽度的比值,是个从0到1的过程,然后把0~1转化为1~0.7(假设内容区域缩小至0.7

仿QQ5.0侧滑菜单效果

慕课网视频 今天我们来继承 HorizontalScrollView 实现比较炫酷的侧滑菜单效果 继承HorizontalScrollView的好处有两点: 1.不用在写 MOVE 事件 2.不用解决 和 ListView 的冲突 以下是实现步骤: 自定义 ViewGroup,实现它的几个方法 1.onMeasure       决定内部 View (子 View) 的宽和高,以及呢,自己的宽和高 /** * 设置 自己的宽和高 子 View 的宽和高 * * @param widthMeasu

彷QQ5.0侧滑菜单(自定义控件--SlideMenu的实现)

一般的侧滑的实现 ViewGroup  Menu + Content onTouchEvent MOVE:ViewGroup的leftMargin UP:根据显示菜单的高度,决定将其隐藏或者显示 1.Scroller 2.LeftMargin + Thread 彷QQ5.0侧滑菜单的实现,使用另外的一种方法,继承HorizontalScrollView 一.自定义ViewGroup 1.构造方法的选择,获得一些需要用到的值 2.onMeasure 计算子View的宽和高,以及设置自己的宽和高 3

Android QQ5.0侧滑菜单

背景 相信大家用过QQ的人,都会知道QQ有这样的一个功能,那就是他的菜单,感觉就像抽屉一样被拉出来的感觉,感觉很拉风啊,酷酷的,如果你有一种想要把它给弄清楚,想明白,这是一个好东西,你要把它变成自己的,那么现在就是你的机会,也在此恭喜你,你终于初步具有一个向中级工程师迈进的门票了,因为你已经跨出第一步了. 一:效果图,走一走,天下我有 二:实现步骤 1.菜单和内容布局的实现 2.自定义viewgroup 3.给注册监听事件,添加动画效果 三:示例源码 ①菜单布局 <?xml version=&quo

QQ5.0侧滑菜单

QQ5.0侧滑菜单 功能分类:社交    支持平台:Android    运行环境:Eclipse 开发语言:Java    开发工具:Eclipse     源码大小:1.06MB 源码简介 和 QQ 侧滑菜单类似效果,包括缩放.透明度变化.位置变化. 下载地址:http://www.dwz.cn/wYBof 源码运行截图  

【案例分享】仿QQ5.0侧滑菜单ResideMenu

本文由孙国威 原创.如需转载,请注明出处! 为了后续对这个项目进行优化,比如透明度动画.背景图的位移动画,以及性能上的优化. 我把这个项目上传到github上面,请大家随时关注. github地址https://github.com/sunguowei 最近项目要做一个QQ5.0的侧滑菜单效果,和传统的侧滑菜单存在着一些差异.想必大家都已经见识过了. 为了不重复发明轮子,先去github上面搜索了一番. 发现了几个类似的,但是还是有一些不同. 下面是搜索到的类似的开源项目. RESideMenu

【转】仿QQ5.0侧滑菜单ResideMenu

本文由孙国威 原创.如需转载,请注明出处! 原文:http://blog.csdn.net/manoel/article/details/39013095 为了后续对这个项目进行优化,比如透明度动画.背景图的位移动画,以及性能上的优化. 我把这个项目上传到github上面,请大家随时关注. github地址https://github.com/sunguowei 最近项目要做一个QQ5.0的侧滑菜单效果,和传统的侧滑菜单存在着一些差异.想必大家都已经见识过了. 为了不重复发明轮子,先去githu