现在的位置: 首页 > 综合 > 正文

人人滑动式菜单

2013年02月01日 ⁄ 综合 ⁄ 共 6272字 ⁄ 字号 评论关闭

文章出处:http://blog.csdn.net/knlnzhao/article/details/7920766

http://www.eoeandroid.com/forum.php?mod=viewthread&tid=183314

最近发现有好多软件都采用了滑动式菜单的效果,例如人人,云中书城等等。这种效果给人以耳目一新的感觉,所以自己也特别想实现一个。由于鄙人才疏学浅,属于菜鸟级的人物,第一次想到的当然是在网上找相关的demo。百度过来谷歌过去,发现相关的demo少的可怜,只找到一个某位大牛jfeinstein10写的SlidingMenu库。欣喜之余,下载下来看看,发现真心麻烦啊,于是下定决心自己写一个。

实现SlidingMenu的方法如下:

自定义ViewGroup类ViewFlipper如下:

 
package knlnzhao.slidingmenu;

import android.content.Context;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Scroller;

public class FlipperView extends ViewGroup {

	private int distance;// 完全显示菜单需要移动的距离
	private View menu;
	private View main;
	private Scroller scroller;
	private boolean menuVisible = false;

	public FlipperView(Context context, AttributeSet attrs) {
		super(context, attrs);
		// TODO Auto-generated constructor stub
		scroller = new Scroller(context);
	}

	@Override
	protected void onLayout(boolean changed, int l, int t, int r, int b) {
		// TODO Auto-generated method stub

		distance = getWidth() * 4 / 5;// 获得平滑移动的距离,也是菜单的宽度

		// 布局菜单和主页面视图
		menu = getChildAt(0);// 获得菜单视图
		menu.setVisibility(VISIBLE);
		menu.measure(
				MeasureSpec.makeMeasureSpec(distance, MeasureSpec.EXACTLY),
				MeasureSpec.makeMeasureSpec(getWidth(), MeasureSpec.EXACTLY));
		menu.layout(-distance, 0, 0, getHeight());

		main = getChildAt(1);// 获得主页面视图
		main.setVisibility(VISIBLE);
		// 相当于fill_parent
		main.measure(
				MeasureSpec.makeMeasureSpec(getWidth(), MeasureSpec.EXACTLY),
				MeasureSpec.makeMeasureSpec(getHeight(), MeasureSpec.EXACTLY));
		main.layout(0, 0, getWidth(), getHeight());

	}

	public void showMenu() {
		if (!menuVisible) {
			scroller.startScroll(getScrollX(), 0, -distance, 0, 300);
			invalidate();
			menuVisible = true;
		}

	}

	public void hideMenu() {
		if (menuVisible) {
			scroller.startScroll(getScrollX(), 0, distance, 0, 300);
			invalidate();
			menuVisible = false;
		}

	}

	@Override
	public void computeScroll() {
		// TODO Auto-generated method stub
		// 当滚动没有完成
		if (scroller.computeScrollOffset()) {
			scrollTo(scroller.getCurrX(), 0);
			postInvalidate();
		}
	}

} 

ViewFlipper中包含有两个子布局,一个子布局是menu布局,另一个子布局是主要显示内容布局。在ViewFlipper的onLayout函数中,对这两个子布局进行布局。显示菜单和隐藏菜单是有两个函数实现,分别是

 
public void showMenu() {
		if (!menuVisible) {
			scroller.startScroll(getScrollX(), 0, -distance, 0, 300);
			invalidate();
			menuVisible = true;
		}

	}

	public void hideMenu() {
		if (menuVisible) {
			scroller.startScroll(getScrollX(), 0, distance, 0, 300);
			invalidate();
			menuVisible = false;
		}

	} 

这两个函数都用到了ViewGroup中负责移动子视图的Scroller类。通过调用函数

startScroll(int startX, int startY, int dx, int dy, int duration) 

 

来实现菜单移动的动画效果。这个函数里面的四个参数比较令人费解,仔细琢磨解释一下,如果理解不对,也请各位大牛指正。

startX:在水平方向上,已经滚动的距离。

startY:在竖直方向上,已经滚动的距离。

dx:在水平方向需要滚动的总距离,注意是总距离,包括已经滚动的距离。

