Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android 自定義側滑菜單

Android 自定義側滑菜單

編輯:關於Android編程

前言

其實對於側滑菜單,在博主剛開始學android接觸到的時候,博主是非常感興趣的,也非常想知道它是如何實現的,在技術的不斷上升之後,我也可以自己封裝側滑菜單了.雖然網上有太多的成品等著我去用,但是博主本著學習和分享的態度還是決定寫下這篇博客,也不介意再重復的造一次輪子,但是我相信,每一次重復的造輪子,都是對我技術最好的檢驗!好了下面就帶大家來封裝這個神奇的側滑菜單吧

閱讀的你需要了解以下的類

用於計算平滑的滑動的時候的運動軌跡的類:Scroller

用於計算用戶手指在屏幕上產生的速度的類:VelocityTracker

實現的效果圖

\

\

\

可以看到實現的效果還是挺棒的,第二種效果和第一種之間就僅僅存在一點區別,就是右邊的視圖會有一個縮放的效果

如果感興趣的話,就跟我一起把這個輪子造出來吧!

 

分析

其實大家腦子裡面應該能想到,菜單和主界面這是一個怎麼樣的擺放,但是博主還是給出一張自己畫的分析圖,菜單在左邊為例:

圖中黑色為手機屏幕

紅色是菜單視圖

藍色是主界面視圖

這是菜單沒有滑動出來的時候

\

這是菜單滑動出來的時候

\

圖畫的不好,大家將就著看一下,其實就是菜單從左邊慢慢的滑出的一個過程

所以其實視圖的擺放還是挺簡單的

1.菜單和主界面緊挨著

2.菜單在左邊,主界面在右邊,主界面的大小就是屏幕的大小(其實是側滑菜單控件的大小,但是為了更好的講解,這裡策劃菜單的大小和屏幕是一樣的,所以這裡就說主界面和屏幕一樣大的,實際大小是你在布局文件中指定側滑控件的大小哦)

 

自定義控件幾步走

1.選擇需要繼承的類並且重寫必要的構造方法--幾乎通用

/**
 * Created by cxj on 2016/5/15.
 *
 * @author 小金子
 *         這個是一個自定義的層疊式的側滑菜單
 *         請遵循一下使用原則:
 *         1.如果是兩個孩子的情況
 *         第一個孩子是菜單,默認是左邊
 *         第二個是主界面
 *         3.不是兩個孩子都會報錯
 */
public class ScaleSlideMenu extends ViewGroup {

    public ScaleSlideMenu(Context context) {
        this(context, null);
    }

    public ScaleSlideMenu(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public ScaleSlideMenu(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(context);
    }

    /**
     * 初始化
     *
     * @param context
     */
    private void init(Context context) {
        this.context = context;
        scroller = new Scroller(context);
        vt = VelocityTracker.obtain();
        screenWidth = ScreenUtils.getScreenWidth(context);
    }
}
構造函數之後用this,這樣子只需要在三個參數的構造函數中調用初始化的方法

 

2.重寫onMeasure方法和onLayout方法--幾乎通用

onMeasure方法測量孩子和自身

onLayout方法排列孩子的位置

這裡不對這兩個方法做深入的講解,所以不太懂的人請自行百度先了解了解

 

onMeasure方法的實現

 

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

        //檢查孩子的個數
        checkChildCount();

        //寬度的計算模式
        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        //推薦的寬度的值
        int widthSize = MeasureSpec.getSize(widthMeasureSpec);

        //高度的計算模式
        int heightMode = MeasureSpec.getMode(heightMeasureSpec);
        //推薦的高度的值
        int heightSize = MeasureSpec.getSize(heightMeasureSpec);

        //菜單
        View menuView = getChildAt(0);
        //生成菜單的寬度的計算模式和大小,菜單的寬度大小受一個百分比限制
        int menuWidthSpec = MeasureSpec.makeMeasureSpec((int) (widthSize * menuPercent), MeasureSpec.AT_MOST);
        //生成菜單的高度的計算模式和大小
        int menuHeightSpec = MeasureSpec.makeMeasureSpec(heightSize, MeasureSpec.AT_MOST);
        //讓菜單的試圖部分去測量自己
        menuView.measure(menuWidthSpec, menuHeightSpec);


