NestedScrollWebview实现与优化

好久没写了,好像也没什么人关注我,呵呵,但我还是坚持写一下,希望能帮到有需要的人!

今天我来说一下NestedScrollWebview。


最近在弄一个需求,我需要用到coordinatorlayout + webview 实现滚动交互效果,但要实现该效果子view必须是要实现NestedScrollingChild接口的,很可惜原生webview并没有实现这接口。

网上找到能实现这种需求的有两种方法:

1)NestedScrollView 嵌套 webview

这种方法我试过,确实可以达到效果,但有一个比较坑的问题。就是webview的高度变成网页高度,导致网页滚动事件的缺失,如果网页需要监听滚动事件实现某些效果时(如图片懒加载)这时就会失效。


2)NestedScrollWebview

google官方并没有提供这个控件,网上能找到的就是rhlff大神写的一个控件(https://github.com/rhlff/NestedScrollWebView),我也用了这个控件,但实际效果比较差,滚动时网页会抖动。


为了实现需求,只能改大神的代码了,看了一轮大神的代码后我修改了事件分发时的逻辑,实测效果跟上述第一种方法效果相似且没有副作用,详细代码如下:

/**
 * Created by moj on 2017/8/28.
 */

public class NestedScrollWebView extends WebView implements NestedScrollingChild {

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

	private int mLastMotionY;

	private final int[] mScrollOffset = new int[2];
	private final int[] mScrollConsumed = new int[2];

	private int mNestedYOffset;
	private boolean mChange;

	private NestedScrollingChildHelper mChildHelper;

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

	public NestedScrollWebView(Context context, AttributeSet attrs) {
		super(context, attrs);
		init();
	}

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

	private void init() {
		mChildHelper = new NestedScrollingChildHelper(this);
		setNestedScrollingEnabled(true);
	}

	private float downx;
	private float downy;
	private MotionEvent b;
	@Override
	public boolean onTouchEvent(MotionEvent event) {
		boolean result = false;

		MotionEvent trackedEvent = MotionEvent.obtain(event);

		final int action = MotionEventCompat.getActionMasked(event);

		if (action == MotionEvent.ACTION_DOWN) {
			mNestedYOffset = 0;
		}

		int y = (int) event.getY();

		event.offsetLocation(0, mNestedYOffset);

		switch (action) {
			case MotionEvent.ACTION_DOWN:
				mLastMotionY = y;
				startNestedScroll(ViewCompat.SCROLL_AXIS_VERTICAL);
				result = super.onTouchEvent(event);
				mChange = false;
				downx = event.getX();
				downy = event.getY();
				b = MotionEvent.obtain(event);
				break;
			case MotionEvent.ACTION_MOVE:
				int deltaY = mLastMotionY - y;

				if (dispatchNestedPreScroll(0, deltaY, mScrollConsumed, mScrollOffset)) {
					deltaY -= mScrollConsumed[1];
					trackedEvent.offsetLocation(0, mScrollOffset[1]);
					mNestedYOffset += mScrollOffset[1];
				}

				int oldY = getScrollY();
				mLastMotionY = y - mScrollOffset[1];
				int newScrollY = Math.max(0, oldY + deltaY);
				deltaY -= newScrollY - oldY;
				if (dispatchNestedScroll(0, newScrollY - deltaY, 0, deltaY, mScrollOffset)) {
					mLastMotionY -= mScrollOffset[1];
					trackedEvent.offsetLocation(0, mScrollOffset[1]);
					mNestedYOffset += mScrollOffset[1];
				}
				if(mScrollConsumed[1]==0 && mScrollOffset[1]==0) {
					if(mChange){
						mChange =false;
						trackedEvent.setAction(MotionEvent.ACTION_DOWN);
						super.onTouchEvent(trackedEvent);
					}else {
						result = super.onTouchEvent(trackedEvent);
					}
					trackedEvent.recycle();
				}else{
					if(!mChange){
						mChange =true;
						super.onTouchEvent(MotionEvent.obtain(0,0,MotionEvent.ACTION_CANCEL,0,0,0));
					}

				}
				break;
			case MotionEvent.ACTION_POINTER_DOWN:
			case MotionEvent.ACTION_UP:
			case MotionEvent.ACTION_CANCEL:
				stopNestedScroll();
				result = super.onTouchEvent(event);
				break;
		}
		return result;
	}

	// NestedScrollingChild

	@Override
	public void setNestedScrollingEnabled(boolean enabled) {
		mChildHelper.setNestedScrollingEnabled(enabled);
	}

	@Override
	public boolean isNestedScrollingEnabled() {
		return mChildHelper.isNestedScrollingEnabled();
	}

	@Override
	public boolean startNestedScroll(int axes) {
		return mChildHelper.startNestedScroll(axes);
	}

	@Override
	public void stopNestedScroll() {
		mChildHelper.stopNestedScroll();
	}

	@Override
	public boolean hasNestedScrollingParent() {
		return mChildHelper.hasNestedScrollingParent();
	}

	@Override
	public boolean dispatchNestedScroll(int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed, int[] offsetInWindow) {
		return mChildHelper.dispatchNestedScroll(dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed, offsetInWindow);
	}

	@Override
	public boolean dispatchNestedPreScroll(int dx, int dy, int[] consumed, int[] offsetInWindow) {
		return mChildHelper.dispatchNestedPreScroll(dx, dy, consumed, offsetInWindow);
	}

	@Override
	public boolean dispatchNestedFling(float velocityX, float velocityY, boolean consumed) {
		return mChildHelper.dispatchNestedFling(velocityX, velocityY, consumed);
	}

	@Override
	public boolean dispatchNestedPreFling(float velocityX, float velocityY) {
		return mChildHelper.dispatchNestedPreFling(velocityX, velocityY);
	}


GitHub传送门

有问题请评论,或留下QQ方便联系

评论 32
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值