-
-
Save kelvinc1024/b1419de9ad6bbcdbb68bad72ff58e069 to your computer and use it in GitHub Desktop.
import android.content.Context; | |
import android.support.annotation.Nullable; | |
import android.support.design.widget.CoordinatorLayout; | |
import android.support.v4.view.NestedScrollingChild2; | |
import android.support.v4.view.NestedScrollingChildHelper; | |
import android.support.v4.view.ViewCompat; | |
import android.util.AttributeSet; | |
import android.view.View; | |
public class NestedScrollCoordinatorLayout extends CoordinatorLayout implements NestedScrollingChild2 { | |
private NestedScrollingChildHelper mChildHelper; | |
public NestedScrollCoordinatorLayout(Context context) { | |
super(context); | |
mChildHelper = new NestedScrollingChildHelper(this); | |
setNestedScrollingEnabled(true); | |
} | |
public NestedScrollCoordinatorLayout(Context context, AttributeSet attrs) { | |
super(context, attrs); | |
mChildHelper = new NestedScrollingChildHelper(this); | |
setNestedScrollingEnabled(true); | |
} | |
public NestedScrollCoordinatorLayout(Context context, AttributeSet attrs, int defStyleAttr) { | |
super(context, attrs, defStyleAttr); | |
mChildHelper = new NestedScrollingChildHelper(this); | |
setNestedScrollingEnabled(true); | |
} | |
@Override | |
public boolean isNestedScrollingEnabled() { | |
return mChildHelper.isNestedScrollingEnabled(); | |
} | |
@Override | |
public void setNestedScrollingEnabled(boolean enabled) { | |
mChildHelper.setNestedScrollingEnabled(enabled); | |
} | |
@Override | |
public boolean hasNestedScrollingParent() { | |
return mChildHelper.hasNestedScrollingParent(); | |
} | |
@Override | |
public boolean hasNestedScrollingParent(int type) { | |
return mChildHelper.hasNestedScrollingParent(type); | |
} | |
@Override | |
public boolean onStartNestedScroll(View child, View target, int axes, int type) { | |
boolean superResult = super.onStartNestedScroll(child, target, axes, type); | |
return startNestedScroll(axes, type) || superResult; | |
} | |
@Override | |
public boolean onStartNestedScroll(View child, View target, int nestedScrollAxes) { | |
boolean superResult = super.onStartNestedScroll(child, target, nestedScrollAxes); | |
return startNestedScroll(nestedScrollAxes) || superResult; | |
} | |
@Override | |
public void onNestedPreScroll(View target, int dx, int dy, int[] consumed, int type) { | |
dispatchNestedPreScroll(dx, dy, consumed, null, type); | |
if (consumed[1] == 0) { | |
super.onNestedPreScroll(target, dx, dy, consumed, type); | |
} | |
} | |
@Override | |
public void onNestedPreScroll(View target, int dx, int dy, int[] consumed) { | |
dispatchNestedPreScroll(dx, dy, consumed, null); | |
if (consumed[1] == 0) { | |
super.onNestedPreScroll(target, dx, dy, consumed, ViewCompat.TYPE_TOUCH); | |
} | |
} | |
@Override | |
public void onNestedScroll(View target, int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed, int type) { | |
super.onNestedScroll(target, dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed, type); | |
dispatchNestedScroll(dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed, null, type); | |
} | |
@Override | |
public void onNestedScroll(View target, int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed) { | |
super.onNestedScroll(target, dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed); | |
dispatchNestedScroll(dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed, null); | |
} | |
@Override | |
public void onStopNestedScroll(View target, int type) { | |
super.onStopNestedScroll(target, type); | |
stopNestedScroll(type); | |
} | |
@Override | |
public void onStopNestedScroll(View target) { | |
super.onStopNestedScroll(target); | |
stopNestedScroll(); | |
} | |
@Override | |
public boolean onNestedPreFling(View target, float velocityX, float velocityY) { | |
boolean superResult = super.onNestedPreFling(target, velocityX, velocityY); | |
return dispatchNestedPreFling(velocityX, velocityY) || superResult; | |
} | |
@Override | |
public boolean onNestedFling(View target, float velocityX, float velocityY, boolean consumed) { | |
boolean superResult = super.onNestedFling(target, velocityX, velocityY, consumed); | |
return dispatchNestedFling(velocityX, velocityY, consumed) || superResult; | |
} | |
@Override | |
public boolean startNestedScroll(int axes, int type) { | |
return mChildHelper.startNestedScroll(axes, type); | |
} | |
@Override | |
public boolean startNestedScroll(int axes) { | |
return mChildHelper.startNestedScroll(axes); | |
} | |
@Override | |
public void stopNestedScroll() { | |
mChildHelper.stopNestedScroll(); | |
} | |
@Override | |
public void stopNestedScroll(int type) { | |
mChildHelper.stopNestedScroll(type); | |
} | |
@Override | |
public boolean dispatchNestedScroll(int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed, @Nullable int[] offsetInWindow, int type) { | |
return mChildHelper.dispatchNestedScroll(dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed, offsetInWindow, type); | |
} | |
@Override | |
public boolean dispatchNestedScroll(int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed, @Nullable int[] offsetInWindow) { | |
return mChildHelper.dispatchNestedScroll(dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed, offsetInWindow); | |
} | |
@Override | |
public boolean dispatchNestedPreScroll(int dx, int dy, @Nullable int[] consumed, @Nullable int[] offsetInWindow) { | |
return mChildHelper.dispatchNestedPreScroll(dx, dy, consumed, offsetInWindow, ViewCompat.TYPE_TOUCH); | |
} | |
@Override | |
public boolean dispatchNestedPreScroll(int dx, int dy, @Nullable int[] consumed, @Nullable int[] offsetInWindow, int type) { | |
return mChildHelper.dispatchNestedPreScroll(dx, dy, consumed, offsetInWindow, type); | |
} | |
@Override | |
public boolean dispatchNestedPreFling(float velocityX, float velocityY) { | |
return mChildHelper.dispatchNestedPreFling(velocityX, velocityY); | |
} | |
@Override | |
public boolean dispatchNestedFling(float velocityX, float velocityY, boolean consumed) { | |
return mChildHelper.dispatchNestedFling(velocityX, velocityY, consumed); | |
} | |
} |
I loooooooove you soooooooo much, thx
Cautions
When you use this with coordinator layout on support library version 28.0.0+ version it will have some smoothness nested scrolling issue in some cases
This code tested work and work well in android support version 27.0.1
See issue tracker here
https://issuetracker.google.com/issues/115569344
Doesn't work when user scroll up. You have to implement NestedScrollingChild3 and method dispatchNestedScroll. It will work.
Add this:
override fun onNestedScroll(
target: View,
dxConsumed: Int,
dyConsumed: Int,
dxUnconsumed: Int,
dyUnconsumed: Int,
type: Int,
consumed: IntArray
) {
super.onNestedScroll(
target,
dxConsumed,
dyConsumed,
dxUnconsumed,
dyUnconsumed,
type,
consumed
)
dispatchNestedScroll(
dxConsumed,
dyConsumed,
dxUnconsumed,
dyUnconsumed,
null,
type,
consumed
)
}
override fun dispatchNestedScroll(
dxConsumed: Int,
dyConsumed: Int,
dxUnconsumed: Int,
dyUnconsumed: Int,
offsetInWindow: IntArray?,
type: Int,
consumed: IntArray
) {
mChildHelper.dispatchNestedScroll(
dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed, offsetInWindow, type, consumed
)
}
Doesn't work when user scroll up. You have to implement NestedScrollingChild3 and method dispatchNestedScroll. It will work. Add this:
override fun onNestedScroll( target: View, dxConsumed: Int, dyConsumed: Int, dxUnconsumed: Int, dyUnconsumed: Int, type: Int, consumed: IntArray ) { super.onNestedScroll( target, dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed, type, consumed ) dispatchNestedScroll( dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed, null, type, consumed ) }
override fun dispatchNestedScroll( dxConsumed: Int, dyConsumed: Int, dxUnconsumed: Int, dyUnconsumed: Int, offsetInWindow: IntArray?, type: Int, consumed: IntArray ) { mChildHelper.dispatchNestedScroll( dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed, offsetInWindow, type, consumed ) }
Thx! It was really helpful :)
This solution works, but based on my experience, it has some subtle nested scrolling bugs when there is more than one level of nesting. I spent a few days fixing it, and this seems to be the most reliable version:
class NestedScrollCoordinatorLayout @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
defStyleAttr: Int = 0,
) : CoordinatorLayout(context, attrs, defStyleAttr), NestedScrollingChild3 {
private val helper = NestedScrollingChildHelper(this)
init {
isNestedScrollingEnabled = true
}
override fun onStartNestedScroll(child: View, target: View, axes: Int, type: Int): Boolean {
val superResult = super.onStartNestedScroll(child, target, axes, type)
return startNestedScroll(axes, type) || superResult
}
override fun onStartNestedScroll(child: View, target: View, axes: Int): Boolean {
val superResult = super.onStartNestedScroll(child, target, axes)
return startNestedScroll(axes) || superResult
}
override fun onNestedPreScroll(target: View, dx: Int, dy: Int, consumed: IntArray, type: Int) {
val parentConsumed = intArrayOf(0, 0)
val thisConsumed = intArrayOf(0, 0)
// Dispatch the pre-scroll to the scrolling parent for it to consume first
dispatchNestedPreScroll(dx, dy, parentConsumed, null, type)
// Then let this view consume the rest
super.onNestedPreScroll(
target,
dx - parentConsumed[0],
dy - parentConsumed[1],
thisConsumed,
type,
)
// The final total consumed must take into account both the parent and this view's
// consumed
consumed[0] += thisConsumed[0] + parentConsumed[0]
consumed[1] += thisConsumed[1] + parentConsumed[1]
}
override fun onNestedPreScroll(target: View, dx: Int, dy: Int, consumed: IntArray) {
val parentConsumed = intArrayOf(0, 0)
val thisConsumed = intArrayOf(0, 0)
// Dispatch the pre-scroll to the scrolling parent for it to consume first
dispatchNestedPreScroll(dx, dy, parentConsumed, null)
// Then let this view consume the rest
super.onNestedPreScroll(
target,
dx - parentConsumed[0],
dy - parentConsumed[1],
thisConsumed,
)
// The final total consumed must take into account both the parent and this view's
// consumed
consumed[0] += thisConsumed[0] + parentConsumed[0]
consumed[1] += thisConsumed[1] + parentConsumed[1]
}
override fun onNestedScroll(
target: View,
dxConsumed: Int,
dyConsumed: Int,
dxUnconsumed: Int,
dyUnconsumed: Int,
type: Int,
consumed: IntArray,
) {
val parentConsumed = intArrayOf(0, 0)
val thisConsumed = intArrayOf(0, 0)
// Dispatch the newsted-scroll to the scrolling parent for it to consume first
dispatchNestedScroll(
dxConsumed,
dyConsumed,
dxUnconsumed,
dyUnconsumed,
null,
type,
thisConsumed,
)
// Then let this view consume the rest
super.onNestedScroll(
target,
dxConsumed + thisConsumed[0],
dyConsumed + thisConsumed[1],
dxUnconsumed - thisConsumed[0],
dyUnconsumed - thisConsumed[1],
type,
parentConsumed,
)
// The final total consumed must take into account both the parent and this view's
// consumed
consumed[0] += thisConsumed[0] + parentConsumed[0]
consumed[1] += thisConsumed[1] + parentConsumed[1]
}
override fun onNestedScroll(
target: View,
dxConsumed: Int,
dyConsumed: Int,
dxUnconsumed: Int,
dyUnconsumed: Int,
type: Int,
) {
dispatchNestedScroll(dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed, null, type)
super.onNestedScroll(target, dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed, type)
}
override fun onNestedScroll(
target: View,
dxConsumed: Int,
dyConsumed: Int,
dxUnconsumed: Int,
dyUnconsumed: Int,
) {
dispatchNestedScroll(dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed, null)
super.onNestedScroll(target, dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed)
}
override fun onStopNestedScroll(target: View, type: Int) {
super.onStopNestedScroll(target, type)
stopNestedScroll(type)
}
override fun onStopNestedScroll(target: View) {
super.onStopNestedScroll(target)
stopNestedScroll()
}
override fun onNestedPreFling(target: View, velocityX: Float, velocityY: Float): Boolean {
val superResult = super.onNestedPreFling(target, velocityX, velocityY)
return dispatchNestedPreFling(velocityX, velocityY) || superResult
}
override fun onNestedFling(
target: View,
velocityX: Float,
velocityY: Float,
consumed: Boolean,
): Boolean {
val superResult = super.onNestedFling(target, velocityX, velocityY, consumed)
return dispatchNestedFling(velocityX, velocityY, consumed) || superResult
}
override fun isNestedScrollingEnabled(): Boolean = helper.isNestedScrollingEnabled
override fun setNestedScrollingEnabled(enabled: Boolean) {
helper.isNestedScrollingEnabled = enabled
}
override fun hasNestedScrollingParent(type: Int): Boolean =
helper.hasNestedScrollingParent(type)
override fun hasNestedScrollingParent(): Boolean = helper.hasNestedScrollingParent()
override fun startNestedScroll(axes: Int, type: Int): Boolean =
helper.startNestedScroll(axes, type)
override fun startNestedScroll(axes: Int): Boolean = helper.startNestedScroll(axes)
override fun stopNestedScroll(type: Int) {
helper.stopNestedScroll(type)
}
override fun stopNestedScroll() {
helper.stopNestedScroll()
}
override fun dispatchNestedScroll(
dxConsumed: Int,
dyConsumed: Int,
dxUnconsumed: Int,
dyUnconsumed: Int,
offsetInWindow: IntArray?,
type: Int,
consumed: IntArray,
) {
helper.dispatchNestedScroll(
dxConsumed,
dyConsumed,
dxUnconsumed,
dyUnconsumed,
offsetInWindow,
type,
consumed,
)
}
override fun dispatchNestedScroll(
dxConsumed: Int,
dyConsumed: Int,
dxUnconsumed: Int,
dyUnconsumed: Int,
offsetInWindow: IntArray?,
type: Int,
): Boolean = helper.dispatchNestedScroll(
dxConsumed,
dyConsumed,
dxUnconsumed,
dyUnconsumed,
offsetInWindow,
type,
)
override fun dispatchNestedScroll(
dxConsumed: Int,
dyConsumed: Int,
dxUnconsumed: Int,
dyUnconsumed: Int,
offsetInWindow: IntArray?,
): Boolean = helper.dispatchNestedScroll(
dxConsumed,
dyConsumed,
dxUnconsumed,
dyUnconsumed,
offsetInWindow,
)
override fun dispatchNestedPreScroll(
dx: Int,
dy: Int,
consumed: IntArray?,
offsetInWindow: IntArray?,
type: Int,
): Boolean = helper.dispatchNestedPreScroll(dx, dy, consumed, offsetInWindow, type)
override fun dispatchNestedPreScroll(
dx: Int,
dy: Int,
consumed: IntArray?,
offsetInWindow: IntArray?,
): Boolean =
helper.dispatchNestedPreScroll(dx, dy, consumed, offsetInWindow)
override fun dispatchNestedPreFling(velocityX: Float, velocityY: Float): Boolean =
helper.dispatchNestedPreFling(velocityX, velocityY)
override fun dispatchNestedFling(
velocityX: Float,
velocityY: Float,
consumed: Boolean,
): Boolean =
helper.dispatchNestedFling(velocityX, velocityY, consumed)
}
Thank you,
this was very helpful.