        //主界面
        View mainView = getChildAt(1);
        //生成主界面的寬度的計算模式和大小
        int mainWidthSpec = MeasureSpec.makeMeasureSpec(widthSize, MeasureSpec.AT_MOST);
        //生成主界面的高度的計算模式和大小
        int mainHeightSpec = MeasureSpec.makeMeasureSpec(heightSize, MeasureSpec.AT_MOST);
        //讓主界面的試圖部分去測量自己
        mainView.measure(mainWidthSpec, mainHeightSpec);

        //側滑控件的大小呢就直接采用父容器推薦的,所以
        //ViewGroup.LayoutParams.WRAP_CONTENT 和 ViewGroup.LayoutParams.MATCH_PARENT 的情況下大小是一致的,這裡做一個說明
        //作用是保存自身的大小,沒有這句話控件不顯示,也就是看不到啦
        setMeasuredDimension(widthSize, heightSize);

        //保存自身的寬度和高度,其他地方有用
        mWidth = getWidth();
        mHeight = getHeight();
    }
注釋寫的很纖細了,這裡不在全部陳述,只說明一點

 

這裡菜單的寬度是由一個比例值算出來的,是整個策劃菜單寬度的百分之幾,這個變量可以從代碼中知道是menuPercent,這裡就給使用的人提供了方便,可以修改這個值,來實現自己想要的菜單大小

有關的變量和常量這裡貼出

 

    /**
     * 最小的菜單寬度占用百分比
     */
    public static final float MIN_MENUPERCENT = 0.5f;

    /**
     * 最大的菜單寬度的占用百分比
     */
    public static final float MAX_MENUPERCENT = 0.8f;

    /**
     * 菜單寬度占屏幕的比例,默認是最小的
     */
    private float menuPercent = MAX_MENUPERCENT;

 

onMeasure方法關聯的方法的代碼

 

    /**
     * 檢查孩子個數
     */
    private void checkChildCount() {
        int childCount = getChildCount();
        if (childCount != 2) {
            throw new RuntimeException("the childCount must be 2");
        }
    }
這個方法來檢查孩子的個數,如果不是兩個,直接讓程序掛掉就行了

 

那麼整個測量的方法就介紹完了,其實挺簡單的,而且很多都是套路,你懂得,就是代碼幾乎都一樣嘛

 

onLayout方法的實現

此方法就是計算出每一個孩子的位置信息,然後通過View.layout(l,t,r,b)方法來保存或者設置每一個孩子的位置信息

所以在保存位置信息之前是不是需要計算每一個孩子的位置信息先吶?

 

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {

        //計算所有孩子的位置信息
        computePosition();

        //獲取孩子的個數
        int childCount = getChildCount();
        int size = rectEntities.size();

        for (int i = 0; i < size && i < childCount; i++) {

            View v = getChildAt(i);
            RectEntity rectEntity = rectEntities.get(i);

            v.layout(rectEntity.leftX, rectEntity.leftY, rectEntity.rightX, rectEntity.rightY);
        }

    }

 

 

    /**
     * 存儲孩子的位置信息,由方法{@link ScaleSlideMenu#computePosition()}計算而來
     */
    private List rectEntities = new ArrayList();

    /**
     * 計算所有孩子的位置信息
     *
     * @return
     */
    private void computePosition() {
        rectEntities.clear();
        //獲取孩子的個數
        int childCount = getChildCount();

        if (childCount == 2) { //如果是兩個孩子的情況
            //第一個孩子是一個菜單
            View menuView = getChildAt(0);

            //闖進第一個孩子的位置參數
            RectEntity menuRect = new RectEntity();
            if (menuGravity == MENU_GRAVITY_LEFT) { //如果菜單是在左邊的
                menuRect.rightX = 0;
                menuRect.leftX = menuRect.rightX - menuView.getMeasuredWidth();
            } else {
                menuRect.leftX = mWidth;
                menuRect.rightX = menuRect.leftX + menuView.getMeasuredWidth();
            }

            menuRect.leftY = 0;
            menuRect.rightY = menuRect.leftY + menuView.getMeasuredHeight();

            //第二個孩子是一個主界面
            View mainView = getChildAt(1);

            //闖進第一個孩子的位置參數
            RectEntity mainRect = new RectEntity();
            mainRect.leftX = 0;
            mainRect.rightX = mainRect.leftX + mainView.getMeasuredWidth();
            mainRect.leftY = 0;
            mainRect.rightY = mainRect.leftY + mainView.getMeasuredHeight();

            //添加位置信息到集合
            rectEntities.add(menuRect);
            rectEntities.add(mainRect);

        } else { //如果是三個孩子的情況

        }

    }

