Assigned
Status Update
Comments
as...@google.com <as...@google.com>
ki...@google.com <ki...@google.com> #2
This is coming from nested scrolling behavior. You can debug the logic in CoordinatorLayout.onNestedScroll to see if the specific child is GONE, or its LayoutParams return false in isNestedScrollAccepted.
al...@gmail.com <al...@gmail.com> #3
I debugged the code as you mentioned : onNestedScroll never get called in nested scrolling behavior, but onNestedScrollAccepted, onNestedPreScroll and onNestedFling get called. Is there any solution to have a call on CoordinatorLayout.onNestedScroll? Here is my layout :
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android "
xmlns:app="http://schemas.android.com/apk/res-auto "
xmlns:tools="http://schemas.android.com/tools "
android:layout_width="wrap_content"
android:layout_height="wrap_content"
tools:context=".ui.MainActivity">
<androidx.viewpager.widget.ViewPager
android:id="@+id/view_pager"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_behavior=".behavior.QuickHideBottomBarBehavior">
<com.sample.android.contact.widget.ListenableTabLayout
android:id="@+id/tab_layout"
android:layout_width="match_parent"
android:layout_height="48dp"
android:layout_alignParentBottom="true"
android:background="@drawable/rectangle_shape"
app:tabIndicatorHeight="2dp"
app:tabSelectedTextColor="@color/color1" />
<ImageView
android:id="@+id/triangle"
android:layout_width="30dp"
android:layout_height="30dp"
android:layout_above="@+id/tab_layout"
android:layout_marginBottom="@dimen/dimen_triangle_bottom_margin"
android:src="@drawable/triangle_shape"
tools:ignore="ContentDescription" />
</RelativeLayout>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="
xmlns:app="
xmlns:tools="
android:layout_width="wrap_content"
android:layout_height="wrap_content"
tools:context=".ui.MainActivity">
<androidx.viewpager.widget.ViewPager
android:id="@+id/view_pager"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_behavior=".behavior.QuickHideBottomBarBehavior">
<com.sample.android.contact.widget.ListenableTabLayout
android:id="@+id/tab_layout"
android:layout_width="match_parent"
android:layout_height="48dp"
android:layout_alignParentBottom="true"
android:background="@drawable/rectangle_shape"
app:tabIndicatorHeight="2dp"
app:tabSelectedTextColor="@color/color1" />
<ImageView
android:id="@+id/triangle"
android:layout_width="30dp"
android:layout_height="30dp"
android:layout_above="@+id/tab_layout"
android:layout_marginBottom="@dimen/dimen_triangle_bottom_margin"
android:src="@drawable/triangle_shape"
tools:ignore="ContentDescription" />
</RelativeLayout>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
Description
I have following CoordinatorLayout behavior class :
public abstract class QuickHideBehavior extends CoordinatorLayout.Behavior<View> {
private static final int DIRECTION_UP = 1;
private static final int DIRECTION_DOWN = -1;
/* Tracking direction of user motion */
private int mScrollingDirection;
/* Tracking last threshold crossed */
private int mScrollTrigger;
/* Accumulated scroll distance */
private int mScrollDistance;
/* Distance threshold to trigger animation */
private int mScrollThreshold;
private ObjectAnimator mAnimator;
protected View mRecyclerView;
protected abstract float getTargetHideValue(ViewGroup parent, View target);
protected abstract void setMarginUpScroll();
protected abstract void setMarginDownScroll();
//Required to instantiate as a default behavior
@SuppressWarnings("unused")
public QuickHideBehavior() {
}
//Required to attach behavior via XML
@SuppressWarnings("unused")
public QuickHideBehavior(Context context, AttributeSet attrs) {
super(context, attrs);
TypedArray a = context.getTheme()
.obtainStyledAttributes(new int[] {R.attr.actionBarSize});
//Use half the standard action bar height
mScrollThreshold = a.getDimensionPixelSize(0, 0) / 2;
a.recycle();
}
@Override
public boolean onLayoutChild(@NonNull CoordinatorLayout parent, @NonNull View child,
int layoutDirection) {
if (mRecyclerView == null) {
mRecyclerView = parent.findViewById(R.id.recyclerView);
}
return super.onLayoutChild(parent, child, layoutDirection);
}
//Called before a nested scroll event. Return true to declare interest
@Override
public boolean onStartNestedScroll(@NonNull CoordinatorLayout coordinatorLayout,
@NonNull View child, @NonNull View directTargetChild,
@NonNull View target, int nestedScrollAxes, int type) {
//We have to declare interest in the scroll to receive further events
return (nestedScrollAxes & ViewCompat.SCROLL_AXIS_VERTICAL) != 0;
}
//Called before the scrolling child consumes the event
// We can steal all/part of the event by filling in the consumed array
@Override
public void onNestedPreScroll(CoordinatorLayout coordinatorLayout,
View child, View target,
int dx, int dy,
int[] consumed) {
//Determine direction changes here
if (dy > 0 && mScrollingDirection != DIRECTION_UP) {
mScrollingDirection = DIRECTION_UP;
mScrollDistance = 0;
} else if (dy < 0 && mScrollingDirection != DIRECTION_DOWN) {
mScrollingDirection = DIRECTION_DOWN;
mScrollDistance = 0;
}
}
//Called after the scrolling child consumes the event, with amount consumed
@Override
public void onNestedScroll(CoordinatorLayout coordinatorLayout,
View child, View target,
int dxConsumed, int dyConsumed,
int dxUnconsumed, int dyUnconsumed) {
//Consumed distance is the actual distance traveled by the scrolling view
mScrollDistance += dyConsumed;
if (mScrollDistance > mScrollThreshold
&& mScrollTrigger != DIRECTION_UP) {
//Hide the target view
mScrollTrigger = DIRECTION_UP;
restartAnimator(child, getTargetHideValue(coordinatorLayout, child));
} else if (mScrollDistance < -mScrollThreshold
&& mScrollTrigger != DIRECTION_DOWN) {
//Return the target view
mScrollTrigger = DIRECTION_DOWN;
restartAnimator(child, 0f);
}
}
//Called after the scrolling child handles the fling
@Override
public boolean onNestedFling(@NonNull CoordinatorLayout coordinatorLayout,
@NonNull View child, @NonNull View target, float velocityX,
float velocityY, boolean consumed) {
//We only care when the target view is already handling the fling
if (consumed) {
if (velocityY > 0 && mScrollTrigger != DIRECTION_UP) {
mScrollTrigger = DIRECTION_UP;
restartAnimator(child, getTargetHideValue(coordinatorLayout, child));
setMarginUpScroll();
} else if (velocityY < 0 && mScrollTrigger != DIRECTION_DOWN) {
mScrollTrigger = DIRECTION_DOWN;
restartAnimator(child, 0f);
setMarginDownScroll();
}
}
return false;
}
}
I want to hide/show following layout using above CoordinatorLayout behavior :
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_behavior=".behavior.QuickHideBottomBarBehavior">
<com.sample.android.contact.widget.ListenableTabLayout
android:id="@+id/tab_layout"
android:layout_width="match_parent"
android:layout_height="48dp"
android:layout_alignParentBottom="true"
android:background="@drawable/rectangle_shape"
app:tabIndicatorHeight="2dp"
app:tabSelectedTextColor="@color/color1" />
<ImageView
android:id="@+id/triangle"
android:layout_width="30dp"
android:layout_height="30dp"
android:layout_above="@+id/tab_layout"
android:layout_marginBottom="@dimen/dimen_triangle_bottom_margin"
android:src="@drawable/triangle_shape"
tools:ignore="ContentDescription" />
</RelativeLayout>
For some reason onNestedScroll never get called. But it is working very well for the appBarLayout:
<com.google.android.material.appbar.AppBarLayout
android:id="@+id/appBarLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_behavior=".behavior.QuickHideAppBarBehavior"
app:showData="@{vm.liveData}">
Why onNestedPreScroll get called but onNestedScroll never get called for FooterLayout which is a RelativeLayout in my case?