2

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

Chirag Patel
  • 437
  • 2
  • 7
  • 22

3 Answers3

1

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;
S T
  • 1,068
  • 2
  • 8
  • 16
  • please add how to use this in my fragmet/activity – Chirag Patel Nov 13 '20 at 07:09
  • app:layout_behavior="your.package.here.HideBottomViewOnScrollBehavior" like this – S T Nov 13 '20 at 07:13
  • bro this is workig but one problem it also show/hide button on swipe up and down if my all recyclerview item collapsed, i don't won't to hide/show if all recyclerview items are fitting in screen – Chirag Patel Nov 13 '20 at 07:27
  • Do you want to while scroll always show when recyclerview is collapsed and only hide when recyclerview is expended? – S T Nov 13 '20 at 07:33
  • yes, if all item of recyclerview is visible in screen then button will always visible if recyclerview item going outside of screen then only show/hide should work on up visible on down hide – Chirag Patel Nov 13 '20 at 07:45
  • update code. I think just check if ca'n scroll, it always show. and if need scroll, it can be hide. may be you can modify as you need. – S T Nov 13 '20 at 07:57
  • bro now button is not hiding on recyclerview item expand because after expand other item go out of screen so at that time button should be hide/show – Chirag Patel Nov 13 '20 at 08:41
  • I forgot NestedScrollView. but in your NestedScrollView has only RecyclerView. So how about remove NestedScrollView?? because NestedScrollView don't support scroll state – S T Nov 13 '20 at 08:56
  • hello i updated my code but didn't work please check updated code – Chirag Patel Nov 13 '20 at 09:15
  • if you use isScanning, I think you can use this. – S T Nov 13 '20 at 09:25
  • didn't understand – Chirag Patel Nov 13 '20 at 09:26
  • how you use this line? android:visibility="@{!isScanning ? View.VISIBLE: View.GONE}" – S T Nov 13 '20 at 09:28
  • isScanning view binding param which true on api load and false on api data get successfull – Chirag Patel Nov 13 '20 at 09:29
  • isScanning is not used after data get successfully from api – Chirag Patel Nov 13 '20 at 09:31
  • 1
    Yes so if you controll this when you need (RecyclerView scroll Listener), it will be work – S T Nov 13 '20 at 09:31
  • didn't understand what to do with isScaning, can you help me remotely bro please? any desk just 5-10 min – Chirag Patel Nov 13 '20 at 09:32
  • Oh sorry it's my fault @binding data is not my expect. I will try more search. and now I am outside so can't help. – S T Nov 13 '20 at 09:38
  • I edited my answer. I hope it will help, add setter and getter for flag. this code writed by mobile. so maybe spell is wrong. and when you click event, use change. basically it is true – S T Nov 13 '20 at 09:50
  • do i have to set isNeedOption value run time? if run time how – Chirag Patel Nov 13 '20 at 09:55
1

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

mitesh makwana
  • 269
  • 3
  • 11
0

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"
Vitali_Ac
  • 1
  • 2