Java tutorial
/* * Copyright (C) 2015 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.customviewcollection.nestedscroll; import android.support.v4.view.ViewCompat; import android.support.v4.view.ViewGroupCompat; import android.support.v4.view.ViewParentCompat; import android.view.View; import android.view.ViewParent; /** * Helper class for implementing nested scrolling child views compatible with Android platform * versions earlier than Android 5.0 Lollipop (API 21). * <p> * <p>{@link android.view.View View} subclasses should instantiate a final instance of this * class as a field at construction. For each <code>View</code> method that has a matching * method signature in this class, delegate the operation to the helper instance in an overriden * method implementation. This implements the standard framework policy for nested scrolling.</p> * <p> * <p>Views invoking nested scrolling functionality should always do so from the relevant * {@link ViewCompat}, {@link ViewGroupCompat} or {@link ViewParentCompat} compatibility * shim static methods. This ensures interoperability with nested scrolling views on Android * 5.0 Lollipop and newer.</p> */ public class NestedScrollingChildHelper { private final View mView; private ViewParent mNestedScrollingParent; private boolean mIsNestedScrollingEnabled; private int[] mTempNestedScrollConsumed; /** * ?ViewNestedScrollingChildHelper */ public NestedScrollingChildHelper(View view) { mView = view; } /** * ?? */ public boolean isNestedScrollingEnabled() { return mIsNestedScrollingEnabled; } /** * ?View */ public boolean hasNestedScrollingParent() { return mNestedScrollingParent != null; } /** * View(?ViewView?) * ???ViewonStartNestedScroll onNestedScrollAccepted * * @param axes ???? * @return true ViewView? */ public boolean startNestedScroll(int axes) { if (hasNestedScrollingParent()) { // Already in progress return true; } if (isNestedScrollingEnabled()) { ViewParent p = mView.getParent(); View child = mView; while (p != null) { if (ViewParentCompat.onStartNestedScroll(p, child, mView, axes)) { mNestedScrollingParent = p; ViewParentCompat.onNestedScrollAccepted(p, child, mView, axes); return true; } if (p instanceof View) { child = (View) p; } p = p.getParent(); } } return false; } /** * ??(?View??ViewstopNestedScroll) * ?ViewonStopNestedScroll * ?{@link #stopNestedScroll()} * * @param enabled true ?? */ public void setNestedScrollingEnabled(boolean enabled) { if (mIsNestedScrollingEnabled) { //?21(?),View //: //if (mNestedScrollingParent != null) { // mNestedScrollingParent.onStopNestedScroll(this); // mNestedScrollingParent = null; //} ViewCompat.stopNestedScroll(mView); } mIsNestedScrollingEnabled = enabled; } /** * View? * ???ViewonStopNestedScroll * ?:parent.onStopNestedScroll(target); */ public void stopNestedScroll() { /** * :?ViewCompat.stopNestedScroll(mView); * ?{@link #setNestedScrollingEnabled(boolean)} * ViewCompat.stopNestedScroll(mView); * ??,{@link #setNestedScrollingEnabled(boolean)}?, * ViewCompat.stopNestedScroll(mView)? */ if (mNestedScrollingParent != null) { ViewParentCompat.onStopNestedScroll(mNestedScrollingParent, mView); mNestedScrollingParent = null; } } /** * ?View??View?View?NestedScrollingChild? * ???ViewonNestedScroll * ?offsetInWindow?? ?View?? * ???View??? * * @return true View */ public boolean dispatchNestedScroll(int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed, int[] offsetInWindow) { if (isNestedScrollingEnabled() && mNestedScrollingParent != null) { if (dxConsumed != 0 || dyConsumed != 0 || dxUnconsumed != 0 || dyUnconsumed != 0) { int startX = 0; int startY = 0; if (offsetInWindow != null) { mView.getLocationInWindow(offsetInWindow); startX = offsetInWindow[0]; startY = offsetInWindow[1]; } ViewParentCompat.onNestedScroll(mNestedScrollingParent, mView, dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed); if (offsetInWindow != null) { mView.getLocationInWindow(offsetInWindow); offsetInWindow[0] -= startX; offsetInWindow[1] -= startY; } return true; } else if (offsetInWindow != null) { // No motion, no dispatch. Keep offsetInWindow up to date. offsetInWindow[0] = 0; offsetInWindow[1] = 0; } } return false; } /** * ?View??View * ???NestedScrollingChild? * ???ViewonNestedPreScroll * ??offsetInWindow?View?consumed??View? * * @return true View */ public boolean dispatchNestedPreScroll(int dx, int dy, int[] consumed, int[] offsetInWindow) { if (isNestedScrollingEnabled() && mNestedScrollingParent != null) { if (dx != 0 || dy != 0) { int startX = 0; int startY = 0; if (offsetInWindow != null) { mView.getLocationInWindow(offsetInWindow); startX = offsetInWindow[0]; startY = offsetInWindow[1]; } if (consumed == null) { if (mTempNestedScrollConsumed == null) { mTempNestedScrollConsumed = new int[2]; } consumed = mTempNestedScrollConsumed; } consumed[0] = 0; consumed[1] = 0; ViewParentCompat.onNestedPreScroll(mNestedScrollingParent, mView, dx, dy, consumed); if (offsetInWindow != null) { mView.getLocationInWindow(offsetInWindow); offsetInWindow[0] -= startX; offsetInWindow[1] -= startY; } return consumed[0] != 0 || consumed[1] != 0; } else if (offsetInWindow != null) { offsetInWindow[0] = 0; offsetInWindow[1] = 0; } } return false; } /** * ?View fling?flingView * ???ViewonNestedFling * * @return true View fling */ public boolean dispatchNestedFling(float velocityX, float velocityY, boolean consumed) { if (isNestedScrollingEnabled() && mNestedScrollingParent != null) { return ViewParentCompat.onNestedFling(mNestedScrollingParent, mView, velocityX, velocityY, consumed); } return false; } /** * ?View fling? View fling * ???ViewonNestedPreFling * * @return true Viewfling */ public boolean dispatchNestedPreFling(float velocityX, float velocityY) { if (isNestedScrollingEnabled() && mNestedScrollingParent != null) { return ViewParentCompat.onNestedPreFling(mNestedScrollingParent, mView, velocityX, velocityY); } return false; } /** * ?View?? * ?View(?View)stopNestedScroll */ public void onDetachedFromWindow() { ViewCompat.stopNestedScroll(mView); } /** * ? * ?View(?View)stopNestedScroll */ public void onStopNestedScroll(View child) { ViewCompat.stopNestedScroll(mView); } }