此方法涉及到一個對象RectEntity,其實就是Java的面向對象思想,把一個孩子的位置信息封裝到一個類中

這裡有四個變量分別是矩形左上角的橫縱坐標和右下角的橫縱坐標,可能有人有疑問,這兩個點就能確定一個矩形了?

顯然不能,但是這裡的矩形隱含了一個條件,就是矩形是水品放置的,所以左上角的坐標和右下角的坐標已經足夠了

 

/**
 * 一個實體類,描述一個矩形的左上角的點坐標和右下角的點的坐標
 * 
 * @author cxj QQ:347837667
 * @date 2015年12月22日
 *
 */
public class RectEntity {

	// 左上角橫坐標
	public int leftX;

	// 左上角縱坐標
	public int leftY;

	// 右下角橫坐標
	public int rightX;

	// 右下角縱坐標
	public int rightY;

}

這些代碼就是計算出了菜單在左邊或者在右邊的時候的位置信息,還有主界面的位置信息,保存到了一個集合中,為什麼要保存到集合中,這是因為位置信息在其他地方還可能有用,如果你直接把這些代碼寫到onLayout方法中,計算出來就直接調用View.layout方法,那麼其他地方想要用到位置信息就十分的麻煩,所以這裡把代碼分離了,也讓整體帶麼顯的更清晰,也降低了耦合性

 

到這裡為止,其實就已經可以看到主界面的試圖了,不過還不能有任何的效果和滑動,這個下面馬上帶你實現

這裡先給出我隨便弄得布局文件

 




    
    

        
        

        
        

    
這裡可以看到策劃菜單這個是填充父容器的,沒有任何內邊距和外邊距,那麼其實就是屏幕的大小啦
側滑菜單中有兩個孩子,一個是我們的菜單,另一個是主界面,給出xml的布局,大家一目十行的看一下啦

 

 

菜單xml

 




    
    


主界面xml

 

 




    
    

        

    

    
    

    

MainActivity的代碼:

 

 

public class MainActivity extends Activity {

    /**
     * 側滑控件
     */
    private ScaleSlideMenu sm = null;

    /**
     * 主界面左上角的小菜單圖標
     */
    private ImageView iv_menu = null;

    /**
     * 顯示菜單數據的
     */
    private ListView lv = null;

    /**
     * listview要用到的數據
     */
    private List data = new ArrayList();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        
        //尋找控件
        sm = (ScaleSlideMenu) findViewById(R.id.sm);
        iv_menu = (ImageView) findViewById(R.id.menu);
        lv = (ListView) findViewById(R.id.lv);
        

        //准備菜單的數據
        for (int i = 0; i < 20; i++) {
            data.add("菜單條目" + i);
        }

        lv.setAdapter(new CommonAdapter(this, data, android.R.layout.simple_list_item_1) {
            @Override
            public void convert(CommonViewHolder h, String item, int position) {
                h.setText(android.R.id.text1, item);
            }
        });


    }

    public void clickView(View view) {
        Toast.makeText(this, "點我按鈕了", Toast.LENGTH_LONG).show();
    }

}

這些大家簡單的看一下就好了,都是十分簡單的布局和一些初始化數據和試圖的代碼,這裡適配器用了通用的適配器,不懂的或者不會用的請自行百度,我認為它是非常好用的哦

 

 

代碼到這裡,你運行以後應該就是下面這樣子了

\

不具備任何的效果和滑動

 

為側滑控件添加滑動效果--根據自己控件的特點編寫

要有滑動效果,肯定是手指滑動吧?所以肯定是重寫onTouchEvent方法吧?所以,go

 

    private int currentX;
    private int currentY;
    private int finalX;
    private int finalY;

    @Override
    public boolean onTouchEvent(MotionEvent e) {

        //獲取事件的類型(動作)
        int action = e.getAction();

        switch (action & MotionEvent.ACTION_MASK) {

            case MotionEvent.ACTION_DOWN: //按下
                
                //保存按下的時候的坐標
                currentX = (int) e.getX();
                currentY = (int) e.getY();

                break;

            case MotionEvent.ACTION_MOVE: //移動

                //保存移動之後的新的坐標點
                finalX = (int) e.getX();
                finalY = (int) e.getY();

                //如果新舊坐標不一致
                if (finalX != currentX || finalY != currentY) {
                    
                    //計算水平距離和垂直距離
                    int dx = finalX - currentX;
                    int dy = finalY - currentY;

                    //讓整個試圖跟著手指移動起來
                    scrollBy(-dx, 0);

                    //移動之後舊的坐標進行更新
                    currentX = (int) e.getX();
                    currentY = (int) e.getY();
                }

                break;
            case MotionEvent.ACTION_UP://抬起

                
                break;
        }

        return true;
    }

