为了账号安全,请及时绑定邮箱和手机立即绑定

Android NestedScrolling框架

标签:
Android

5b94dbbd0001a07203320522.jpg

package muzhi.nestedscrollingchild;

import android.annotation.TargetApi;
import android.content.Context;
import android.os.Build;
import android.support.v4.view.MotionEventCompat;
import android.support.v4.view.NestedScrollingChild;
import android.support.v4.view.NestedScrollingChildHelper;
import android.support.v4.view.ViewCompat;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;

/**
 * Created by Administrator on 2017/8/7.
 */
public class NestedChildView  extends View implements NestedScrollingChild{
    public static final String TAG = "NestedChildView";

    private final NestedScrollingChildHelper childHelper = new NestedScrollingChildHelper(this);
    private float downY;

    private int[] consumed = new int[2];
    private int[] offsetInWindow = new int[2];
    public NestedChildView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }
    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
    private void init() {
        setNestedScrollingEnabled(true);
    }

    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        final int actionMasked = MotionEventCompat.getActionMasked(event);

        // 取第一个接触屏幕的手指Id
        final int pointerId = MotionEventCompat.getPointerId(event, 0);
        switch (actionMasked) {
            case MotionEvent.ACTION_DOWN:

                // 取得当前的Y,并赋值给lastY变量
                downY = getPointerY(event, pointerId);
                // 找不到手指,放弃掉这个触摸事件流
                if (downY == -1) {
                    return false;
                }

                // 通知父View,开始滑动
                startNestedScroll(ViewCompat.SCROLL_AXIS_VERTICAL);
                break;
            case MotionEvent.ACTION_MOVE:

                // 获得当前手指的Y
                final float pointerY = getPointerY(event, pointerId);

                // 找不到手指,放弃掉这个触摸事件流
                if (pointerY == -1) {
                    return false;
                }

                // 计算出滑动的偏移量
                float deltaY = pointerY - downY;


                // 通知父View, 子View想滑动 deltaY 个偏移量,父View要不要先滑一下,然后把父View滑了多少,告诉子View一下
                // 下面这个方法的前两个参数为在x,y方向上想要滑动的偏移量
                // 第三个参数为一个长度为2的整型数组,父View将消费掉的距离放置在这个数组里面
                // 第四个参数为一个长度为2的整型数组,父View在屏幕里面的偏移量放置在这个数组里面
                // 返回值为 true,代表父View有消费任何的滑动.
                if (dispatchNestedPreScroll(0, (int) deltaY, consumed, offsetInWindow)) {

                    // 偏移量需要减掉被父View消费掉的,如果不减掉,子view和父view滑动的距离是不一样的
                    deltaY -= consumed[1];

                }

                // 上面的 (int)deltaY 会造成精度丢失,这里把精度给舍弃掉
                if(Math.floor(Math.abs(deltaY)) == 0) {
                    deltaY = 0;
                }

                // 这里移动子View,下面的min,max是为了控制边界,避免子View越界
                setY(Math.min(Math.max(getY() + deltaY, 0), ((View) getParent()).getHeight() - getHeight()));


                break;
        }
        return true;
    }
    /**
     * 这个方法通过pointerId获取pointerIndex,然后获取Y
     *
     */
    private float getPointerY(MotionEvent event, int pointerId) {
        final int pointerIndex = MotionEventCompat.findPointerIndex(event, pointerId);
        if (pointerIndex < 0) {
            return -1;
        }
        return MotionEventCompat.getY(event, pointerIndex);
    }

    /**
     * 设置事件分发允许
     * @param enabled
     */
    @Override
    public void setNestedScrollingEnabled(boolean enabled) {
        Log.d(TAG, String.format("setNestedScrollingEnabled , enabled = %b", enabled));
        childHelper.setNestedScrollingEnabled(enabled);
    }

    /**
     * 判断事件分发
     * @return
     */
    @Override
    public boolean isNestedScrollingEnabled() {
        Log.d(TAG, "isNestedScrollingEnabled");
        return childHelper.isNestedScrollingEnabled();
    }

    /**
     * 开始滑动前
     * @param axes
     * @return
     */
    @Override
    public boolean startNestedScroll(int axes) {
        Log.d(TAG, String.format("startNestedScroll , axes = %d", axes));
        return childHelper.startNestedScroll(axes);
    }

    /**
     * 停止滑动
     */
    @Override
    public void stopNestedScroll() {
        Log.d(TAG, "stopNestedScroll");
        childHelper.stopNestedScroll();
    }

    /**
     * 判断是否滑动父类
     * @return
     */
    @Override
    public boolean hasNestedScrollingParent() {
        Log.d(TAG, "hasNestedScrollingParent");
        return childHelper.hasNestedScrollingParent();
    }

    /**
     * 回调中获取父类消费了的距离
     * @param dxConsumed
     * @param dyConsumed
     * @param dxUnconsumed
     * @param dyUnconsumed
     * @param offsetInWindow
     * @return
     */
    @Override
    public boolean dispatchNestedScroll(int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed, int[] offsetInWindow) {
        final boolean b = childHelper.dispatchNestedScroll(dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed, offsetInWindow);
        return b;
    }

    /**
     * 也是获取值
     * @param dx
     * @param dy
     * @param consumed
     * @param offsetInWindow
     * @return
     */
    @Override
    public boolean dispatchNestedPreScroll(int dx, int dy, int[] consumed, int[] offsetInWindow) {
        final boolean b = childHelper.dispatchNestedPreScroll(dx, dy, consumed, offsetInWindow);
          return b;
    }

    /**
     * filing的时候获取
     * @param velocityX
     * @param velocityY
     * @param consumed
     * @return
     */
    @Override
    public boolean dispatchNestedFling(float velocityX, float velocityY, boolean consumed) {
        Log.d(TAG, String.format("dispatchNestedFling , velocityX = %f, velocityY = %f, consumed = %b", velocityX, velocityY, consumed));
        return childHelper.dispatchNestedFling(velocityX, velocityY, consumed);
    }

    @Override
    public boolean dispatchNestedPreFling(float velocityX, float velocityY) {
        Log.d(TAG, String.format("dispatchNestedPreFling , velocityX = %f, velocityY = %f", velocityX, velocityY));
        return childHelper.dispatchNestedPreFling(velocityX, velocityY);
    }
}

