自定义控件之QQ5.0侧滑效果

/*
 *  @Copyright (c) tianchenglin
 *  @Author TCL
 *  @Date 2016.6.22
 */

package com.study.tcl.studio.view;

import android.content.Context;
import android.graphics.Color;
import android.graphics.PorterDuff;
import android.support.v4.view.ViewCompat;
import android.support.v4.widget.ViewDragHelper;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.widget.FrameLayout;

import com.nineoldandroids.animation.FloatEvaluator;
import com.nineoldandroids.animation.IntEvaluator;
import com.nineoldandroids.view.ViewHelper;
import com.study.tcl.studio.utils.ColorUtil;

/**
 * Created by TCL on 2016/6/22.
 */
public class SlideMenu extends FrameLayout {
    private View menuView;
    private View mainView;
    private ViewDragHelper mViewDragHelper;
    private int width;
    float dragRange;//拖拽范围

    private onDragStateChangeListener mOnDragStateChangeListener;//拖拽的回调

    //定义状态常量
    public enum DragState {
        Open, Close;
    }

    private DragState mCurrentState = DragState.Close;


    public SlideMenu(Context context) {
        super(context);
        init();
    }

    public SlideMenu(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }

    public SlideMenu(Context context, AttributeSet attrs) {

        super(context, attrs);
        init();
    }

    private void init() {
        mViewDragHelper = ViewDragHelper.create(this, new ViewDragHelper.Callback() {
            @Override
            public boolean tryCaptureView(View child, int pointerId) {
                return child == menuView || child == mainView;
            }

            @Override
            public int getViewHorizontalDragRange(View child) {
                return (int) dragRange;
            }

            @Override
            public int clampViewPositionHorizontal(View child, int left, int dx) {
                if (child == mainView) {
                    if (left < 0) {
                        left = 0;//限制左边
                    }
                    if (left > dragRange) {
                        left = (int) dragRange;//限制右边
                    }
                }
                return left;
            }

            @Override
            public void onViewPositionChanged(View changedView, int left, int top, int dx, int dy) {
                super.onViewPositionChanged(changedView, left, top, dx, dy);

                if (changedView == menuView) {
                    //固定menuView
                    menuView.layout(0, 0, menuView.getMeasuredWidth(), menuView.getMeasuredHeight());

                    //限制边界
                    int newLeft = mainView.getLeft() + dx;
                    if (newLeft < 0) {
                        newLeft = 0;
                    }
                    if (newLeft > dragRange) {
                        newLeft = (int) dragRange;//限制右边
                    }
                    mainView.layout(newLeft, mainView.getTop() + dy, newLeft + mainView.getMeasuredWidth(),
                            mainView.getBottom() + dy);
                }


                //1.计算当前百分比
                float fraction = mainView.getLeft() / dragRange;
                //2.执行伴随动画
                executeAnim(fraction);
                //3.更改状态回调方法
                if (fraction == 0 && mCurrentState != DragState.Close) {
                    //更改状态为关闭,并回调关闭方法
                    mCurrentState = DragState.Close;
                    if (mOnDragStateChangeListener != null) {
                        mOnDragStateChangeListener.onClose();
                    }
                }

                if (fraction == 1 && mCurrentState != DragState.Open) {
                    //更改状态为打开,并回调关闭方法
                    mCurrentState = DragState.Open;
                    if (mOnDragStateChangeListener != null) {
                        mOnDragStateChangeListener.onOpen();
                    }
                }

                //将drag的fraction暴露给外界
                if (mOnDragStateChangeListener != null) {
                    mOnDragStateChangeListener.onDraging(fraction);
                }
            }

            @Override
            public void onViewReleased(View releasedChild, float xvel, float yvel) {
                super.onViewReleased(releasedChild, xvel, yvel);
                if (mainView.getLeft() < dragRange / 2) {
                    //在左半边
                    close();
                } else {
                    //在右半边
                    open();
                }
                //处理用户稍微滑动
                if (xvel > 200 && mCurrentState != DragState.Open) {
                    open();
                }
                if (xvel < -200 && mCurrentState != DragState.Close) {
                    close();
                }
            }
        });
    }

    public void open() {
        mViewDragHelper.smoothSlideViewTo(mainView, (int) dragRange, 0);
        ViewCompat.postInvalidateOnAnimation(SlideMenu.this);
    }

    public void close() {
        mViewDragHelper.smoothSlideViewTo(mainView, 0, 0);
        ViewCompat.postInvalidateOnAnimation(SlideMenu.this);
    }

    public interface onDragStateChangeListener {

        /**
         * 拖拽开始的回调
         */
        void onOpen();

        /**
         * 拖拽结束的回调
         */
        void onClose();

        /**
         * 拖拽中的回调
         *
         * @param fraction
         */
        void onDraging(float fraction);
    }


    /**
     * 获取当前状态
     *
     * @return
     */
    public DragState getCurrentState() {
        return mCurrentState;
    }

    public void setOnDragStateChangeListener(onDragStateChangeListener onDragStateChangeListener) {
        this.mOnDragStateChangeListener = onDragStateChangeListener;
    }

    /**
     * 执行伴随动画
     *
     * @param fraction
     */
    private void executeAnim(float fraction) {
        //fraction 0-1
        //缩小mainView
        FloatEvaluator floatEvaluator = new FloatEvaluator();//float的计算器
        ViewHelper.setScaleX(mainView, (Float) floatEvaluator.evaluate(fraction, 1f, 0.8f));
        ViewHelper.setScaleY(mainView, (Float) floatEvaluator.evaluate(fraction, 1f, 0.8f));

        //移动menuView
        IntEvaluator intEvaluator = new IntEvaluator();//int的计算器
        ViewHelper.setTranslationX(menuView, intEvaluator.evaluate(fraction, -menuView.getMeasuredWidth() /
                2, 0));

        //放大menuView
        ViewHelper.setScaleX(menuView, floatEvaluator.evaluate(fraction, 0.5, 1));
        ViewHelper.setScaleY(menuView, floatEvaluator.evaluate(fraction, 0.5, 1));

        //改变menuView的透明度
        ViewHelper.setAlpha(menuView, floatEvaluator.evaluate(fraction, 0.3, 1));

        //给SlideMenu添加黑色遮罩层效果
        getBackground().setColorFilter((Integer) ColorUtil.evaluateColor(fraction, Color.BLACK, Color.TRANSPARENT),
                PorterDuff.Mode.SRC_OVER);
    }

    @Override
    public void computeScroll() {
        if (mViewDragHelper.continueSettling(true)) {
            ViewCompat.postInvalidateOnAnimation(SlideMenu.this);
        }
    }

    /**
     * 该方法在OnMearsure执行后执行,那么可以在该方法中初始化自己和子view的宽高
     *
     * @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);
        width = getMeasuredWidth();
        dragRange = width * 0.6f;
    }

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

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        mViewDragHelper.processTouchEvent(event);
        return true;
    }

    @Override
    protected void onFinishInflate() {
        super.onFinishInflate();
        //简单的异常处理
        if (getChildCount() != 2) {
            throw new IllegalArgumentException("SlideMenu only have 2 children!");
        }
        menuView = getChildAt(0);
        mainView = getChildAt(1);
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值