代碼都是看得懂的,注釋寫的很詳細了哦,所以不在解釋,最後返回一個true,表示事件傳遞到我這裡我就要吃掉啦!

 

加上這段代碼之後,你的策劃菜單就可以滾動啦!目前的效果

\

可以看到我們的試圖是可以滾動了

然後先實現平滑的打開菜單和關閉菜單,這裡提供給用戶兩個方法,分別用來打開和關閉菜單

 

    /**
     * 打開菜單
     */
    public void openMenu() {
        if (menuGravity == MENU_GRAVITY_LEFT) {
            //拿到菜單的位置參數
            RectEntity menuRect = rectEntities.get(0);
            smoothTo(menuRect.leftX);
        } else {
            //拿到菜單的位置參數
            RectEntity menuRect = rectEntities.get(0);
            smoothTo(menuRect.rightX - menuRect.leftX);
        }

        preIsMenuOpen = isMenuOpen;
        isMenuOpen = true;
    }

    /**
     * 關閉菜單
     */
    public void closeMenu() {
        smoothTo(0);
        preIsMenuOpen = isMenuOpen;
        isMenuOpen = false;
    }

其實就是計算出打開菜單或者關閉菜單的時候要滑動的目標點的橫坐標,然後調用smoothTo方法

 

 

    /**
     * 平滑的移動到指定位置
     */
    private void smoothTo(int finalX) {
        isScrolling = true;
        scroller.startScroll(getScrollX(), 0, finalX - getScrollX(), 0, defalutDuring);
        removeRepeatData();//消除重復數據
        scrollTo(scroller.getCurrX(), 0);
    }
在這裡可以看到Scroller類被使用到了,它幫我們產生從起始點到重點過程中的軌跡點

 

但是數據並不是一次性全部產生的,而是每次調用scroller.computeScrollOffset();方法後才會產生下一個新的數據

比如(1,1)到(10,10),產生的一些列數據大概如下:

(1,1),(2,2),(3,3),(4,4)......(10,10)

當然了,它產生的數據可比我舉例的多得多,甚至很多都是重復的數據,也就是所謂的比較密集吧,所以這裡為了消除重復的那些數據,編寫了一個removeRepeatData()的方法來消除重復的數據,讓它新舊數據之間相差至少為1

    /**
     * 用於消除滑動的時候出現的重復數據
     * 因為平滑的滑動的時候產生的數據很多都是重復的
     * 都是所以這裡如果遇到事重復的就拿下一個,直到不重復為止
     * 1.當前的值{@link View#getScrollX()}不等於{@link Scroller#getCurrX()}
     * 2.
     */
    private void removeRepeatData() {
        //獲取當前的滾動的值
        int scrollX = getScrollX();
        //如果當前的值不是最後一個值,並且當前的值等於scroller中的當前值,那麼獲取下一個值
        while (scrollX != scroller.getFinalX() && scrollX == scroller.getCurrX()) {
            scroller.computeScrollOffset();
        }
    }

 

 

scrollTo(int x, int y)方法是View中的方法,可以讓試圖滾動到某一點,而我們要使用試圖平滑的滾動,你肯定不能直接滾動到目標點,你肯定需要讓Scroller類產生軌跡,然後反復的調用scrollTo(int x, int y)方法滾動到每一個點,從而實現效果上的平滑滾動
所以方法smoothTo中的scrollTo(scroller.getCurrX(), 0);語句就是讓試圖滾動到了第一個點
在View中當滾動完成後會調用computeScroll()方法,所以我們就可以在這個方法中讓視圖繼續滾動到下一個點
    @Override
    public void computeScroll() { //當View完成滾動的時候調用
        //如果軌跡中還有沒有滾完的點
        if (scroller.computeScrollOffset()) {
            removeRepeatData();//消除重復數據
            scrollTo(scroller.getCurrX(), 0);
        }
    }
上述實現平滑的滾動的方法是每一個能平滑滾動的控件的一個基本的實現方法,所以閱讀的你,需要掌握!
我們給我們的小菜單按鈕添加一個監聽

\

然後看現在的效果圖

