下拉上拉带阻尼回弹的NestedScrollView

package com.artvrpro.yiwei.weight.view;

import android.content.Context;
import android.graphics.Rect;
import android.os.Handler;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.animation.Animation;
import android.view.animation.TranslateAnimation;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.widget.NestedScrollView;


/**
 * 自定义下拉上拉带阻尼回弹的NestedScrollView
 */
public class BounceNestedScrollView extends NestedScrollView {

    private View mInnerView;

    private float mDownY;
    private float mStartY;
    private float mCurrentY;

    private Rect mRect = new Rect();
    private int offset;

    private boolean isCount = false;

    boolean isMove = false;

    private int mWidth;
    private int mHeight;

    public BounceNestedScrollView(@NonNull Context context) {
        this(context, null);
    }

    public BounceNestedScrollView(@NonNull Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public BounceNestedScrollView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    @Override
    protected void onFinishInflate() {
        super.onFinishInflate();
        //获取的就是 scrollview 的第一个子 View
        if (getChildCount() > 0) {
            mInnerView = getChildAt(0);
        }
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);

        mWidth = MeasureSpec.getSize(widthMeasureSpec);
        mHeight = MeasureSpec.getSize(heightMeasureSpec);

        MarginLayoutParams lp = (MarginLayoutParams) mInnerView.getLayoutParams();
        //减去 margin 的值
        offset = mInnerView.getMeasuredHeight() - lp.topMargin - lp.bottomMargin - mHeight;
    }

    @Override
    public boolean onTouchEvent(MotionEvent e) {
        if (mInnerView != null) {
            commOnTouchEvent(e);
        }
        return super.onTouchEvent(e);
    }

    public void commOnTouchEvent(MotionEvent e) {
        switch (e.getAction()) {
            case MotionEvent.ACTION_DOWN:
                break;
            case MotionEvent.ACTION_MOVE:
                final float preY = mDownY;// 按下时的y坐标

                if (!isMove){
                    mStartY = e.getY();
                    isMove = true;
                }

                float nowY = e.getY();// 时时y坐标
                int deltaY = (int) (preY - nowY);// 滑动距离
                //排除出第一次移动计算无法得知y坐标
                if (!isCount) {
                    deltaY = 0;
                }

                mDownY = nowY;
                // 当滚动到最上或者最下时就不会再滚动,这时移动布局
                if (isNeedMove()) {
                    if (mRect.isEmpty()) {
                        // 保存正常的布局位置
                        mRect.set(mInnerView.getLeft(), mInnerView.getTop(),
                                mInnerView.getRight(), mInnerView.getBottom());
                    }
                    // 移动布局
                    mInnerView.layout(mInnerView.getLeft(), mInnerView.getTop() - deltaY / 2,
                            mInnerView.getRight(), mInnerView.getBottom() - deltaY / 2);
                }
                isCount = true;


//                int i  = DensityUtil.dp2px(getContext(),nowY);
//                int dp = DensityUtil.px2dip(getContext(),i);
                Log.d("BounceNestedScrollView", " deltaY = "+ (mStartY - nowY) + " nowY = "+nowY + " mStartY = "+mStartY);
                if ( mStartY - e.getY() < - 500 /*e.getY() > 1500*/){
                    mDistListener.getScrollDist();
                    new Handler().postDelayed(new Runnable() {
                        @Override
                        public void run() {
                            if (isNeedAnimation()) {
                                translateAnimator();
                                isCount = false;
                                isMove = false;
                            }
                        }
                    }, 500);


                }

                break;
            case MotionEvent.ACTION_UP:
                isMove = false;
                if (isNeedAnimation()) {
                    if ( mStartY - e.getY() < - 500) {
                        mTakeUpListener.getUpCallback();
                    }
                    translateAnimator();
                    isCount = false;
                }

                break;
        }
    }

    public interface distListener{
        void getScrollDist();
    }

    private distListener mDistListener;

    public void setDistListener(distListener mDistListener){
        this.mDistListener = mDistListener;

    }

    public interface TakeUpListener{
        void getUpCallback();
    }

    private TakeUpListener mTakeUpListener;

    public void setUpListener(TakeUpListener takeUpListener){
        this.mTakeUpListener = takeUpListener;

    }

    public void translateAnimator() {
        Animation animation = new TranslateAnimation(0, 0, mInnerView.getTop(), mRect.top);
        animation.setDuration(200);
        animation.setFillAfter(true);
        mInnerView.startAnimation(animation);
        // 设置回到正常的布局位置
        mInnerView.layout(mRect.left, mRect.top, mRect.right, mRect.bottom);
        mRect.setEmpty();
    }

    // 是否需要开启动画
    public boolean isNeedAnimation() {
        return !mRect.isEmpty();
    }

    public boolean isNeedMove() {
        if (getScrollY() == 0 || getScrollY() >= offset) {
            return true;
        }
        return false;
    }

}


xml:

<com.artvrpro.yiwei.weight.view.BounceNestedScrollView
            android:id="@+id/nestedscrollview"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:background="@color/transparent"
            app:behavior_hideable="false"
            android:layout_marginTop="@dimen/dp_140"

            >

//滑动控件里面的布局

        </com.artvrpro.yiwei.weight.view.BounceNestedScrollView>

代码中调用:

//添加上拉下拉监听
mNestedScrollview.setDistListener(this);
        mNestedScrollview.setUpListener(this);

boolean isScrollIn;
    @Override
    public void getScrollDist() {
        mHandler.sendEmptyMessage(1);



    }

    @Override
    public void getUpCallback() {
        mHandler.sendEmptyMessage(2);

    }


    Handler mHandler = new Handler(){
        @Override
        public void handleMessage(@NonNull Message msg) {
            super.handleMessage(msg);
            switch (msg.what){
                case 1:
//                    tv_scrollIn.setVisibility(View.VISIBLE);

                    
                    if (isScrollIn==false){


                                isScrollIn = true;
                                
                                //跳转activity


                    }
                    break;

                case 2:

                    break;
            }
        }
    };

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值