側滑菜單(一):帶縮放動畫

實現效果


實現代碼

  • 新建項目A
  • 新建自定義控件Draglayout繼承FrameLayout
/**
* Created by Administrator on 2016/9/30.
* 創建自定義控件
*/
public class Draglayout extends FrameLayout {

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

    public Draglayout(Context context, AttributeSet attrs) {
        this(context, attrs,-1);
    }

    public Draglayout(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);

        //初始化控件
        init();
    }

    /**
     * 初始化控件
     */
    private void init() {

    }
}
  • 對activity_main.xml進行修改
<RelativeLayout 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"
    >

    <com.one1go.draglayout.Draglayout
        android:background="@drawable/bg"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
         >
        </com.one1go.draglayout.Draglayout>
</RelativeLayout>
  • 新建一個menu.xml佈局
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#6f599c">

    <ImageView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:src="@drawable/head"/>

</LinearLayout>
  • 新建一個main.xml佈局
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#3c3645">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="#18b4ed">
        <ImageView
            android:layout_width="50dp"
            android:layout_height="50dp"
            android:padding="10dp"
            android:src="@drawable/head"/>
    </LinearLayout>

</LinearLayout>
  • 對activity_main.xml添加以上兩個佈局
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
  ...
    >

    <com.itheima.draglayout.Draglayout
       ...
         >
        <!--在上面的在下面-->
        <include layout="@layout/menu"/>
        <include layout="@layout/main"/>
        </com.itheima.draglayout.Draglayout>
</RelativeLayout>
  • 在清單文件中去除標題欄:由於MainActivity中繼承的是AppCompatActivity,所以它沒有title,只有actionbar
application
    android:allowBackup="true"
    android:icon="@mipmap/ic_launcher"
    android:label="@string/app_name"
    android:supportsRtl="true"
    android:theme="@style/Theme.AppCompat.NoActionBar">
    <activity android:name=".MainActivity">
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />

            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity>
</application>
  • 實現界面的左右上下滑動:在DrawLayout中進行修改
/**
* Created by Administrator on 2016/x/xx.
* 創建自定義控件
*/
public class Draglayout extends FrameLayout {

    private ViewDragHelper helper;
     ...

    public Draglayout(Context context, AttributeSet attrs, int defStyleAttr) {
        ...
    }

    /**
     * 初始化控件
     * Google I/O ViewDragHelper封裝了觸摸,滑動等操作,可以輕鬆的控件觸摸滑動
     */
    private void init() {
        //創建ViewDragHelper
        //參數1 : 爲誰處理觸摸操作
        helper = ViewDragHelper.create(this,callback);
    }

    /**
     * 新建一個callback
     */
    private ViewDragHelper.Callback callback = new ViewDragHelper.Callback() {

        /**
         * 嘗試捕獲視圖
         * @param child 被捕獲的子視圖
         * @param pointerId 多指觸摸,某個手指的id
         * @return  如果返回true,表示所有的孩子都可以被觸摸,返回true表示可以移動
         */
        @Override
        public boolean tryCaptureView(View child, int pointerId) {
            return true;
        }

        /**
         * 處理水平移動
         * @param child 被觸摸的孩子
         * @param left  oldLeft + dx = newLeft
         * @param dx    系統每隔一段時間檢測手指移動的距離
         * @return
         */
        @Override
        public int clampViewPositionHorizontal(View child, int left, int dx) {
            return left;
        }

        /**
         * 處理垂直移動
         * @param child
         * @param top
         * @param dy
         * @return
         */
//        @Override
//        public int clampViewPositionVertical(View child, int top, int dy) {
//            return top;
//        }
    };

    /**
     * 讓helper接手觸摸事件的處理
     * @param event
     * @return  必須返回true才能處理
     */
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        helper.processTouchEvent(event);
        return true;
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        return helper.shouldInterceptTouchEvent(ev);
    }

}
  • 處理滑動的最大範圍:DrawLayout -- 1.在當前控件及其子控件全部測量完的時候,調用此方法。
/*自定義控件的4個基本流程
* 1,加載
* 2,測量
* 3,佈局
* 4,繪製
* */
/**
* 在當前控件及其子控件全部加載完畢時,調用此方法
*/
@Override
protected void onFinishInflate() {
    super.onFinishInflate();

    //對當前加入的控件的子視圖進行限制
    //代碼健壯性處理

    //孩子的數目不能超過2個
    if(getChildCount() != 2) {
        throw new RuntimeException("Are you kedding me?there only hava two childs");
    }

    //必須包含ViewGroup
    if(!(getChildAt(0) instanceof ViewGroup) || !(getChildAt(1) instanceof  ViewGroup)) {
        throw new RuntimeException("hehe,you never can use it if it isn't ViewGroup");
    }

    menu = getChildAt(0);
    main = getChildAt(1);
}
  • 處理滑動的最大範圍:DrawLayout -- 2.獲取在onMeasure方法執行後執行,可以獲得測量結果
