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;
}
}
};