Android -- SlidingMenu

來源:互聯網
上載者:User

Android -- SlidingMenu
實現原理                                                                               在一個Activity的布局中需要有兩部分,一個是菜單(menu)的布局,一個是內容(content)的布局。兩個布局橫向排列,菜單布局在左,內容布局在右。初始化的時候將菜單布局向左位移,以至於能夠完全隱藏,這樣內容布局就會完全顯示在Activity中。然後通過監聽手指滑動事件,來改變菜單布局的左位移距離,從而控制功能表布局的顯示和隱藏。 布局                                                                                    複製代碼<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:tools="http://schemas.android.com/tools"    android:layout_width="match_parent"    android:layout_height="match_parent"    android:orientation="horizontal"    tools:context=".MyActivity">     <LinearLayout        android:id="@+id/menu"        android:layout_width="fill_parent"        android:layout_height="fill_parent"        android:background="#ff00ff00"        android:orientation="vertical"></LinearLayout>     <LinearLayout        android:id="@+id/content"        android:layout_width="fill_parent"        android:layout_height="fill_parent"        android:background="#ffff0000"        android:orientation="vertical"></LinearLayout> </LinearLayout>複製代碼這個布局檔案的最外層布局是一個LinearLayout,排列方向是水平方向排列。這個LinearLayout下面嵌套了兩個子LinearLayout,分別就是菜單的布局和內容的布局。這裡為了要讓布局盡量簡單,菜單布局和內容布局裡面沒有加入任何控制項。 Code                                                                                    複製代碼public class MyActivity extends Activity implements View.OnTouchListener {    /**     * 手指每單位時間滑動200個像素     */    private static final int SPEED = 200;    /**     * 螢幕寬度     */    private int mScreenWidth;    /**     * menu的layout     */    private LinearLayout mMenuLayout;    /**     * content的layout     */    private LinearLayout mContentLayout;    /**     * menu的layout的Paramters     */    private LinearLayout.LayoutParams mMenuParams;    /**     * menu完全顯示的時候給content的寬度值     */    private int mMenuPadding = 80;    /**     * menu最多滑到左邊緣,值由menu布局的寬度決定,marginLeft到達此值之後,不能在減少     */    private int mLeftEdge;    /**     * 測速度的對象     */    private VelocityTracker mVelocityTracker;    /**     * 手指按下的X座標     */    private float mXDown;    /**     * 手指移動時候的X座標     */    private float mXMove;    /**     * 手指抬起的X座標     */    private float mXUp;    /**     * menu是否再顯示     */    private boolean mIsMenuVisible = false;      @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_my);        initViewsAndValues();        mContentLayout.setOnTouchListener(this);    }     /**     * 初始化menu和content並且設定他們的位置     */    private void initViewsAndValues() {        //得到windowManager        WindowManager window = (WindowManager) getSystemService(Context.WINDOW_SERVICE);        //得到螢幕寬度        mScreenWidth = window.getDefaultDisplay().getWidth();        //找到控制項        mMenuLayout = (LinearLayout) findViewById(R.id.menu);        mContentLayout = (LinearLayout) findViewById(R.id.content);        //得到menu的paramter        mMenuParams = (LinearLayout.LayoutParams) mMenuLayout.getLayoutParams();        //將menu的寬度設定為螢幕寬度減去mMenuPading        mMenuParams.width = mScreenWidth - mMenuPadding;        //左邊緣的值複製為menu寬度的負數,這樣的話就可以將menu隱藏        mLeftEdge = -mMenuParams.width;        //將margin設定為mLeftEdge        mMenuParams.leftMargin = mLeftEdge;        //將content顯示再螢幕上        mContentLayout.getLayoutParams().width = mScreenWidth;    }      @Override    public boolean onTouch(View view, MotionEvent event) {        createVelocityTracker(event);        switch (event.getAction()) {            case MotionEvent.ACTION_DOWN:                //記錄X座標                mXDown = event.getRawX();                break;            case MotionEvent.ACTION_MOVE:                mXMove = event.getRawX();                int distanceX = (int) (mXMove - mXDown);                if (mIsMenuVisible) {                    mMenuParams.leftMargin = distanceX;                } else {                    mMenuParams.leftMargin = mLeftEdge + distanceX;                }                if (mMenuParams.leftMargin < mLeftEdge) {                    //因為leftEdge是負數,就是menu已經隱藏完畢了,不能再往左隱藏了                    mMenuParams.leftMargin = mLeftEdge;                } else if (mMenuParams.leftMargin > 0) {                    //menu顯示完全了,不能再往右移動了                    mMenuParams.leftMargin = 0;                }                mMenuLayout.setLayoutParams(mMenuParams);                break;            case MotionEvent.ACTION_UP:                mXUp = event.getRawX();                if (wantToShowMenu()) {                    if (shouldScrollToMenu()) {                        scrollToMenu();                    } else {                        //條件不滿足,把menu繼續隱藏掉                        scrollToContent();                    }                } else if (wantToShowContent()) {                    if (shouldScrollToContent()) {                        scrollToContent();                    } else {                        scrollToMenu();                    }                }                break;        }        recycleVelocityTracker();        return true;    }     /**     * 建立VelocityTracker對象,針對於content的介面的滑動事件     *     * @param event     */    private void createVelocityTracker(MotionEvent event) {        if (null == mVelocityTracker) {            mVelocityTracker = VelocityTracker.obtain();        }        mVelocityTracker.addMovement(event);    }     /**     * 判斷手勢是不是想要顯示Content && menu處於顯示狀態     *     * @return     */    private boolean wantToShowContent() {        return mXUp - mXDown < 0 && mIsMenuVisible;    }     /**     * 是不是要顯示menu && menu處於隱藏狀態     *     * @return     */    private boolean wantToShowMenu() {        return mXUp - mXDown > 0 && !mIsMenuVisible;    }     /**     * 是否應該滑動出menu     *     * @return     */    private boolean shouldScrollToMenu() {        return mXUp - mXDown > mScreenWidth / 2 || getScrollVelocity() > SPEED;    }     /**     * 是否應該讓content全部顯示出來     *     * @return     */    private boolean shouldScrollToContent() {        return mXDown - mXUp < mScreenWidth / 2 || getScrollVelocity() > SPEED;    }     /**     * 顯示出menu     */    private void scrollToMenu() {        new ScrollAsyncTask().execute(30);    }     /**     * 隱藏掉menu     */    private void scrollToContent() {        new ScrollAsyncTask().execute(-30);    }      /**     * 得到手指滑動速度,每秒移動多少單位像素     *     * @return     */    private int getScrollVelocity() {        mVelocityTracker.computeCurrentVelocity(1000);        int velocity = (int) mVelocityTracker.getXVelocity();        return Math.abs(velocity);    }     /**     * 回收VelocityTracker對象。     */    private void recycleVelocityTracker() {        mVelocityTracker.recycle();        mVelocityTracker = null;    }     class ScrollAsyncTask extends AsyncTask<Integer, Integer, Integer> {         @Override        protected Integer doInBackground(Integer[] speed) {            //得到當前margin            int leftMargin = mMenuParams.leftMargin;            //不斷更改margin的值            while (true) {                leftMargin = leftMargin + speed[0];                if (leftMargin > 0) {                    leftMargin = 0;                    break;                }                if (leftMargin < mLeftEdge) {                    leftMargin = mLeftEdge;                    break;                }                publishProgress(leftMargin);                sleep();            }            if (speed[0] > 0) {                mIsMenuVisible = true;            } else {                mIsMenuVisible = false;            }            return leftMargin;        }         @Override        protected void onPostExecute(Integer integer) {            mMenuParams.leftMargin = integer;            mMenuLayout.setLayoutParams(mMenuParams);        }         @Override        protected void onProgressUpdate(Integer... values) {            mMenuParams.leftMargin = values[0];            mMenuLayout.setLayoutParams(mMenuParams);        }    }     /**     * sleep線程睡眠一下     */    private void sleep() {        try {            Thread.sleep(20);        } catch (InterruptedException e) {            e.printStackTrace();        }    }}複製代碼首先初始化的時候調用initViewsAndValues方法,在這裡面將內容布局的寬度設定為螢幕的寬度,菜單布局的寬度設定為螢幕的寬度減去menuPadding值,這樣可以保證在菜單布局展示的時候,仍有一部分內容布局可以看到。如果不在初始化的時候重定義兩個布局寬度,就會按照layout檔案裡面聲明的一樣,兩個布局都是fill_parent,這樣就無法實現滑動菜單的效果了。然後將菜單布局的左位移量設定為負的菜單布局的寬度,這樣菜單布局就會被完全隱藏,只有內容布局會顯示在介面上。 之後給內容布局註冊監聽事件,這樣當手指在內容布局上滑動的時候就會觸發onTouch事件。在onTouch事件裡面,根據手指滑動的距離會改變菜單布局的左位移量,從而控制功能表布局的顯示和隱藏。當手指離開螢幕的時候,會判斷應該滑動到菜單布局還是內容布局,判斷依據是根據手指滑動的距離或者滑動的速度,細節可以看代碼中的注釋。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.