自定義控件-側拉菜單

    手機版qq有一個挺不錯的效果是側拉菜單,在主界面向右滑動就會在左側出現關於自己qq的一些信息;
    實現側滑效果目前知道有三種:
	一是SlidingDrawer,谷歌在Android4.2之後已經不建議使用
	二是DrawerLayout,谷歌提供的挺好用的控件,只需在佈局文件中加載即可
	三是第三方提供的開源控件,更加的靈活;下面就來簡單介紹一下原理
  一、需求
    1.定義兩個佈局,菜單和主內容,然後整合在一個自定義的控件中
    2.分別測量出菜單和主內容的寬和高
    3.主內容全屏顯示在屏幕上,那麼左側的菜單就會看不到,達到了隱藏菜單的效果
    4.處理屏幕的onTouchEvent()事件,實現左右滑動控制菜單的隱藏與顯示
  二、具體實現
    1.定義佈局文件菜單和主內容,然後整合在自定義的SlideMenu控件中
    2.在SlideMenu中通過onMeasure測量佈局文件的寬和高
	
 @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        //測量菜單的寬和高,寬爲240dip,高爲父窗體高度
        //0代表菜單
        View menuView = getChildAt(0);
        menuView.measure(menuView.getLayoutParams().width, heightMeasureSpec);

        //測量內容正文的寬和高,與父窗體一致
        //1代表正文內容
        View contentView = getChildAt(1);
        contentView.measure(widthMeasureSpec, heightMeasureSpec);
    }

        在系統底層measure調用了onMeasure(定義了寬高的約束)
	onMeasrue調用了setMeasureDimension(真實的寬高信息)
    3.通過onLayout方法繪製佈局
	
 @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        //把測量出菜單和內容繪製屏幕上
        View menuView = getChildAt(0);
        //設置菜單在屏幕的左側顯示(即隱藏)
        menuView.layout(-menuView.getMeasuredWidth(), t, 0, b);
        //主內容的繪製
        View contentView = getChildAt(1);
        contentView.layout(l, t, r, b);
    }

    4.處理屏幕的onTouchEvent事件實現菜單的隱藏與顯示
	
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        int scrollX;

        switch (event.getAction()) {
            //按下
            case MotionEvent.ACTION_DOWN:
                downX = (int) event.getX();
                break;
            //移動
            case MotionEvent.ACTION_MOVE:
                int moveX = (int) event.getX();
                //偏移量
                int deltax = downX - moveX;

                scrollX = getScrollX() + deltax;
                //根據當前位置確定屏幕的顯示
                if (scrollX < -getChildAt(0).getMeasuredWidth()) {
                    scrollTo(-getChildAt(0).getMeasuredWidth(), 0);
                } else if (scrollX > 0) {
                    scrollTo(0, 0);
                } else {
                    scrollBy(deltax, 0);
                }
                downX = moveX;
                break;
            //擡起
            case MotionEvent.ACTION_UP:
                int center = -getChildAt(0).getMeasuredWidth() / 2;
                scrollX = getScrollX();
                if (scrollX < center) {
                    currentState = SCREEN_CONTENT;
                } else {
                    currentState = SCREEN_MAIN;
                }
                switchScreen();
                break;
        }
        return true;
    }

    /**
     * 根據currentState的狀態來更改屏幕的顯示
     */
    private void switchScreen() {
        int startX = getScrollX();  //當前屏幕的X位置
        int dX = 0;                 //增量=目的位置-當前位置
        switch (currentState) {
            case SCREEN_CONTENT:
//                scrollTo(-getChildAt(0).getMeasuredWidth(),0);
                dX = -getChildAt(0).getMeasuredWidth() - startX;
                break;
            case SCREEN_MAIN:
//                scrollTo(0,0);
                dX = 0 - startX;
                break;
        }
        int duration = Math.abs(dX) * 10;
        if (duration > 1000) {
            duration = 1000;
        }

        scroller.startScroll(startX, 0, dX, 0, duration);
        invalidate();
    }

    @Override
    public void computeScroll() {
        //當不在模擬數據時候跳出遞歸
        if (scroller.computeScrollOffset()) {
            //獲取當前模擬的數據
            int currX = scroller.getCurrX();
            //更新位置
            scrollTo(currX, 0);
            invalidate();
        }
    }


       滑動的分析:
	 1.當點擊屏幕時記錄下當前的位置downX,在移動的過程中根據當前位置moveX和downX計算偏移量
	   根據偏移量的值不斷的修正菜單和主內容在屏幕的顯示位置;
         2.當擡起時,如果菜單顯示出來的內容是否大於二分之一,那麼滑動顯示菜單,反之顯示主內容
	 3.currentState用來記錄當前屏幕顯示的是菜單還是主內容,並且是屏幕固定時偏移量計算的依據
	 4.scroller.startScroll(startX,0,dX,0,duration)
	   用來模擬X軸從startX到偏移dX經過duration時間的過程,但是這個方法只是模擬,並不會改變
	   屏幕的顯示,還需要通過invalidate()來修改屏幕的顯示
	 5.invalidate()在ViewGroup中通過調用DrawChild()->再調view.draw->computeScroll修改屏幕
	   顯示的內容,由於startScroll的數據是緩慢變化的,因此需要用遞歸不斷的更新當前的顯示,就
	   實現了鬆手後菜單緩慢移動的效果
   三、回調簡介
	Android回調方法用的特別多,其原理類似於設計模式中的觀察者模式,回調通過自身提供一個內部
	接口,在接口定義統一的方法,那麼不管是誰調用我,只要實現我接口中定義的方法,使代碼有了很
	好的封裝性
   四、個人總結
	寫自定義控件一定要有的步驟:
	1.分析控件的實現都有什麼狀態
	2.找出狀態之間轉換的臨界條件
	3.實現即可


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章