android抽屜式側滑

側滑效果展示

這裏寫圖片描述

原理

要實現這種側滑效果,首先自定義一個滑動Layout繼承自RelativeLayout,裏面有兩個View分別是用來存放內容和菜單佈局的,然後記錄手指一動的距離更改內容View的leftMargin(注意:只有leftMargin的值是負數才能夠向左偏移,如果是正數的話那麼會向右壓縮),在內容View移動的同時,調用菜單的setTranslateX()方法就可以達到菜單移動了

代碼

首先上代碼:

<cn.karent.slide.UI.SlideLayout xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
     android:layout_height="match_parent">

    <!--側滑菜單-->
    <RelativeLayout
        android:id="@+id/slide_menu"
        android:layout_width="300dp"
        android:layout_height="match_parent"
        android:layout_alignParentRight="true"
        android:layout_marginRight="-150dp"
        android:background="@android:color/holo_purple"
        android:orientation="vertical">
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="側滑菜單"/>
        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerInParent="true"
            android:text="測試按鈕"/>
    </RelativeLayout>

    <!--內容View-->
    <RelativeLayout
        android:id="@+id/slide_content"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_alignParentLeft="true"
        android:background="@android:color/holo_red_dark">
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="我是內容"/>
        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="button"
            android:layout_centerInParent="true"/>

    </RelativeLayout>

</cn.karent.slide.UI.SlideLayout>

注意,我直接讓菜單項往右偏移一半,這樣就不會有完全滾動的效果,而是菜單的偏移比內容的偏移更慢一點,下面上自定義Layout的代碼:

package cn.karent.slide.UI;

import android.content.Context;
import android.os.AsyncTask;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.widget.RelativeLayout;
import cn.karent.slide.R;
import cn.karent.slide.util.ScreenUtil;

/**
 * Created by wan on 2016/12/6.
 * 側滑菜單,內容會偏移
 */
public class SlideLayout extends RelativeLayout {

    private Context mContext;

    private static final int MOTION_VELOCITY = 300;

    /*
        是否是第一次調用onLayout方法
     */
    private boolean mLoadOnece = false;

    /*
        左邊內容的佈局參數
     */
    private MarginLayoutParams mLeftParams;

    /*
        右邊菜單的佈局參數
     */
    private MarginLayoutParams mMenuParams;

    /*
        左邊的內容View
     */
    private View mLeftView;

    /*
        側滑菜單View
     */
    private View mMenuView;

    private float mOldX;

    private float mOldY;

    /*
     * 屏幕的寬度
     */
    private int mScreenWidth;

    /**
     * 控件能夠移動到的左邊界,內容View能向左偏移的最大邊界
     */
    private int mLeftEdge ;

    public SlideLayout(Context context) {
        super(context);
        mContext = context;
    }