\
 

到這裡為止實現了平滑的打開菜單,關閉菜單同理,不再詳細解釋

但是拖動的時候只是拖動到哪裡就是哪裡,不會自動判斷當前的位置是應該打開菜單還是關閉菜單

所以下一步就是在手指抬起的時候判斷當前的位置是應該打開菜單還是關閉菜單

判斷之後讓試圖平滑的滑動到位置

觸摸事件處理詳解--根據控件功能定制

但是還有其他細節的處理,所以這裡就直接給出了全部的觸摸的事件的處理代碼,還請見諒,博主會做一個詳細的解釋

 

    @Override
    public boolean onTouchEvent(MotionEvent e) {

        //獲取事件的類型(動作)
        int action = e.getAction();

        //如果按下的,進行有效點的判讀,只有接近邊緣小於某一個百分比,才可以滑出菜單
        if ((action & MotionEvent.ACTION_MASK) == MotionEvent.ACTION_DOWN) {
            //拿到按下的時候的橫左邊
            float x = e.getX();
            if (menuGravity == MENU_GRAVITY_LEFT) { //如果菜單在左邊
                if (x / ((Number) screenWidth).floatValue() < slidePercent) { //如果距離邊界的百分比小於設置的百分比
                    isMyEvent = true;
                }
            } else {
                if ((mWidth - x) / ((Number) screenWidth).floatValue() < slidePercent) { //如果距離邊界的百分比小於設置的百分比
                    isMyEvent = true;
                }
            }
        }

        //如果不需要側滑出菜單,並且菜單是關閉狀態
        if (!isMyEvent && !isMenuOpen && !isScrolling) {
            return false;
        }

        vt.addMovement(e);

        switch (action & MotionEvent.ACTION_MASK) {

            case MotionEvent.ACTION_DOWN: //按下

                isMove = false;

                //保存按下的時候的坐標
                currentX = (int) e.getX();
                currentY = (int) e.getY();

                scroller.setFinalX(currentX);
                scroller.abortAnimation();

                break;

            case MotionEvent.ACTION_MOVE: //移動

                //保存移動之後的新的坐標點
                finalX = (int) e.getX();
                finalY = (int) e.getY();

                //如果新舊坐標不一致
                if (finalX != currentX || finalY != currentY) {

                    //計算水平距離和垂直距離
                    int dx = finalX - currentX;
                    int dy = finalY - currentY;

                    //讓整個試圖跟著手指移動起來
                    scrollBy(-dx, 0);

                    scaleMainView();

                    //移動之後舊的坐標進行更新
                    currentX = (int) e.getX();
                    currentY = (int) e.getY();
                    isMove = true;
                }

                break;
            case MotionEvent.ACTION_UP://抬起

                if (isMove) {
                    //計算速度
                    vt.computeCurrentVelocity(1000, Integer.MAX_VALUE);
                    //水平方向的速度
                    float xVelocity = vt.getXVelocity();

                    //如果速度的絕對值大於200,我們就認為試圖有一個拋出的感覺

                    //如果速度達到了
                    if (xVelocity > 200) {
                        if (menuGravity == MENU_GRAVITY_LEFT) {
                            openMenu();
                        } else {
                            closeMenu();
                        }
                    } else if (xVelocity < -200) {
                        if (menuGravity == MENU_GRAVITY_LEFT) {
                            closeMenu();
                        } else {
                            openMenu();
                        }
                    } else {
                        judgeShouldSmoothToLeftOrRight();
                    }
                } else {
                    closeMenu();
                }

                vt.clear();
                isMove = false;
                isMyEvent = false;
                break;
        }

        return true;
    }


 

首先在觸摸事件的最開始有一些代碼是一個判斷,在判斷什麼呢?你想一下,我們不一定在主界面的任何地方滑動都希望滑出菜單,所以這裡就有一個限制,如果你手指剛剛觸碰到屏幕的時候,如果你距離屏幕兩邊的距離和屏幕寬度的壁紙小於指定的百分比,策劃菜單則認為你要滑出菜單,所以你可以看到有一個變量isMyEvent,這個變量就是記錄判斷之後是不是認為要滑出菜單,如果不要並且菜單是關閉狀態,並且試圖不在滑動,則直接返回false,表示我不需要這個事件,你們愛誰處理就誰處理去吧~~~

 

然後往下看,有一句vt.addMovement(e);