/**
* 在onMeasure()方法執行後執行,可以獲得測量結果
* @param w
* @param h
* @param oldw
* @param oldh
*/
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
    super.onSizeChanged(w, h, oldw, oldh);

    int width = main.getMeasuredWidth();
    //獲取最大拖動範圍
    maxDragRange = (int) (width * 0.6f);
}
  • 處理滑動的最大範圍:DrawLayout -- 處理移動的最大範圍
    /**
     * 新建一個callback
     */
    private ViewDragHelper.Callback callback = new ViewDragHelper.Callback() {

        ...

        ...
        @Override
        public int clampViewPositionHorizontal(View child, int left, int dx) {
            //處理滑動的最大範圍
            if(child == main) {
                if(left < 0) {
                    left = 0;
                } else if(left > maxDragRange) {
                    left = maxDragRange;
                }
            }
            return left;
        }
          ...
    };
  • menu的滑動處理:DragLayout
/**
* Created by Administrator on 2016/9/30.
* 創建自定義控件
*/
public class Draglayout extends FrameLayout {

    private ViewDragHelper helper;
    private View menu;
    private View main;
    private int maxDragRange;

   ...
    ...
    private ViewDragHelper.Callback callback = new ViewDragHelper.Callback() {

        ...
        /**
         * 位置已經便改變的回掉方法
         * @param changedView   被改變位置的孩子視圖
         * @param left  已經移動的left
         * @param top
         * @param dx    手指移動的dx
         * @param dy
         */
        @Override
        public void onViewPositionChanged(View changedView, int left, int top, int dx, int dy) {
            super.onViewPositionChanged(changedView, left, top, dx, dy);
            //判斷當前的視圖是menu的時候
            //1.禁止menu滑動
            //2.將meun移動的距離傳給main
            if(changedView == menu) {
                //滑動的底層都是調用這個代碼
                menu.offsetLeftAndRight(-dx);

                //處理滑動menu造成menu移動的邊界範圍
                int oldLeft = main.getLeft();
                int newLeft = oldLeft + dx;

                //限制newLeft的範圍
                if(newLeft > maxDragRange) {
                    newLeft = maxDragRange;
                } else if(newLeft < 0) {
                    newLeft = 0;
                }

                int newDx = newLeft - oldLeft;
                main.offsetLeftAndRight(newDx);

            }
        }

       ...
    };
...
}
  • 擡起手的操作
public class Draglayout extends FrameLayout {

    ...
    private ViewDragHelper.Callback callback = new ViewDragHelper.Callback() {
     ...
        /**
         * 釋放視圖的回調
         * @param releasedChild 被釋放的孩子視圖
         * @param xvel  釋放瞬間x方向的速度
         * @param yvel
         */
        @Override
        public void onViewReleased(View releasedChild, float xvel, float yvel) {
            super.onViewReleased(releasedChild, xvel, yvel);
            //判斷當釋放視圖的時候,main的左邊距與最大範圍的一半進行比較
            if(main.getLeft() < maxDragRange / 2) {
                close();
            } else {
                open();
            }
        }
     ...
    };

    /**
     * 開啓側滑菜單
     */
    private void open() {
        //設置目標點
        //平滑的開始滾動視圖
        if(helper.smoothSlideViewTo(main,maxDragRange,0)) {
            //繪製界面
            invalidate();
        }
    }

    /**
     * 計算滾動過程中的某幀
     */
    @Override
    public void computeScroll() {
        super.computeScroll();
        if(helper.continueSettling(true)) {
            invalidate();
        }
    }

    /**'
     * 關閉側滑菜單
     */
    private void close() {
        if(helper.smoothSlideViewTo(main,0,0)) {
            //繪製界面
            invalidate();
        }
    }

    ...
}
  • 讓main縮放
...
public class Draglayout extends FrameLayout {

    ...

    /**
     * 新建一個callback
     */
    private ViewDragHelper.Callback callback = new ViewDragHelper.Callback() {

       ...

        /**
         * 位置已經便改變的會掉方法
         * @param changedView   被改變位置的孩子視圖
         * @param left  已經移動的left
         * @param top
         * @param dx    手指移動的dx
         * @param dy
         */
        @Override
        public void onViewPositionChanged(View changedView, int left, int top, int dx, int dy) {
           ...
            if(changedView == menu) {
                ...
            }
            //計算移動的距離佔總距離的百分比
            float percent = main.getLeft() * 1.0f / maxDragRange;
            executeAnimation(percent);
        }

       ...
    };

    /**
     * 執行移動時main的縮放動畫
     * @param percent
     */
    private void executeAnimation(float percent) {
//        Log.i("test", "executeAnimation: percent=" + percent);
        //1.讓main越來越小 : 1.0f - 0.75f
        //估值器.插值器
        float evaluateResult = evaluate(percent,1.0f,0.75f);
        //2.讓main縮放
        main.setScaleX(evaluateResult);
        main.setScaleY(evaluateResult);
    }

    private float evaluate(float fraction, float startValue, float endValue) {
        return startValue + fraction * (endValue - startValue);
    }

   ...
}

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