Android抽屉效果的实现(不挤压,不覆盖)


抽屉效果,顾名思义就是可以像抽屉一样拉出来推进去,在Android中一般是通过滑动(从左到右,或者像帘子一样从上往下拉,或者通过某个按钮)来实现抽屉效果。其实Android的抽屉效果很简单(V4.0以上),使用了一个叫做DrawerLayout的类就可以轻松实现。废话少说,开始干活。

Android官网的教程(需要翻墙):http://developer.android.com/training/implementing-navigation/nav-drawer.html

首先说说我今天准备实现的目标:

1、抽屉效果,就是可以推拉的,这个是基本(我的是从左向右滑动)。

2、挤压效果。所谓挤压,就是当把抽屉拉出来是,原来的屏幕不会被遮挡或者覆盖,而是顺势向同样的方向移动相同的距离。之所以会做这一个效果,是因为官网的DrawerLayout是默认会挤压的。

效果如下图(由于不知道怎么手机动态截屏,只能上静态图了,有知道的可以告诉我,当然腾讯手机管家的试过了,不流畅)

下面是具体的实现步骤

1、布局文件mlayout.xml


    
    
	
		

需要注意的是:

(1)这里的根标签是android.support.v4.widget.DrawerLayout而不是普通的RelativeLayout之类的,里面有2个部分,第一个部分是The main content view,主界面,也就是抽屉还没打开之前的界面,这里官网用的是FrameLayout,其实也就是一个主界面的布局,所以都无所谓,我喜欢用RelativeLayout所以用它,主界面布局内根据自己的需要随意添加空间;

(2)第二个部分就是抽屉的界面,布局也是随意的。我用的是ListView,因为一般拉出来的抽屉,都是系统的一些设置和检查更新什么的。

(3)主界面布局宽和高,必须match_parent,抽屉的高也是,抽屉的宽度不得超过320dp(官方规定的),否则会全部遮挡(或挤压)掉主布局。

(4)抽屉有个属性是layout_gravity,这个是指抽屉出来的方向,必须设置。一般可以设置left、end、right、start(不过貌似我出来start,其他的感觉都会使应用崩溃)

2、主类MainActivity.java,其中滑动和点击按钮都可以打开抽屉

package com.exam.drawerdemo;

import android.app.Activity;
import android.os.Bundle;
import android.support.v4.widget.DrawerLayout;
import android.support.v4.widget.DrawerLayout.DrawerListener;
import android.view.Gravity;
import android.view.View;
import android.view.View.MeasureSpec;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.ListView;
import android.widget.RelativeLayout;

public class MainActivity extends Activity {

	DrawerLayout mDrawerLayout;
	Button mButton;
	ListView mDrawerList;
	String[] str={"AA","BB","CC","DD","EE","FF"};
	RelativeLayout mRelativeLayout;
	int mDrawerWidth;//抽屉全部拉出来时的宽度
	float scrollWidth;//抽屉被拉出部分的宽度
	
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.mlayout);

		
		mDrawerLayout=(DrawerLayout)findViewById(R.id.drawer_layout);
		mRelativeLayout=(RelativeLayout) findViewById(R.id.content_frame);
		
		//填充抽屉ListView的内容
		mDrawerList=(ListView)findViewById(R.id.left_drawer);
		mDrawerList.setAdapter(new ArrayAdapter(getApplicationContext(),
				android.R.layout.simple_expandable_list_item_1,str));
		//测量抽屉的宽度和高度
		measureView(mDrawerList);
		mDrawerWidth=mDrawerList.getMeasuredWidth();
		
		mButton=(Button)findViewById(R.id.mButton);
		mButton.setOnClickListener(new OnClickListener() {
			
			@Override
			public void onClick(View v) {
				mDrawerLayout.openDrawer(Gravity.LEFT);
			}
		});
		
		//必须给抽屉设置监听事件
		mDrawerLayout.setDrawerListener(new DrawerListener() {
			
			@Override
			public void onDrawerStateChanged(int arg0) {
				
			}
			
			//抽屉被拉出来或者推回去
			@Override
			public void onDrawerSlide(View arg0, float arg1) {
				//因为arg1的范围是0.0-1.0,是一个相对整个抽屉宽度的比例
				//所以要准换成
				scrollWidth=arg1*mDrawerWidth;
				//setScroll中的参数,正数表示向左移动,负数向右
				mRelativeLayout.setScrollX((int)(-1*scrollWidth));
				
			}
			
			@Override
			public void onDrawerOpened(View arg0) {
				
			}
			
			@Override
			public void onDrawerClosed(View arg0) {
				
			}
		});

	}
	
	/**
	 * 此方法可以多次被不同的View对象调用。
	 * 在调用该方法后,
	 * 使用View对象的getMessuredHeight()获高度(单位px)
	 * @param child 需要测量高度和宽度的View对象,
	 */
	private void measureView(View child) {    
        ViewGroup.LayoutParams params = child.getLayoutParams();    
        if (params == null) {    
            params = new ViewGroup.LayoutParams(    
                    ViewGroup.LayoutParams.MATCH_PARENT,    
                    ViewGroup.LayoutParams.WRAP_CONTENT);    
        }    
        int childWidthSpec = ViewGroup.getChildMeasureSpec(0, 0 + 0,    
                params.width);    
        int lpHeight = params.height;    
        int childHeightSpec;    
        if (lpHeight > 0) {    
            childHeightSpec = MeasureSpec.makeMeasureSpec(lpHeight,    
                    MeasureSpec.EXACTLY);    
        } else {    
            childHeightSpec = MeasureSpec.makeMeasureSpec(0,    
                    MeasureSpec.UNSPECIFIED);    
        }    
        child.measure(childWidthSpec, childHeightSpec);    
    }    
	

}

再啰嗦几句:(1)挤压效果的实现,其实就是通过监测抽屉向右滑动的距离,然后主界面也通过滑动相应距离实现的(setScroll,负数表示向右);(2)DrawerLayout有个方法openDrawer(Gravity arg)也可以打开抽屉,其关闭则是closeDrawer();但是用了按钮打开抽屉(比如我上面的),不影响滑动也可以打开。

有问题和建议的,或者如上面说的有比较好的动态截屏方法的,欢迎再下面留言

源码地址http://download.csdn.net/detail/programming2012/8554275