在父ViewGroup中
package muzhi.nestedscrollingchild;

import android.content.Context;
import android.support.v4.view.NestedScrollingChild;
import android.support.v4.view.NestedScrollingChildHelper;
import android.support.v4.view.NestedScrollingParent;
import android.support.v4.view.NestedScrollingParentHelper;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;

/**
 * Created by Administrator on 2017/8/7.
 */
public class NestedParentView  extends FrameLayout implements NestedScrollingParent {

    public static final String TAG = NestedParentView.class.getSimpleName();

    private NestedScrollingParentHelper parentHelper;

    public NestedParentView(Context context) {
        super(context);
    }

    public NestedParentView(Context context, AttributeSet attrs) {
        super(context, attrs);
        parentHelper = new NestedScrollingParentHelper(this);
    }
    @Override
    public boolean onStartNestedScroll(View child, View target, int nestedScrollAxes) {
        Log.d(TAG, String.format("onStartNestedScroll, child = %s, target = %s, nestedScrollAxes = %d", child, target, nestedScrollAxes));
        return true;
    }
    @Override
    public void onNestedScrollAccepted(View child, View target, int nestedScrollAxes) {
        Log.d(TAG, String.format("onNestedScrollAccepted, child = %s, target = %s, nestedScrollAxes = %d", child, target, nestedScrollAxes));
        parentHelper.onNestedScrollAccepted(child, target, nestedScrollAxes);
    }

    @Override
    public void onStopNestedScroll(View target) {
        Log.d(TAG, "onStopNestedScroll");
        parentHelper.onStopNestedScroll(target);
    }

    @Override
    public void onNestedScroll(View target, int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed) {
        Log.d(TAG, String.format("onNestedScroll, dxConsumed = %d, dyConsumed = %d, dxUnconsumed = %d, dyUnconsumed = %d", dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed));
    }

    @Override
    public void onNestedPreScroll(View target, int dx, int dy, int[] consumed) {
        //dy,就是直接表示一次的偏移量,方向和坐标系的相同,而且每一次的
        // 应该移动的Y距离
        Log.i("onNestedPreScroll","===================");
        Log.i("onNestedPreScroll","dy==="+dy);
        Log.i("onNestedPreScroll","getY==="+getY());

        final float shouldMoveY = getY() + dy;//表示最终停留的位置
        Log.i("onNestedPreScroll","shouldMoveY==="+shouldMoveY);
        // 获取到父View的容器的引用,这里假定父View容器是View
        final View parent = (View) getParent();

        int consumedY;
        // 如果超过了父View的上边界,只消费子View到父View上边的距离
        if (shouldMoveY <= 0) {
            consumedY = - (int) getY();//将它移动回来
        } else if (shouldMoveY >= parent.getHeight() - getHeight()) {
            // 如果超过了父View的下边界,只消费子View到父View
            consumedY = (int) (parent.getHeight() - getHeight() - getY());
        } else {
            // 其他情况下全部消费
            consumedY = dy;
        }
        Log.i("onNestedPreScroll"," getHeight()==="+  getHeight());
        Log.i("onNestedPreScroll"," parent.getHeight()==="+ parent.getHeight());
        Log.i("onNestedPreScroll","consumedY==="+consumedY);
        Log.i("onNestedPreScroll","===================");
        // 对父View进行移动
        setY(getY() + consumedY);

        // 将父View消费掉的放入consumed数组中
        consumed[1] = consumedY;

       }

    @Override
    public boolean onNestedFling(View target, float velocityX, float velocityY, boolean consumed) {
        Log.d(TAG, String.format("onNestedFling, velocityX = %f, velocityY = %f, consumed = %b", velocityX, velocityY, consumed));
        return true;
    }

    @Override
    public boolean onNestedPreFling(View target, float velocityX, float velocityY) {
        Log.d(TAG, String.format("onNestedPreFling, velocityX = %f, velocityY = %f", velocityX, velocityY));
        return true;
    }

    @Override
    public int getNestedScrollAxes() {
        Log.d(TAG, "getNestedScrollAxes");
        return parentHelper.getNestedScrollAxes();
    }
}

原文链接:http://www.apkbus.com/blog-880881-68576.html

点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消