侧滑面板

  1. 自定义FrameLayout,在布局里面引用,并添加两个LinearLayout作为子view。
  2. 导入最新support-v4包,使用ViewDragHelper辅助类,构造方法初始化。 ViewDragHelper.create(this, 1.0f, callback);

实例化callback

    // 1. 返回值, 决定了child是否可以被拖拽
    @Override
        public boolean tryCaptureView(View child, int pointerId) {
            return false;
        }
    @Override
    public void onViewDragStateChanged(int state) {
        super.onViewDragStateChanged(state);
    }

3.转交触摸事件给ViewDragHelper。

    public boolean onInterceptTouchEvent(android.view.MotionEvent ev) {
        // 由 ViewDragHelper 判断触摸事件是否该拦截
        return mHelper.shouldInterceptTouchEvent(ev);
    }   

    public boolean onTouchEvent(MotionEvent event) {
        // 由 ViewDragHelper 处理事件
        try {
            mHelper.processTouchEvent(event);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return true;
    }

4.在onSizedChange去获取宽高,getMeasuredWidth,getMeasuredHeight,设置拖拽范围。

5.

// 2. 返回拖拽的范围. 返回一个 >0 的值, 决定了动画的执行时长, 水平方向是否可以被滑开
@Override
public int getViewHorizontalDragRange(View child) {
    return mRange;
};
// 3. 修正子View水平方向的位置. 此时还没有发生真正的移动.
// 返回值决定了View将会移动到的位置
public int clampViewPositionHorizontal(View child, int left, int dx) {
    // child 被拖拽的子View
    // left 建议移动到的位置
    // dx 跟旧的位置的差值

    if(child == mMainContent){
        left = fixLeft(left);
    }
    return left;
}

6.

// 4. 当控件位置变化时 调用, 可以做 : 伴随动画, 状态的更新, 事件的回调.
@Override
public void onViewPositionChanged(View changedView, int left, int top,
        int dx, int dy) {
    // left最新的水平方向的位置
    // dx 刚刚发生的水平变化量

    if(changedView == mLeftContent){
        // 如果移动的是左面板
        // 1. 放回原来的位置
        mLeftContent.layout(0, 0, 0 + mWidth, 0 + mHeight);
        // 2. 把左面板发生的变化量dx转递给主面板
        int newLeft = mMainContent.getLeft() + dx;

        // 修正左边值.
        newLeft = fixLeft(newLeft);
        mMainContent.layout(newLeft, 0, newLeft + mWidth, 0 + mHeight);
    }

    dispatchDragEvent();

    // 为了兼容低版本, 手动重绘界面所有内容.
    invalidate();
}

7.

    //5. 决定了松手之后要做的事情, 结束的动画
    @Override
    public void onViewReleased(View releasedChild, float xvel, float yvel) {
        super.onViewReleased(releasedChild, xvel, yvel);
        System.out.println("onViewReleased: xvel: " + xvel);
        // releasedChild 被释放的孩子
        // xvel 水平方向的速度 向右为+,  向左为-
        if(xvel == 0 && mMainContent.getLeft() > mRange * 0.5f){
            open();
        } else if (xvel > 0) {
            open();
        } else {
            close();
        }

    }

8.做平滑移动开关动画

if(mHelper.smoothSlideViewTo(mMainContent, finalLeft, 0)){
    // 如果当前位置不是指定的最终位置. 返回true
    // 需要重绘界面, 一定要传 子View 所在的容器
    ViewCompat.postInvalidateOnAnimation(this);
}
//2. 维持动画的继续, 高频率调用.
@Override
public void computeScroll() {
    super.computeScroll();

    if(mHelper.continueSettling(true)){
        // 如果当前位置还没有移动到最终位置. 返回true.需要继续重绘界面
        ViewCompat.postInvalidateOnAnimation(this);
    }
}

9.拖拽伴随动画

/**
 * 分发拖拽事件, 伴随动画,更新状态.
 */
protected void dispatchDragEvent() {
    // 0.0 -> 1.0  
    float percent = mMainContent.getLeft() * 1.0f / mRange;
    System.out.println("percent: " + percent);

    if(onDragChangeListener != null){
        onDragChangeListener.onDraging(percent);
    }

    // 更新状态
    Status lastStatus = status;
    status = updateStatus(percent);
    if(lastStatus != status && onDragChangeListener != null){
        if(status == Status.Close){
            onDragChangeListener.onClose();
        }else if (status == Status.Open) {
            onDragChangeListener.onOpen();
        }
    }   

    // 执行动画
    animViews(percent);
}
private void animViews(float percent) {
    //      - 左面板: 缩放动画, 平移动画, 透明度动画
            // 缩放动画 0.0 -> 1.0  >>> 0.0 -> 0.5 >>>0.5 -> 1.0
            // percent * 0.5 + 0.5
    //      mLeftContent.setScaleX(percent * 0.5f + 0.5f);
    //      mLeftContent.setScaleY(percent * 0.5f + 0.5f);
            ViewHelper.setScaleX(mLeftContent, evaluate(percent, 0.5f, 1.0f));
            ViewHelper.setScaleY(mLeftContent, evaluate(percent, 0.5f, 1.0f));

    //      平移动画 -mWidth / 2.0f -> 0
            ViewHelper.setTranslationX(mLeftContent, evaluate(percent,  -mWidth / 2.0f, 0));

            // 透明度动画 0.2f -> 1.0
            ViewHelper.setAlpha(mLeftContent, evaluate(percent,  0.2f, 1.0f));

    //      - 主面板: 缩放动画 1.0 -> 0.8
            ViewHelper.setScaleX(mMainContent, evaluate(percent, 1.0f, 0.8f));
            ViewHelper.setScaleY(mMainContent, evaluate(percent, 1.0f, 0.8f));

    //      - 背  景: 亮度变化
            getBackground().setColorFilter((Integer)evaluateColor(percent, Color.BLACK, Color.TRANSPARENT), PorterDuff.Mode.SRC_OVER);
}

10.侧边栏状态

public static enum Status {
    Close, Open, Draging
}
public interface OnDragChangeListener {
    void onClose();

    void onOpen();

    void onDraging(float percent);
}

private OnDragChangeListener onDragChangeListener;

public Status getStatus() {
    return status;
}

public void setStatus(Status status) {
    this.status = status;
}

public OnDragChangeListener getOnDragChangeListener() {
    return onDragChangeListener;
}

public void setOnDragChangeListener(OnDragChangeListener onDragChangeListener) {
    this.onDragChangeListener = onDragChangeListener;
}
/**
 * 更新状态
 * @param percent 当前动画执行的百分比
 * @return
 */
private Status updateStatus(float percent) {
    if(percent == 0){
        return Status.Close;
    }else if (percent == 1) {
        return Status.Open;
    }
    return Status.Draging;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值