自定義Android側(cè)滑菜單控件

package com.tenghu.sideslipmenu.view;

網(wǎng)站建設(shè)哪家好,找創(chuàng)新互聯(lián)!專注于網(wǎng)頁(yè)設(shè)計(jì)、網(wǎng)站建設(shè)、微信開發(fā)、微信小程序開發(fā)、集團(tuán)企業(yè)網(wǎng)站建設(shè)等服務(wù)項(xiàng)目。為回饋新老客戶創(chuàng)新互聯(lián)還提供了崇左免費(fèi)建站歡迎大家使用!

import android.content.Context;

import android.os.AsyncTask;

import android.util.AttributeSet;

import android.util.DisplayMetrics;

import android.view.MotionEvent;

import android.view.VelocityTracker;

import android.view.View;

import android.view.WindowManager;

import android.widget.LinearLayout;

/**

 * Created by Arvin_Li on 2014/11/18.

 */

public class SideslipMenuView extends LinearLayout {

    //滾動(dòng)顯示和隱藏menu時(shí),手指滑動(dòng)需要達(dá)到的速度

    private static final int SNAP_VELOCITY = 200;

    private View mMenu;//菜單布局

    private View mContent;//主內(nèi)容布局

    private int mScreenWidth;//屏幕寬度

    private int mMenuWidth;//菜單寬度

    //menu最多可以滑動(dòng)到的左邊緣,值由menu布局的寬度來(lái)定

    private int leftEdge;

    //menu最多可以滑到的有邊緣,值恒為0

    private int rightEdge = 0;

    //menu完全顯示時(shí),留給content的寬度值

    private int toRightPaddingWidth = 50;

    //menu布局的參數(shù),通過(guò)此參數(shù)來(lái)更改leftMargin的值

    private LinearLayout.LayoutParams menuParams;

    //記錄手指按下的橫坐標(biāo)

    private float xDown;

    //記錄手指抬起的橫坐標(biāo)

    private float xUp;

    //記錄手指移動(dòng)的橫坐標(biāo)

    private float xMove;

    //當(dāng)前menu是顯示還是隱藏,只有menu完全顯示和隱藏才會(huì)改變?cè)撝?,滑?dòng)時(shí)不會(huì)改變

    private boolean isMenuVisible;

    //用于計(jì)算手指滑動(dòng)的速度

    private VelocityTracker mVelocityTracker;

    private boolean once;

    public SideslipMenuView(Context context) {

        super(context);

        init(context);

    }

    public SideslipMenuView(Context context, AttributeSet attrs) {

        super(context, attrs);

        init(context);

    }

    /**

     * 初始化

     */

    private void init(Context context) {

        //獲取WindowManager對(duì)象

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

        DisplayMetrics displayMetrics = new DisplayMetrics();

        windowManager.getDefaultDisplay().getMetrics(displayMetrics);

        mScreenWidth = displayMetrics.widthPixels;//獲取屏幕寬度

    }

    @Override

    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

        super.onMeasure(widthMeasureSpec, heightMeasureSpec);

