文章出处: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"?>
- lt;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">
- lt;/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进行填充,滑动操作等等。
奉上运行效果图: