天天看点

安卓侧滑菜单制作

引言,最近看很多项目都加入了侧滑菜单,但是相对完美的大家接触最多的还是QQ的侧滑菜单。这里,咱就不贴图片了。

    首先说下要用什么东西来实现。   根据安卓应用来说,所有的控件都可以继承view来实现,但是这样开发的效率较低下,而根据网上各路大神的讲解,发现用的最多的,相对开发最快的还是HorizontalScrollView 。

首先新建一个安卓项目,在项目包中,直接新建一个类(SlidingMenu)来继承 HorizontalScrollView 类。再直接实现方法,这里咱使用参数为:Context context, AttributeSet attrs 这两个的方法。这时候,我们点击类名,会看到完整的包名+类名如:com.acheng.cehuatest.SlidingMenu 。这个时候可以看到 com.acheng.cehuatest是我的包名,SlidingMenu 是我的类名。  我们直接将这个完整的包名+类名 (com.acheng.cehuatest.SlidingMenu ) 覆盖到我们的activity_main.xml 这个布局文件中的最外层,结果如图:

安卓侧滑菜单制作

同时删去activity_main.xml中最外层的android:paddingBottom、android:paddingLeft、android:paddingRight、android:paddingTop、tools:context、的这些属性。为了区分最外层和内部层,咱指定下最外层的background。接着,添加android:fadingEdge="none"、android:scrollbars="none"这两个属性(fadingEdge为边缘阴影,scrollbars为滚动条这两个要设置取消,具体不取消是什么效果大家伙可以自己看下),这里设置完成后,我们最外层就完成了。这时候我们只需要导入两个布局文件嵌套LinearLayout在里面,我们就可以看到两个布局文件已经并排排列了(界面需要并列,所以要又LinearLayout)。代码效果如上图。

当我们完成上面的操作的时候,初始布局完成 但是我们想要的侧滑效果并没达到。就需要我们在代码中进一步完成了。重点到了:

     当我们初步设定好布局文件时候,布局是并列实现的,但是这不是我们要的效果,这时候我们必须计算控件宽度,使用onMeasure方法。

由于我们的控件都是放置在线性布局(Linearlayout)中,所以我们使用getChildAt(0)拿到线性布局,代码语句为(LinearLayout wrapper = (LinearLayout) getChildAt(0);)(我们也可以使用ViewGroup来替代LinearLayout)。同样的,我们要拿到菜单和主界面布局,也是使用同样的方法来实现,如下:

// 界面布局完成 现在我们要计算时机手机宽度

 @Override

 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

//拿到线性布局的

  wrapper = (ViewGroup) getChildAt(0);

  // 菜单布局获取

  mMenu = (ViewGroup) wrapper.getChildAt(0);

  // 界面布局获取

  mMain = (ViewGroup) wrapper.getChildAt(1);

  // 菜单宽度

  mMenuWidth = mScreenWidth - mRightPadding;

  //由于要完成侧滑效果,所以在菜单显示的时候要设定菜单的宽度

  mMenu.getLayoutParams().width = mMenuWidth;

  // 主界面宽度

  mMain.getLayoutParams().width = mScreenWidth;

  super.onMeasure(widthMeasureSpec, heightMeasureSpec);

 }

(为了使我们的布局方便直接调用,都要设定成本布局class的全局变量)

在上面的代码中,有个语句是:mMenuWidth = mScreenWidth - mRightPadding;  这个语句是为了指定菜单(第一页面)显示的错位差值,错位的位置留给第二页面。所以我们需要在菜单界面刚显示的时候获得窗口宽度并作一些相关设定:

所以在新建类的时候的构造方法中添加设定,如下:

 public SlidingMenu(Context context, AttributeSet attrs) {

  super(context, attrs);

  WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);

  Display display = wm.getDefaultDisplay();

  DisplayMetrics outMetrics = new DisplayMetrics();

  display.getMetrics(outMetrics);

  // 屏幕宽度 数据类型为int

  mScreenWidth = outMetrics.widthPixels;

 }