還記得開頭前言的下面我有說過這個vt這個類的作用,是一個可以計算出用戶在觸摸的時候產生的速度的一個類,用法很簡單,就是調用vt.addMovement(e);,在抬起的時候你就可以獲取速度啦

 

在移動的動作事件裡面有這麼一句話:scaleMainView();這個最後解釋

 

最後看抬起事件中的代碼,通過判斷isMove變量得知,手指在屏幕中是否滑動了,如果滑動了則計算出因滑動產生的速度,如果速度如注釋所說,就有一個拋出的感覺,那麼根據速度的方向和菜單的位置來選擇應該是打開還是關閉菜單

拋出的這段的效果來一張

\

\

可以看到效果棒棒哒~~~~

 

最後來揭露一下為什麼這裡的縮放效果我沒介紹,但是上述的效果中都已經實現了,這是因為真的就是一行代碼

介紹一個方法:

 

    /**
     * 縮放主界面
     */
    private void scaleMainView() {
        if (slideMode == SCALE_SLIDE_MODE) { //如果模式是縮放的模式
            float percent = ((Number) Math.abs(getScrollX())).floatValue() / ((Number) Math.abs(rectEntities.get(0).leftX)).floatValue();
            getChildAt(1).setScaleX(1f - 0.4f * (percent));
            getChildAt(1).setScaleY(1f - 0.4f * (percent));
        }
    }

 

這個方法的注釋寫出了這個方法的功能,就是縮放主界面,而方法中是根據什麼進行縮放的呢?

就是根據當前的視圖滾動的偏移量和菜單的寬度的計算出百分比

然後使用這個百分比設置主界面View的縮放比例,這裡利用數學上的知識做了一個限制,可以看到

percent的值區間是[0-1],所以整個1-0.4*percent的區域就是[0.6-1],所以不會出現縮放太誇張的現象!

所以這個方法在視圖滾動的時候調用即可實現縮放的效果!

第一個需要調用這個方法地方就是平滑滾動的時候

 

    @Override
    public void computeScroll() { //當View完成滾動的時候調用
        //如果軌跡中還有沒有滾完的點
        if (scroller.computeScrollOffset()) {
            removeRepeatData();//消除重復數據
            scrollTo(scroller.getCurrX(), 0);
            scaleMainView();
        }
    }

 

第二個需要調用的地方就是我們的手指去滑動的時候

 

            case MotionEvent.ACTION_MOVE: //移動

                //保存移動之後的新的坐標點
                finalX = (int) e.getX();
                finalY = (int) e.getY();

                //如果新舊坐標不一致
                if (finalX != currentX || finalY != currentY) {

                    //計算水平距離和垂直距離
                    int dx = finalX - currentX;
                    int dy = finalY - currentY;

                    //讓整個試圖跟著手指移動起來
                    scrollBy(-dx, 0);

                    scaleMainView();

                    //移動之後舊的坐標進行更新
                    currentX = (int) e.getX();
                    currentY = (int) e.getY();
                    isMove = true;
                }

                break;

 

好了,到這裡就基本上完工了,最後的最後需要處理的一點事情就是在我們的菜單打開的時候,菜單部分的試圖的事件不攔截,但是主界面的事件要絕對的攔截!

所以需要重寫onInterceptTouchEvent(MotionEvent ev)方法

 

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        int action = ev.getAction();
        switch (action & MotionEvent.ACTION_MASK) {

            case MotionEvent.ACTION_DOWN: //按下

                //獲取到按下的時候的相對於屏幕的橫坐標x
                int x = (int) ev.getX();

                //攔截菜單打開的情況下主界面的事件
                if (isMenuOpen) {
                    //菜單的位置參數對象
                    RectEntity menuRect = rectEntities.get(0);

                    if (menuGravity == MENU_GRAVITY_LEFT) { //如果菜單在左邊
                        if (x > Math.abs(menuRect.leftX)) { //滿足說明了點擊的是主界面的區域
                            return true;
                        }
                    } else { //菜單在右邊
                        if (x < (mWidth - (menuRect.rightX - menuRect.leftX))) {
                            return true;
                        }
                    }
                }
        }

        return super.onInterceptTouchEvent(ev);
    }

好了,全部的代碼完工了,這篇博客已經盡我所能了,自己覺得講的是很詳細了,就是希望閱讀者能在自定義控件上面多學一點

源碼下載

https://github.com/xiaojinzi123/xiaojinzi-openSource-view/tree/master/xiaojinzi/view/scaleSlideMenu

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved