Reputation: 467
I am trying to hide text view on scroll down and show on scroll up it's working fine if I have an item like 10 or 15 but it's not working the same if I have less item
in recyclerview
, I have expanded/collapse functionality so it's not the same sometimes
textview
not hiding/visible some times I don't understand I added this line to my view which I want to hide/show on scroll
app:layout_behavior="com.google.android.material.behavior.HideBottomViewOnScrollBehavior"
XML
<androidx.coordinatorlayout.widget.CoordinatorLayout
android:id="@+id/lnMain"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@mipmap/bg"
tools:context=".tab.history.view.HistoryFragment">
<com.google.android.material.appbar.AppBarLayout
android:id="@+id/mAppBarLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:elevation="0dp">
<RelativeLayout
android:id="@+id/lnActionBar"
android:layout_width="match_parent"
android:layout_height="?android:attr/actionBarSize"
android:background="@color/colorPrimary">
<TextView
android:id="@+id/tvtitle"
style="@style/fontMedium"
android:layout_width="wrap_content"
android:layout_height="?android:attr/actionBarSize"
android:layout_centerHorizontal="true"
android:gravity="center_vertical"
android:text="@string/beacon"
android:textColor="@color/white"
android:textSize="@dimen/header_font_size" />
</RelativeLayout>
</com.google.android.material.appbar.AppBarLayout>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rvBeacon"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipToPadding="false"
android:overScrollMode="never"
app:layout_behavior="@string/appbar_scrolling_view_behavior"
android:paddingBottom="@dimen/_40sdp"
android:scrollbars="none"
android:visibility="visible"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
tools:itemCount="10"
tools:listitem="@layout/raw_beacon" />
<TextView
android:id="@+id/btnBack"
style="@style/fontBold"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:layout_marginTop="@dimen/_10sdp"
android:layout_marginBottom="@dimen/_20sdp"
android:background="@drawable/background_button_yellow_20dp"
android:contentDescription="@string/back_button"
android:drawableStart="@drawable/ic_back"
android:layout_gravity="bottom|center_horizontal"
android:drawablePadding="@dimen/_5sdp"
android:gravity="center"
android:padding="@dimen/_10sdp"
android:text="@string/back_to_search"
android:textColor="@color/white"
android:textSize="@dimen/button_font_size"
android:visibility="@{!isScanning ? View.VISIBLE: View.GONE}"
app:layout_behavior="com.google.android.material.behavior.HideBottomViewOnScrollBehavior" />
</androidx.coordinatorlayout.widget.CoordinatorLayout>
this is what I did so far but it's not working every time
Note:- Please not I have a recyclerview
item which expands onclick so scroll and textview must behave according to that
Any help would be highly appriciated
Upvotes: 2
Views: 2042
Reputation: 11
There was a similar problem on Android 13. If there are fewer elements in the recyclerView and scrolling is not required, while you can open the keyboard, then if you swipe up, then HideBottomViewOnScrollBehavior hid the view and no longer showed it. Used S T's answer and extended the standard HideBottomViewOnScrollBehavior class:
class HideBottomViewOnRealScrollBehavior<V : View> @JvmOverloads constructor(
context: Context? = null,
attrs: AttributeSet? = null
) : HideBottomViewOnScrollBehavior<V>(context, attrs) {
private var dyDirectionSum = 0
override fun onNestedPreScroll(
coordinatorLayout: CoordinatorLayout,
child: V,
target: View,
dx: Int,
dy: Int,
consumed: IntArray,
type: Int
) {
if (dy > 0 && dyDirectionSum < 0 || dy < 0 && dyDirectionSum > 0) {
child.animate().cancel()
dyDirectionSum = 0
}
dyDirectionSum += dy
if (dyDirectionSum > child.height) {
slideDown(child)
} else if (dyDirectionSum < -child.height) {
slideUp(child)
}
}
}
Usage:
app:layout_behavior="your.package.HideBottomViewOnRealScrollBehavior"
Upvotes: 0
Reputation: 279
i don't know why HideBottomViewOnScrollBehavior
is not working for you
app:layout_behavior="com.google.android.material.behavior.HideBottomViewOnScrollBehavior"
may be it's beacause you have a expand/collapse functionality since you have only recyclerview only in screen so you can also perform this task by adding Custom ScrollListener
MyRecyclerScroll class
public abstract class MyRecyclerScroll extends RecyclerView.OnScrollListener {
private static final float HIDE_THRESHOLD = 100;
private static final float SHOW_THRESHOLD = 50;
int scrollDist = 0;
private boolean isVisible = true;
// We dont use this method because its action is called per pixel value change
@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
// Check scrolled distance against the minimum
if (isVisible && scrollDist > HIDE_THRESHOLD) {
// Hide fab & reset scrollDist
hide();
scrollDist = 0;
isVisible = false;
}
// -MINIMUM because scrolling up gives - dy values
else if (!isVisible && scrollDist < -SHOW_THRESHOLD) {
// Show fab & reset scrollDist
show();
scrollDist = 0;
isVisible = true;
}
// Whether we scroll up or down, calculate scroll distance
if ((isVisible && dy > 0) || (!isVisible && dy < 0)) {
scrollDist += dy;
}
}
public abstract void show();
public abstract void hide();
}
Activity/Fragment
binding.rvBeacon.addOnScrollListener(object : MyRecyclerScroll() {
override fun show() {
binding.btnBack.animate().translationY(0f).setInterpolator(DecelerateInterpolator(2f)).start()
}
override fun hide() {
binding.btnBack.animate().translationY(binding.btnBack.getHeight() + 60f)
.setInterpolator(AccelerateInterpolator(2f)).start()
}
})
you can change animation, delay and margin according to your requirement
for more detail refer to this blog
Note: it will not work if your recyclerview inside scrollview
Upvotes: 2
Reputation: 1134
how about make custom behavior?
for example.
public class QuickReturnFooterBehavior extends CoordinatorLayout.Behavior<View> {
private static final Interpolator INTERPOLATOR = new FastOutSlowInInterpolator();
private static final long ANIMATION_DURATION = 200;
private int dyDirectionSum;
private boolean isShowing;
private boolean isHiding;
private boolean isNeedOption = true;
public boolean isNeedOption() {
return isNeedOption;
}
public void setNeedOption(boolean needOption) {
isNeedOption = needOption;
}
public QuickReturnFooterBehavior(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
public boolean onStartNestedScroll(@NonNull CoordinatorLayout coordinatorLayout, @NonNull View child, @NonNull View directTargetChild, @NonNull View target, int axes, int type) {
return axes == ViewCompat.SCROLL_AXIS_VERTICAL;
}
@Override
public void onNestedPreScroll(@NonNull CoordinatorLayout coordinatorLayout, @NonNull View child, @NonNull View target, int dx, int dy, @NonNull int[] consumed, int type) {
// scroll chhange up and down
if (isNeedOption) {
showView(child);
} else {
if (dy > 0 && dyDirectionSum < 0
|| dy < 0 && dyDirectionSum > 0) {
child.animate().cancel();
dyDirectionSum = 0;
}
dyDirectionSum += dy;
if (dyDirectionSum > child.getHeight()) {
hideView(child);
} else if (dyDirectionSum < -child.getHeight()) {
showView(child);
}
}
}
private void hideView(final View view) {
if (isHiding || view.getVisibility() != View.VISIBLE) {
return;
}
ViewPropertyAnimator animator = view.animate()
.translationY(view.getHeight())
.setInterpolator(INTERPOLATOR)
.setDuration(ANIMATION_DURATION);
animator.setListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animator) {
isHiding = true;
}
@Override
public void onAnimationEnd(Animator animator) {
isHiding = false;
view.setVisibility(View.INVISIBLE);
}
@Override
public void onAnimationCancel(Animator animator) {
// show when cancle
isHiding = false;
showView(view);
}
@Override
public void onAnimationRepeat(Animator animator) {
// no-op
}
});
animator.start();
}
private void showView(final View view) {
if (isShowing || view.getVisibility() == View.VISIBLE) {
return;
}
ViewPropertyAnimator animator = view.animate()
.translationY(0)
.setInterpolator(INTERPOLATOR)
.setDuration(ANIMATION_DURATION);
animator.setListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animator) {
isShowing = true;
view.setVisibility(View.VISIBLE);
}
@Override
public void onAnimationEnd(Animator animator) {
isShowing = false;
}
@Override
public void onAnimationCancel(Animator animator) {
// show when cancle
isShowing = false;
hideView(view);
}
@Override
public void onAnimationRepeat(Animator animator) {
// no-op
}
});
animator.start();
}
}
UPDATE : for check can scroll in behavior
child.canScrollVertically(1) // "Top of list"
child.canScrollVertically(-1) // "End of list"
**UPDATE : add setter and getter **
private boolean isNeedOption = true;
Upvotes: 1