侧滑菜单(一):带缩放动画

实现效果


实现代码

  • 新建项目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);
    }

   ...
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值