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了

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值