    public SlideLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
        mContext = context;
    }

    /**
     * 佈局
     */
    public void onLayout(boolean change, int l, int t, int r, int b) {
        super.onLayout(change, l, t, r, b);
        if( change && !mLoadOnece) {
            mLeftEdge = ScreenUtil.dp2px(300);
            mLeftView = findViewById(R.id.slide_content);
            mMenuView = findViewById(R.id.slide_menu);
            mLeftParams =  (MarginLayoutParams) mLeftView.getLayoutParams();
            mMenuParams = (MarginLayoutParams)mMenuView.getLayoutParams();
            DisplayMetrics dm = getResources().getDisplayMetrics();
            mScreenWidth = dm.widthPixels;
            mLoadOnece = true;
        }
    }

    /**
     * 事件攔截
     * @param e
     * @return
     *  true 表示攔截子類的Touch事件
     *  false 表示
     */
    public boolean onInterceptTouchEvent(MotionEvent e) {
        int action  = e.getAction();
        switch( action ) {
            case MotionEvent.ACTION_DOWN:
                return false;
            case MotionEvent.ACTION_MOVE:
                mOldX = e.getRawX();
                break;
            case MotionEvent.ACTION_UP:
                break;
        }
        return true;
    }

    public boolean onTouchEvent(MotionEvent e) {
        int action = e.getAction();
        switch( action ) {
            case MotionEvent.ACTION_DOWN:
                //e.getX()得到的是相對當前容器的座標
                mOldX = e.getRawX();
                mOldY = e.getRawY();
                break;
            case MotionEvent.ACTION_MOVE:
                float x = e.getRawX();
                float y = e.getRawY();
                if( y - mOldY > 20 || y - mOldY < -20) {
                    return false;
                }
                //獲取移動了多少個px
                int moveX = (int)(x - mOldX);
                mOldX = x;
                mOldY = y;

                //側滑
                modifyLeftMargin(mLeftParams.leftMargin + moveX);
                break;
            case MotionEvent.ACTION_UP:
                //當手指拿起時,計算是向哪邊滑動
                int l = mLeftParams.leftMargin > (-mLeftEdge / 2) ? 0 : -mLeftEdge;
                new SmoothScrollTack().execute(l, mLeftParams.leftMargin);
                break;
        }
        return true;
    }

    /**
     * 修改View的邊距來達到移動的效果
     * @param leftMargin
     */
    private void modifyLeftMargin(int leftMargin) {
        //如果左邊距大於0代表將要向右變壓縮,應該禁止
        if( leftMargin > 0 ) {
            mLeftParams.leftMargin = 0;
            mMenuView.setTranslationX(0);
            //控制左邊界滑動
        } else if( leftMargin < -mLeftEdge) {
            mLeftParams.leftMargin = -mLeftEdge;
            mMenuView.setTranslationX(-mLeftEdge / 2);
        } else {
            mLeftParams.leftMargin = leftMargin;
            mMenuView.setTranslationX(leftMargin / 2);
        }
        mLeftParams.width = mScreenWidth;
        mLeftView.setLayoutParams(mLeftParams);
    }

    /**
     * 當側滑停止的時候來處理接下來的滑動
     */
    private class SmoothScrollTack extends AsyncTask<Integer, Integer, Integer> {

        @Override
        protected void onProgressUpdate(Integer... values) {
            int leftMargin = values[0];
            modifyLeftMargin(leftMargin);
        }

        /**
         * 計算下一個leftMargin值
         * @param params
         * @return
         */
        @Override
        protected Integer doInBackground(Integer... params) {
            int targetLeftMargin = params[0];
            int currentLeftMargin = params[1];
            int leftMargin = currentLeftMargin;
            //計算增加的步長
            int step = targetLeftMargin == 0 ? 10 : -10;
            while(true) {
                leftMargin += step;
                //判斷是否滑動完成
                if( leftMargin < -mLeftEdge ) {
                    leftMargin = -mLeftEdge;
                    break;
                }
                if( leftMargin > 0 ) {
                    leftMargin = 0;
                    break;
                }

                publishProgress(leftMargin);
                try {
                    Thread.sleep(5);
                } catch( InterruptedException e) {
                    e.printStackTrace();
                }
            }
            publishProgress(leftMargin);
            return leftMargin;
        }
    }

}

ScreenUtil:

package cn.karent.slide.util;

import android.util.DisplayMetrics;
import android.util.Log;

/**
 * Created by wan on 2016/12/22.
 *
 */
public class ScreenUtil  {

    /**
     * 獲取屏幕的密度
     * @return
     */
    public static float getDensity() {
        DisplayMetrics dm = MyApplication.getContext().getResources().getDisplayMetrics();
        float density = dm.density;
        Log.d("density", density + "");
        return density;
    }

    public static DisplayMetrics getDislayMetrics() {
        return MyApplication.getContext().getResources().getDisplayMetrics();
    }

    public static int px2dp(float p) {
        float density = getDensity();
        return (int)(p / density + 0.5f);
    }

    public static int dp2px(float dip) {
        return (int)(dip * getDensity() + 0.5f);
    }

}

獲取全局的Context:

package cn.karent.slide.util;

import android.app.Application;
import android.content.Context;

/**
 * Created by wan on 2016/12/22.
 * 獲取全局Context對象
 */
public class MyApplication extends Application {

    private static Context mContext;

    @Override
    public void onCreate() {
        mContext = getApplicationContext();
        super.onCreate();
    }

    public static Context getContext() {
        return mContext;
    }
}

androidManifest.xml:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="cn.karent.slide">

    <application
        android:name=".util.MyApplication"
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@android:style/Theme.NoTitleBar">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

只要在下面使用android:name=”.util.MyApplication”那麼我們自己定義的Application就會覆蓋系統默認的Application了

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