dy:在竖直方向上需要滚动的总距离。

这样,自定义的ViewGroup类ViewFlipper就完成了。接下来就要填写内容,包括菜单和主页面了。

菜单menu.xml如下:

<?xml version="1.0" encoding="utf-8"?>
<linearlayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="200.0dip" android:layout_height="fill_parent" android:orientation="vertical" android:background="@color/dark_blue">
    
    <button android:id="@+id/close" android:layout_height="wrap_content" android:layout_width="wrap_content" android:text="关闭菜单"/>
    
    <textview android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="这是菜单" android:textsize="20.0sp" android:textcolor="#ff000000" android:layout_gravity="center"/>
 </linearlayout>

主页面content.xml如下

<?xml version="1.0" encoding="utf-8"?>
<linearlayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="200.0dip" android:layout_height="fill_parent" android:orientation="vertical" android:background="@color/dark_blue">
    
    <button android:id="@+id/close" android:layout_height="wrap_content" android:layout_width="wrap_content" android:text="打开菜单"/>
    
    <textview android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="这是主页面" android:textsize="20.0sp" android:textcolor="#ff000000" android:layout_gravity="center"/>
</linearlayout>

在SlidingMenuActivity的内容描述文件main.xml中做如下定义:

 <?xml version="1.0" encoding="utf-8"?>
<linearlayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical">
    
    <knlnzhao slidingmenu="" flipperview="" android:id="@+id/flipper" android:layout_width="fill_parent" android:layout_height="fill_parent">

</knlnzhao></linearlayout>

在启动的Activity中做如下代码:

package knlnzhao.slidingmenu;

import android.app.Activity;
import android.os.Bundle;
import android.view.GestureDetector;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.GestureDetector.OnGestureListener;
import android.widget.Button;

public class SlidingMenuActivity extends Activity {
	private FlipperView flipper;
	private Button open;
	private Button close;
	private GestureDetector detector;

	/** Called when the activity is first created. */
	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);

		flipper = (FlipperView) findViewById(R.id.flipper);
		View menu = LayoutInflater.from(this).inflate(R.layout.menu, null);
		View content = LayoutInflater.from(this)
				.inflate(R.layout.content, null);
		flipper.addView(menu);
		flipper.addView(content);

		open = (Button) content.findViewById(R.id.open);
		close = (Button) menu.findViewById(R.id.close);

		open.setOnClickListener(new View.OnClickListener() {

			public void onClick(View v) {
				// TODO Auto-generated method stub
				flipper.showMenu();
			}
		});

		close.setOnClickListener(new View.OnClickListener() {

			public void onClick(View v) {
				// TODO Auto-generated method stub
				flipper.hideMenu();
			}
		});

		detector = new GestureDetector(new OnGestureListener() {

			public boolean onSingleTapUp(MotionEvent e) {
				// TODO Auto-generated method stub
				return false;
			}

			public void onShowPress(MotionEvent e) {
				// TODO Auto-generated method stub

			}

			public boolean onScroll(MotionEvent e1, MotionEvent e2,
					float distanceX, float distanceY) {
				// TODO Auto-generated method stub
				return false;
			}

			public void onLongPress(MotionEvent e) {
				// TODO Auto-generated method stub

			}

			public boolean onFling(MotionEvent e1, MotionEvent e2,
					float velocityX, float velocityY) {
				// TODO Auto-generated method stub
				// 判断是否达到最小滑动速度,取绝对值
				if (Math.abs(velocityX) > ViewConfiguration.get(
						SlidingMenuActivity.this).getScaledMinimumFlingVelocity()) {
					if (velocityX > 0 ) {//向右滑动
						flipper.showMenu();
					} else if (velocityX < 0) {//向左滑动
						flipper.hideMenu();
					}
				}
				return true;
			}

			public boolean onDown(MotionEvent e) {
				// TODO Auto-generated method stub
				return false;
			}
		});
		
	}

	@Override
	public boolean onTouchEvent(MotionEvent event) {
		// TODO Auto-generated method stub
		detector.onTouchEvent(event);
		return true;
	}
} 

 

主要包括对FlipperView进行填充,滑动操作等等。

奉上运行效果图:

抱歉!评论已关闭.