        if (!once) {

            mMenu = getChildAt(0);//獲取菜單布局

            mContent = getChildAt(1);//獲取內(nèi)容布局

            menuParams = (LayoutParams) mMenu.getLayoutParams();//獲取菜單參數(shù)

            mMenuWidth = menuParams.width = mScreenWidth - toRightPaddingWidth;//設(shè)置菜單寬度

            //左邊緣的值賦值為menu寬度的負(fù)數(shù)

            leftEdge = -menuParams.width;

            //menu的leftMargin設(shè)置為左邊緣的值,默認(rèn)菜單不可見(jiàn)

            menuParams.leftMargin = leftEdge;

            mContent.getLayoutParams().width = mScreenWidth;//設(shè)置內(nèi)容寬度

            once = true;

        }

    }

    @Override

    public boolean onTouchEvent(MotionEvent event) {

        createVelocityTracker(event);//創(chuàng)建VelocityTracker對(duì)象

        switch (event.getAction()) {

            //手指按下

            case MotionEvent.ACTION_DOWN:

                xDown = event.getRawX();//記錄橫坐標(biāo)

                break;

            //手指移動(dòng)

            case MotionEvent.ACTION_MOVE:

                //手指移動(dòng)時(shí),對(duì)比按下的橫坐標(biāo),計(jì)算出移動(dòng)的距離來(lái)調(diào)整menu的leftMargin值,從而顯示和隱藏menu

                xMove = event.getRawX();

                //計(jì)算獲取到距離

                int distanceX = (int) (xMove - xDown);

                if (isMenuVisible) {

                    menuParams.leftMargin = distanceX;

                } else {

                    menuParams.leftMargin = leftEdge + distanceX;

                }

                //如果菜單的左邊界小于了可以滑動(dòng)的左邊界

                if (menuParams.leftMargin <= leftEdge) {

                    //將可以滑動(dòng)的左邊界賦值給菜單左邊界

                    menuParams.leftMargin = leftEdge;

                } else if (menuParams.leftMargin >= rightEdge) {

                    menuParams.leftMargin = rightEdge;

                }

                mMenu.setLayoutParams(menuParams);//設(shè)置菜單參數(shù)

                break;

            //手指抬起

            case MotionEvent.ACTION_UP:

                //手指抬起時(shí),進(jìn)行判斷當(dāng)前手勢(shì)的意圖,從而決定是滾動(dòng)到menu界面,還是滾動(dòng)到content界面

                xUp = event.getRawX();

                if (wantToShowMenu()) {

                    if (shouldScrollToMenu()) {

                        scrollToMenu();

                    } else {

                        scrollToContent();

                    }

                } else if (wantToShowContent()) {

                    if (shouldScrollToContent()) {

                        scrollToContent();

                    } else {

                        scrollToMenu();

                    }

                }

                //手指抬起是回收VelocityTracker對(duì)象

                recycleVelocityTracker();

                break;

        }

        return true;

    }

    /**

     * 創(chuàng)建VelocityTracker對(duì)象,并將觸摸content界面的滑動(dòng)時(shí)間加入到VelocityTracker中

     *

     * @param event

     */

    private void createVelocityTracker(MotionEvent event) {

        if (null == mVelocityTracker) {

            mVelocityTracker = VelocityTracker.obtain();//初始化VelocityTracker

        }

        mVelocityTracker.addMovement(event);//添加界面滑動(dòng)事件

    }

    /**

     * 判斷當(dāng)前手勢(shì)的意圖是不是想顯示content,如果手指移動(dòng)的距離是負(fù)數(shù),且當(dāng)前menu是可見(jiàn)的,則認(rèn)為當(dāng)前手勢(shì)是想要顯示content。

     *

     * @return

     */

    private boolean wantToShowContent() {

        return xUp - xDown < 0 && isMenuVisible;

    }

    /**

     * 判斷當(dāng)前手勢(shì)的意圖是不是想顯示menu,如果手指移動(dòng)的距離是正數(shù),且當(dāng)前menu是不可見(jiàn),則認(rèn)為當(dāng)前手勢(shì)是顯示menu

     *

     * @return

     */

    private boolean wantToShowMenu() {

        return xUp - xDown > 0 && !isMenuVisible;

    }

    /**

     * 判斷是否應(yīng)該滾動(dòng)將menu展示出來(lái),如果手指移動(dòng)距離大于屏幕的1/2,或者手指移動(dòng)速度大于SNAP_VELOCITY,就認(rèn)為應(yīng)該滾動(dòng)將menu展示出來(lái)。

     *

     * @return 如果應(yīng)該滾動(dòng)將menu展示出來(lái)返回true,否則返回false。

     */

    private boolean shouldScrollToMenu() {

        return xUp - xDown > mMenuWidth / 2 || getScrollVelocity() > SNAP_VELOCITY;

    }

    /**

     * 判斷是否應(yīng)該滾動(dòng)將content展示出來(lái),如果手指移動(dòng)距離加上menuPadding大于屏幕的1/2,或者手指移動(dòng)速度大于SNAP_VELOCITY, 就認(rèn)為應(yīng)該滾動(dòng)將content展示出來(lái)。

     *

     * @return 如果應(yīng)該滾動(dòng)將content展示出來(lái)返回true,否則返回false。

     */

    private boolean shouldScrollToContent() {

        //這里菜單狀態(tài)為顯示,如果要菜單隱藏,那么手勢(shì)是從右到左滑動(dòng),這里手指按下的橫坐標(biāo)就會(huì)比抬起時(shí)的橫坐標(biāo)小

        return xDown - xUp + toRightPaddingWidth > mMenuWidth / 2 || getScrollVelocity() > SNAP_VELOCITY;

    }

    /**

     * 獲取手指在content上滑動(dòng)的速度

     *

     * @return 滑動(dòng)速度,以每秒鐘移動(dòng)了多少像素為單位

     */

    private int getScrollVelocity() {

        mVelocityTracker.computeCurrentVelocity(1000);

        int velocity = (int) mVelocityTracker.getXVelocity();//獲取x方向的速度值

        return Math.abs(velocity);

    }

    /**

     * 回收VelocityTracker對(duì)象

     */

    private void recycleVelocityTracker() {

        if (null != mVelocityTracker) {

            mVelocityTracker.recycle();

            mVelocityTracker = null;

        }

    }

    /**

     * 將屏幕滾動(dòng)到menu界面,設(shè)置滾動(dòng)速度為30

     */

    private void scrollToMenu() {

        isMenuVisible = true;

        new ScrollTask().execute(30);

    }

    /**

     * 將屏幕滾動(dòng)到content界面,設(shè)置滾動(dòng)速度為-30

     */

    private void scrollToContent() {

        isMenuVisible = false;

        new ScrollTask().execute(-30);

    }

    /**

     * 創(chuàng)建滾動(dòng)任務(wù)類

     */

    class ScrollTask extends AsyncTask<Integer, Integer, Integer> {

        @Override

        protected Integer doInBackground(Integer... speed) {

            int leftMargin = menuParams.leftMargin;

            //根據(jù)傳入的速度來(lái)滾動(dòng)界面,當(dāng)滾動(dòng)到達(dá)左邊界或右邊界時(shí)跳出循環(huán)

            while (true) {

                leftMargin = leftMargin + speed[0];

                if (leftMargin > rightEdge) {

                    leftMargin = rightEdge;

                    break;

                }

                if (leftMargin < leftEdge) {

                    leftMargin = leftEdge;

                    break;

                }

                //更新任務(wù)進(jìn)度,會(huì)把值傳入到onProgressUpdate()方法中進(jìn)行UI的更新

                publishProgress(leftMargin);

                //為了要有滾動(dòng)效果產(chǎn)生,每次循環(huán)使線程睡眠20毫秒

                sleep(20);

            }

            return leftMargin;

        }

        /**

         * 這里的Intege參數(shù)對(duì)應(yīng)AsyncTask中的第二個(gè)參數(shù)

         * 在doInBackground方法當(dāng)中,,每次調(diào)用publishProgress方法都會(huì)觸發(fā)onProgressUpdate執(zhí)行

         * onProgressUpdate是在UI線程中執(zhí)行,所有可以對(duì)UI空間進(jìn)行操作

         *

         * @param leftMargin

         */

        @Override

        protected void onProgressUpdate(Integer... leftMargin) {

            menuParams.leftMargin = leftMargin[0];

            mMenu.setLayoutParams(menuParams);

        }

        /**

         * 執(zhí)行異步結(jié)束,接收doInBackground()方法的返回值,接收到的返回值對(duì)應(yīng)AsyncTask<Integer, Integer, Integer> 第3個(gè)參數(shù)

         *

         * @param leftMargin

         */

        @Override

        protected void onPostExecute(Integer leftMargin) {

            menuParams.leftMargin = leftMargin;

            mMenu.setLayoutParams(menuParams);

        }

    }

    /**

     * 是當(dāng)前線程睡眠指定的毫秒數(shù)

     *

     * @param millis

     */

    private void sleep(long millis) {

        try {

            Thread.sleep(millis);

        } catch (InterruptedException e) {

            e.printStackTrace();

        }

    }

}