这个时候  我们保存代码,运行项目  会发现项目成功完成了,我们也能侧滑  但是问题是:开始现实的不是主界面、侧滑的时候如果手指不完全划过屏幕界面会停在中间,这不是我们想要的完整效果。解决办法是使用onLayout设定主界面,使用onTouchEvent()做事件判定左右滑。代码如下:

//这是创建activity时打开的主界面。

@Override

 protected void onLayout(boolean changed, int l, int t, int r, int b) {

  super.onLayout(changed, l, t, r, b);

  //打开主界面

  this.scrollBy(mMenuWidth, 0);

 }

//这是滑动事件判定

public boolean onTouchEvent(MotionEvent ev) {

  switch (ev.getAction()) {

  case MotionEvent.ACTION_DOWN:

   downX = ev.getX();

   break;

  case MotionEvent.ACTION_UP:

   float upX = ev.getX();

   float chazhi = upX - downX;

   // 往左滑动

   if (chazhi < 0) {

    this.smoothScrollTo(mMenuWidth, 0);

   } else {

    this.smoothScrollTo(0, 0);

   }

   break;

  default:

   break;

  }

  return true;

 }

  到此我们的项目完成了。保存运行会发现侧滑效果实现了,唯一的就是没有那种侧滑过程中的界面渐变效果,少了一些酸爽的感觉。

 完整布局设定(包含滑动效果)的代码如下

package com.acheng.cehuatest;

import android.content.Context;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.view.Display;
import android.view.MotionEvent;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.widget.HorizontalScrollView;

public class SlidingMenu extends HorizontalScrollView {

	private ViewGroup wrapper;
	private ViewGroup mMenu;
	private ViewGroup mMain;
	private int mRightPadding = 100;
	private WindowManager wm;
	private int mScreenWidth;
	private int mMenuWidth;
	private float downX;

	public SlidingMenu(Context context, AttributeSet attrs) {
		super(context, attrs);
		wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
		Display display = wm.getDefaultDisplay();
		DisplayMetrics outMetrics = new DisplayMetrics();
		display.getMetrics(outMetrics);
		// 屏幕宽度
		mScreenWidth = outMetrics.widthPixels;

	}

	// 界面布局完成 现在我们要计算时机手机宽度
	@Override
	protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
		wrapper = (ViewGroup) getChildAt(0);
		// 菜单布局获取
		mMenu = (ViewGroup) wrapper.getChildAt(0);
		// 界面布局获取
		mMain = (ViewGroup) wrapper.getChildAt(1);
		// 菜单宽度
		mMenuWidth = mScreenWidth - mRightPadding;
		mMenu.getLayoutParams().width = mMenuWidth;
		// 主界面宽度
		mMain.getLayoutParams().width = mScreenWidth;

		super.onMeasure(widthMeasureSpec, heightMeasureSpec);
	}

	@Override
	public boolean onTouchEvent(MotionEvent ev) {
		switch (ev.getAction()) {
		case MotionEvent.ACTION_DOWN:
			downX = ev.getX();
			break;
		case MotionEvent.ACTION_UP:
			float upX = ev.getX();
			float chazhi = upX - downX;
			// 往左滑动
			if (chazhi < 0) {
				this.smoothScrollTo(mMenuWidth, 0);
			} else {
				this.smoothScrollTo(0, 0);
			}
			break;
		default:
			break;
		}

		return true;
	}
	
	@Override
	protected void onLayout(boolean changed, int l, int t, int r, int b) {
		super.onLayout(changed, l, t, r, b);
		//打开主界面
		this.scrollBy(mMenuWidth, 0);
	}
	

}
           

 布局配置文件代码如下:

<com.acheng.cehuatest.SlidingMenu xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/imenu"
    android:layout_width="wrap_content"
    android:layout_height="match_parent"
    android:background="@drawable/menu_bg"
    android:fadingEdge="none"
    android:scrollbars="none" >

    <LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="horizontal" >

        <!-- 菜单布局文件导入 -->

        <include layout="@layout/imenu" />
        <!-- 主界面布局 -->

        <include layout="@layout/imain" />
    </LinearLayout>

</com.acheng.cehuatest.SlidingMenu>
           

上面的菜单布局、主界面布局请随意创建。