zoukankan      html  css  js  c++  java
  • Android 滑动菜单SlidingMenu

    首先我们看下面视图:

    这种效果大家都不陌生,网上好多都说是仿人人网的,估计人家牛逼出来的早吧,我也参考了一一些例子,实现起来有三种方法,我下面简单介绍下:

    方法一:其实就是对GestureDetector手势的应用及布局文件的设计.

    布局文件main.xml    采用RelativeLayout布局.

    <?xml version="1.0" encoding="utf-8"?>
    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:orientation="vertical" >
    
        <LinearLayout
            android:id="@+id/layout_right"
            android:layout_width="fill_parent"
            android:layout_height="fill_parent"
            android:layout_marginLeft="50dp"
            android:orientation="vertical" >
    
            <AbsoluteLayout
                android:layout_width="fill_parent"
                android:layout_height="wrap_content"
                android:background="@color/grey21"
                android:padding="10dp" >
    
                <TextView
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:text="设置"
                    android:textColor="@android:color/background_light"
                    android:textSize="20sp" />
            </AbsoluteLayout>
    
            <ListView
                android:id="@+id/lv_set"
                android:layout_width="fill_parent"
                android:layout_height="fill_parent"
                android:layout_weight="1" >
            </ListView>
        </LinearLayout>
    
        <LinearLayout
            android:id="@+id/layout_left"
            android:layout_width="fill_parent"
            android:layout_height="fill_parent"
            android:background="@color/white"
            android:orientation="vertical" >
    
            <RelativeLayout
                android:layout_width="fill_parent"
                android:layout_height="wrap_content"
                android:background="@drawable/nav_bg" >
    
                <ImageView
                    android:id="@+id/iv_set"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_alignParentRight="true"
                    android:layout_alignParentTop="true"
                    android:src="@drawable/nav_setting" />
    
                <TextView
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_centerInParent="true"
                    android:text=""
                    android:textColor="@android:color/background_light"
                    android:textSize="20sp" />
            </RelativeLayout>
    
            <ImageView
                android:id="@+id/iv_set"
                android:layout_width="fill_parent"
                android:layout_height="fill_parent"
                android:scaleType="fitXY"
                android:src="@drawable/bg_guide_5" />
        </LinearLayout>
    
    </RelativeLayout>

    ayout_right:这个大布局文件,layout_left:距离左边50dp像素.(我们要移动的是layout_left).

    看到这个图我想大家都很清晰了吧,其实:我们就是把layout_left这个布局控件整理向左移动,至于移动多少,就要看layout_right有多宽了。layout_left移动到距离左边的边距就是layout_right的宽及-MAX_WIDTH.相信大家都理解.

    布局文件就介绍到这里,下面看代码.

    /***
         * 初始化view
         */
        void InitView() {
            layout_left = (LinearLayout) findViewById(R.id.layout_left);
            layout_right = (LinearLayout) findViewById(R.id.layout_right);
            iv_set = (ImageView) findViewById(R.id.iv_set);
            lv_set = (ListView) findViewById(R.id.lv_set);
            lv_set.setAdapter(new ArrayAdapter<String>(this, R.layout.item,
                    R.id.tv_item, title));
            lv_set.setOnItemClickListener(new OnItemClickListener() {
    
                @Override
                public void onItemClick(AdapterView<?> parent, View view,
                        int position, long id) {
                    Toast.makeText(MainActivity.this, title[position], 1).show();
                }
            });
            layout_left.setOnTouchListener(this);
            iv_set.setOnTouchListener(this);
            mGestureDetector = new GestureDetector(this);
            // 禁用长按监听
            mGestureDetector.setIsLongpressEnabled(false);
            getMAX_WIDTH();
        }

    这里要对手势进行监听,我想大家都知道怎么做,在这里我要说明一个方法

    /***
         * 获取移动距离 移动的距离其实就是layout_left的宽度
         */
        void getMAX_WIDTH() {
            ViewTreeObserver viewTreeObserver = layout_left.getViewTreeObserver();
            // 获取控件宽度
            viewTreeObserver.addOnPreDrawListener(new OnPreDrawListener() {
                @Override
                public boolean onPreDraw() {
                    if (!hasMeasured) {
                        window_width = getWindowManager().getDefaultDisplay()
                                .getWidth();
                        RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) layout_left
                                .getLayoutParams();
                        layoutParams.width = window_width;
                        layout_left.setLayoutParams(layoutParams);
                        MAX_WIDTH = layout_right.getWidth();
                        Log.v(TAG, "MAX_WIDTH=" + MAX_WIDTH + "width="
                                + window_width);
                        hasMeasured = true;
                    }
                    return true;
                }
            });
    
        }

    在这里我们要获取屏幕的宽度,并将屏幕宽度设置给layout_left这个控件,为什么要这么做呢因为如果不把该控件宽度写死的话,那么系统将认为layout_left会根据不同环境宽度自动适应,也就是说我们通过layout_left.getLayoutParams动态移动该控件的时候,该控件会伸缩而不是移动。描述的有点模糊,大家请看下面示意图就明白了.

    我们不为layout_left定义死宽度效果:


    getLayoutParams可以很清楚看到,layout_left被向左拉伸了,并不是我们要的效果.

    还有一种解决办法就是我们在配置文件中直接把layout_left宽度写死,不过这样不利于开发,因为分辨率的问题.因此就用ViewTreeObserver进行对layout_left设置宽度.

    ViewTreeObserver,这个类主要用于对布局文件的监听.强烈建议同学们参考这篇文章 android ViewTreeObserver详细讲解,相信让你对ViewTreeObserver有更一步的了解.

    其他的就是对GestureDetector手势的应用,下面我把代码贴出来:

    package com.jj.slidingmenu;
    
    import android.app.Activity;
    import android.os.AsyncTask;
    import android.os.Bundle;
    import android.util.Log;
    import android.view.GestureDetector;
    import android.view.KeyEvent;
    import android.view.MotionEvent;
    import android.view.View;
    import android.view.ViewTreeObserver;
    import android.view.ViewTreeObserver.OnPreDrawListener;
    import android.view.Window;
    import android.view.View.OnTouchListener;
    import android.widget.AdapterView;
    import android.widget.AdapterView.OnItemClickListener;
    import android.widget.ArrayAdapter;
    import android.widget.ImageView;
    import android.widget.LinearLayout;
    import android.widget.ListView;
    import android.widget.RelativeLayout;
    import android.widget.Toast;
    import android.widget.LinearLayout.LayoutParams;
    
    /***
     * 滑动菜单
     * 
     * @author jjhappyforever...
     * 
     */
    public class MainActivity extends Activity implements OnTouchListener,
            GestureDetector.OnGestureListener {
        private boolean hasMeasured = false;// 是否Measured.
        private LinearLayout layout_left;
        private LinearLayout layout_right;
        private ImageView iv_set;
        private ListView lv_set;
    
        /** 每次自动展开/收缩的范围 */
        private int MAX_WIDTH = 0;
        /** 每次自动展开/收缩的速度 */
        private final static int SPEED = 30;
    
        private GestureDetector mGestureDetector;// 手势
        private boolean isScrolling = false;
        private float mScrollX; // 滑块滑动距离
        private int window_width;// 屏幕的宽度
    
        private String TAG = "jj";
    
        private String title[] = { "待发送队列", "同步分享设置", "编辑我的资料", "找朋友", "告诉朋友",
                "节省流量", "推送设置", "版本更新", "意见反馈", "积分兑换", "精品应用", "常见问题", "退出当前帐号" };
    
        /***
         * 初始化view
         */
        void InitView() {
            layout_left = (LinearLayout) findViewById(R.id.layout_left);
            layout_right = (LinearLayout) findViewById(R.id.layout_right);
            iv_set = (ImageView) findViewById(R.id.iv_set);
            lv_set = (ListView) findViewById(R.id.lv_set);
            lv_set.setAdapter(new ArrayAdapter<String>(this, R.layout.item,
                    R.id.tv_item, title));
            lv_set.setOnItemClickListener(new OnItemClickListener() {
    
                @Override
                public void onItemClick(AdapterView<?> parent, View view,
                        int position, long id) {
                    Toast.makeText(MainActivity.this, title[position], 1).show();
                }
            });
            layout_left.setOnTouchListener(this);
            iv_set.setOnTouchListener(this);
            mGestureDetector = new GestureDetector(this);
            // 禁用长按监听
            mGestureDetector.setIsLongpressEnabled(false);
            getMAX_WIDTH();
        }
    
        /***
         * 获取移动距离 移动的距离其实就是layout_left的宽度
         */
        void getMAX_WIDTH() {
            ViewTreeObserver viewTreeObserver = layout_left.getViewTreeObserver();
            // 获取控件宽度
            viewTreeObserver.addOnPreDrawListener(new OnPreDrawListener() {
                @Override
                public boolean onPreDraw() {
                    if (!hasMeasured) {
                        window_width = getWindowManager().getDefaultDisplay()
                                .getWidth();
                        RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) layout_left
                                .getLayoutParams();
                        // layoutParams.width = window_width;
                        layout_left.setLayoutParams(layoutParams);
                        MAX_WIDTH = layout_right.getWidth();
                        Log.v(TAG, "MAX_WIDTH=" + MAX_WIDTH + "width="
                                + window_width);
                        hasMeasured = true;
                    }
                    return true;
                }
            });
    
        }
    
        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            requestWindowFeature(Window.FEATURE_NO_TITLE);
            setContentView(R.layout.main);
            InitView();
    
        }
    
        // 返回键
        @Override
        public boolean onKeyDown(int keyCode, KeyEvent event) {
            if (KeyEvent.KEYCODE_BACK == keyCode && event.getRepeatCount() == 0) {
                RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) layout_left
                        .getLayoutParams();
                if (layoutParams.leftMargin < 0) {
                    new AsynMove().execute(SPEED);
                    return false;
                }
            }
    
            return super.onKeyDown(keyCode, event);
        }
    
        @Override
        public boolean onTouch(View v, MotionEvent event) {
            // 松开的时候要判断,如果不到半屏幕位子则缩回去,
            if (MotionEvent.ACTION_UP == event.getAction() && isScrolling == true) {
                RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) layout_left
                        .getLayoutParams();
                // 缩回去
                if (layoutParams.leftMargin < -window_width / 2) {
                    new AsynMove().execute(-SPEED);
                } else {
                    new AsynMove().execute(SPEED);
                }
            }
    
            return mGestureDetector.onTouchEvent(event);
        }
    
        @Override
        public boolean onDown(MotionEvent e) {
            mScrollX = 0;
            isScrolling = false;
            // 将之改为true,不然事件不会向下传递.
            return true;
        }
    
        @Override
        public void onShowPress(MotionEvent e) {
    
        }
    
        /***
         * 点击松开执行
         */
        @Override
        public boolean onSingleTapUp(MotionEvent e) {
            RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) layout_left
                    .getLayoutParams();
            // 左移动
            if (layoutParams.leftMargin >= 0) {
                new AsynMove().execute(-SPEED);
            } else {
                // 右移动
                new AsynMove().execute(SPEED);
            }
    
            return true;
        }
    
        /***
         * e1 是起点,e2是终点,如果distanceX=e1.x-e2.x>0说明向左滑动。反之亦如此.
         */
        @Override
        public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX,
                float distanceY) {
            isScrolling = true;
            mScrollX += distanceX;// distanceX:向左为正,右为负
            RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) layout_left
                    .getLayoutParams();
            layoutParams.leftMargin -= mScrollX;
            if (layoutParams.leftMargin >= 0) {
                isScrolling = false;// 拖过头了不需要再执行AsynMove了
                layoutParams.leftMargin = 0;
    
            } else if (layoutParams.leftMargin <= -MAX_WIDTH) {
                // 拖过头了不需要再执行AsynMove了
                isScrolling = false;
                layoutParams.leftMargin = -MAX_WIDTH;
            }
            layout_left.setLayoutParams(layoutParams);
            return false;
        }
    
        @Override
        public void onLongPress(MotionEvent e) {
    
        }
    
        @Override
        public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
                float velocityY) {
            return false;
        }
    
        class AsynMove extends AsyncTask<Integer, Integer, Void> {
    
            @Override
            protected Void doInBackground(Integer... params) {
                int times = 0;
                if (MAX_WIDTH % Math.abs(params[0]) == 0)// 整除
                    times = MAX_WIDTH / Math.abs(params[0]);
                else
                    times = MAX_WIDTH / Math.abs(params[0]) + 1;// 有余数
    
                for (int i = 0; i < times; i++) {
                    publishProgress(params[0]);
                    try {
                        Thread.sleep(Math.abs(params[0]));
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
    
                return null;
            }
    
            /**
             * update UI
             */
            @Override
            protected void onProgressUpdate(Integer... values) {
                RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) layout_left
                        .getLayoutParams();
                // 右移动
                if (values[0] > 0) {
                    layoutParams.leftMargin = Math.min(layoutParams.leftMargin
                            + values[0], 0);
                    Log.v(TAG, "移动右" + layoutParams.rightMargin);
                } else {
                    // 左移动
                    layoutParams.leftMargin = Math.max(layoutParams.leftMargin
                            + values[0], -MAX_WIDTH);
                    Log.v(TAG, "移动左" + layoutParams.rightMargin);
                }
                layout_left.setLayoutParams(layoutParams);
    
            }
    
        }
    
    }

    上面代码注释已经很明确,相信大家都看的明白,我就不过多解释了。

    效果图:截屏出来有点卡,不过在手机虚拟机上是不卡的.

  • 相关阅读:
    linux下的内存映射函数mmap详解及示例代码
    Android平台上使用属性系统(property system)
    Android筆記
    Android Prelink
    DataGridView BindingSource BindNavigator
    可排序的ListView
    开源2D绘图组件ZedGraph
    BackgroundWorker示例
    级联datagridview 利用datarelation和bindingsource
    继承DataGridView
  • 原文地址:https://www.cnblogs.com/zhujiabin/p/4282170.html
Copyright © 2011-2022 走看看