以上就是整個(gè)自定義側(cè)滑菜單控件的代碼,在布局文件直接使用即可如下:

<?xml version="1.0" encoding="utf-8"?>

<com.tenghu.sideslipmenu.view.SideslipMenuView xmlns:android="http://schemas.android.com/apk/res/android"

    android:layout_width="match_parent"

    android:layout_height="match_parent"

    android:background="@drawable/bg_01">

    <include layout="@layout/left_menu" />

    <LinearLayout

        android:layout_width="match_parent"

        android:layout_height="match_parent"

        android:background="@drawable/bg_02"

        android:orientation="vertical">

       

    </LinearLayout>

</com.tenghu.sideslipmenu.view.SideslipMenuView>

其中include引用的就是一個(gè)菜單布局文件,如下:

<?xml version="1.0" encoding="utf-8"?>

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"

    android:layout_width="match_parent"

    android:layout_height="match_parent"

    android:gravity="center_vertical">

    <LinearLayout

        android:layout_width="match_parent"

        android:layout_height="wrap_content"

        android:layout_marginLeft="30dp"

        android:orientation="vertical">

        <RelativeLayout

            android:layout_width="wrap_content"

            android:layout_height="50dp"

            android:layout_marginBottom="10dp">

            <ImageView

                android:id="@+id/iv_img_01"

                android:layout_width="50dp"

                android:layout_height="match_parent"

                android:src="@drawable/app_01" />

            <TextView

                android:layout_width="match_parent"

                android:layout_height="match_parent"

                android:layout_marginLeft="10dp"

                android:layout_toRightOf="@id/iv_img_01"

                android:gravity="center_vertical"

                android:text="第一個(gè)Item" />

        </RelativeLayout>

        <RelativeLayout

            android:layout_width="wrap_content"

            android:layout_height="50dp"

            android:layout_marginBottom="10dp">

            <ImageView

                android:id="@+id/iv_img_02"

                android:layout_width="50dp"

                android:layout_height="match_parent"

                android:src="@drawable/app_02" />

            <TextView

                android:layout_width="match_parent"

                android:layout_height="match_parent"

                android:layout_marginLeft="10dp"

                android:layout_toRightOf="@id/iv_img_02"

                android:gravity="center_vertical"

                android:text="第二個(gè)Item" />

        </RelativeLayout>

        <RelativeLayout

            android:layout_width="wrap_content"

            android:layout_height="50dp"

            android:layout_marginBottom="10dp">

            <ImageView

                android:id="@+id/iv_img_03"

                android:layout_width="50dp"

                android:layout_height="match_parent"

                android:src="@drawable/app_03" />

            <TextView

                android:layout_width="match_parent"

                android:layout_height="match_parent"

                android:layout_marginLeft="10dp"

                android:layout_toRightOf="@id/iv_img_03"

                android:gravity="center_vertical"

                android:text="第三個(gè)Item" />

        </RelativeLayout>

        <RelativeLayout

            android:layout_width="wrap_content"

            android:layout_height="50dp"

            android:layout_marginBottom="10dp">

            <ImageView

                android:id="@+id/iv_img_04"

                android:layout_width="50dp"

                android:layout_height="match_parent"

                android:src="@drawable/app_04" />

            <TextView

                android:layout_width="match_parent"

                android:layout_height="match_parent"

                android:layout_marginLeft="10dp"

                android:layout_toRightOf="@id/iv_img_04"

                android:gravity="center_vertical"

                android:text="第四個(gè)Item" />

        </RelativeLayout>

        <RelativeLayout

            android:layout_width="wrap_content"

            android:layout_height="50dp"

            android:layout_marginBottom="10dp">

            <ImageView

                android:id="@+id/iv_img_05"

                android:layout_width="50dp"

                android:layout_height="match_parent"

                android:src="@drawable/app_05" />

            <TextView

                android:layout_width="match_parent"

                android:layout_height="match_parent"

                android:layout_marginLeft="10dp"

                android:layout_toRightOf="@id/iv_img_05"

                android:gravity="center_vertical"

                android:text="第五個(gè)Item" />

        </RelativeLayout>

    </LinearLayout>

</RelativeLayout>

其中的菜單可以使用ListView去布局,這里做測(cè)試就沒(méi)有去使用了

當(dāng)前題目:自定義Android側(cè)滑菜單控件
標(biāo)題網(wǎng)址:http://muchs.cn/article0/pgosoo.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供網(wǎng)頁(yè)設(shè)計(jì)公司、電子商務(wù)移動(dòng)網(wǎng)站建設(shè)、、虛擬主機(jī)品牌網(wǎng)站設(shè)計(jì)

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)

小程序開發(fā)