how to detect the position of the scroll nestedscrollview android at the bottom?
Asked Answered
R

9

48

i just want to detect the position of the scroll nestedscrollview android at the bottom, and the to call function. my code is :

scroll.getViewTreeObserver()
      .addOnScrollChangedListener(new ViewTreeObserver.OnScrollChangedListener() {
           @Override
           public void onScrollChanged() {
               int totalHeight = scroll.getChildAt(0).getHeight();
               int scrollY = scroll.getScrollY();
               Log.v("position", "totalHeight=" + totalHeight + "scrollY=" + scrollY);
               if (scrollY==totalHeight) {
                   getPlaylistFromServer("more");
               }
           }
      });

but totalheight not same wit MAX ScrollY. how to fix it ?

Rhizocarpous answered 21/3, 2016 at 23:51 Comment(2)
Use ViewCompat.canScrollVertically(View v, int direction)Eubank
As ViewCompat.canScrollVertically(View v, int direction) is deprecated, use View.canScrollVertically(int direction).Cown
U
121

Set setOnScrollChangeListener in a NestedScrollView params to get

  • NestedScrollView v (parent with scroll)
  • int scrollY
  • int oldScrollY

To detect whether the offset is at the bottom, it is necessary to obtain the value of content height v.getChildAt(0).getMeasuredHeight() and compare the current scroll over the height of the parent, if you have the same value , it means that it has reached the end.

You can get the height with parent view with v.getMeasuredHeight()

NestedScrollView scroller = (NestedScrollView) findViewById(R.id.myScroll);

if (scroller != null) {

    scroller.setOnScrollChangeListener(new NestedScrollView.OnScrollChangeListener() {
        @Override
        public void onScrollChange(NestedScrollView v, int scrollX, int scrollY, int oldScrollX, int oldScrollY) {

            if (scrollY > oldScrollY) {
                Log.i(TAG, "Scroll DOWN");
            }
            if (scrollY < oldScrollY) {
                Log.i(TAG, "Scroll UP");
            }

            if (scrollY == 0) {
                Log.i(TAG, "TOP SCROLL");
            }

           if (scrollY == ( v.getMeasuredHeight() - v.getChildAt(0).getMeasuredHeight() )) {
               Log.i(TAG, "BOTTOM SCROLL");
           }
       }
    });
}
Unbrace answered 4/6, 2016 at 12:10 Comment(7)
How to check when the user stopped scrolling like once it becomes idle?Austenite
Would someone be able to explain why this line works? if (scrollY == (v.getChildAt(0).getMeasuredHeight() - v.getMeasuredHeight())) How is it that the NestedScrollView's measured height is smaller than the content's height, even though the NestedScrollView is the parent?Steinmetz
much better v.getMeasuredHeight() - v.getChildAt(0).getMeasuredHeight(, I change nowUnbrace
min API for this approach is 23, do you know another alternative?Else
@JoãoCarlos no this is not from 23 API. setOnScrollChangeListener(View.OnScrollChangeListener) needs API 23, but setOnScrollChangeListener(NestedScrollView.OnScrollChangeListener) doesn'tHarsh
You are the hero of my day, bro! Your answer helped me a lot. Thanks!Mazel
How to know the first element has been scrolled up ? Please help on thisCupid
D
45

I know it's late but.. try this way.

scroll.getViewTreeObserver().addOnScrollChangedListener(new ViewTreeObserver.OnScrollChangedListener() {
    @Override
    public void onScrollChanged() {
            View view = (View) scroll.getChildAt(scroll.getChildCount() - 1);

            int diff = (view.getBottom() - (scroll.getHeight() + scroll
                    .getScrollY()));

            if (diff == 0) {
                getPlaylistFromServer("more");
            }          
    }
});

Happy Coding..

Disagreeable answered 3/6, 2016 at 4:54 Comment(3)
Thank you. Its save my day.Troposphere
If you have a recyclerview in nested scroll view. Please refer to this.Vauban
how to know user scrolled up first item ? Please help on thisCupid
M
10

Webserveis answered right, but it needs a little bit of changes in onScrollChange (override method), like this:

if (scrollY === v.getChildAt(0).getMeasuredHeight() - v.getMeasuredHeight()) {
   // end of the scroll view
}

Kotlin:

if (scrollY == v.getChildAt(0).measuredHeight - v.measuredHeight) {
    // end of the scroll view
}
Megalomania answered 29/4, 2019 at 4:17 Comment(0)
B
6
  @Override
public void onScrollChange(NestedScrollView nestedScrollView, int scrollX, int scrollY, int oldScrollX, int oldScrollY) {
    if (nestedScrollView.getChildAt(nestedScrollView.getChildCount() - 1) != null) {
        if ((scrollY >= (nestedScrollView.getChildAt(nestedScrollView.getChildCount() - 1).getMeasuredHeight() - nestedScrollView.getMeasuredHeight())) &&
                scrollY > oldScrollY) {
            LogsUtils.INSTANCE.makeLogD(">onScrollChange>", ">>BOTTOm");
        }

    }
}

Its worked for me, Source

Bellbird answered 6/12, 2018 at 10:34 Comment(1)
This one helped meAlgeciras
D
5

This worked for me :

nestedScroll.setOnScrollChangeListener(new NestedScrollView.OnScrollChangeListener() {
        @Override
        public void onScrollChange(NestedScrollView v, int scrollX, int scrollY, int oldScrollX, int oldScrollY) {

            if (v.getChildAt(0).getBottom()<=(nestedScroll.getHeight()+scrollY)) {
                System.out.println("End of NestedScrollView");
            }

        }
    });

Basically , we add many views inside a nestedScrollView but wrap them together in a form of Single View. Therefore, childCount will always be 1 with its index 0. Thus, used v.getChildAt(0).getBottom() to determine its bottom. Now, nestedScroll.getHeight() returns height in pixel,and , scrollY will return current vertical origin. Therefore, the above condition will be true everytime the bottom of NestedScrollView is reached.

if (v.getChildAt(0).getBottom()==(nestedScroll.getHeight()+nestedScroll.getScrollY()))

This only works some time... therefore, don't use it in such way.

Dameron answered 31/10, 2020 at 21:20 Comment(0)
M
1

I just changed a little codes of first answer to detect reaching end of recyclerview inside nested scrollview.

binding.nestedScroll.setOnScrollChangeListener(object:NestedScrollView.OnScrollChangeListener {
        override fun onScrollChange(
            v: NestedScrollView,
            scrollX: Int,
            scrollY: Int,
            oldScrollX: Int,
            oldScrollY: Int
        ) {

        if (scrollY > oldScrollY) {
            Log.i("TAG", "Scroll DOWN");
        }
        if (scrollY < oldScrollY) {
            Log.i("TAG", "Scroll UP");
        }

        if (scrollY == 0) {
            Log.i("TAG", "TOP SCROLL");
        }
       
        if (v.getChildAt(0).getBottom() <= v.height + scrollY)
            {
            Log.i("TAG", "BOTTOM SCROLL IN Recyclerview.");

            Toast.makeText(requireContext(), "Last", Toast.LENGTH_LONG).show()
        }

        }
    })
Monkhmer answered 14/12, 2022 at 16:31 Comment(0)
S
0

for api <23 you can add a treeObserver.scrollChangeLister store a local float variable and check which way your scrolling like this

example

public class About extends AppCompatActivity implements 
ViewTreeObserver.OnScrollChangedListener{

private float viewScrolled = 0;

   nestedScrollView.getViewTreeObserver().addOnScrollChangedListener(this);

}

@Override
public void onScrollChanged() {

    if (viewScrolled < nestedScrollView.getScrollY()){
        viewScrolled = nestedScrollView.getScrollY();
        Log.d(TAG, "scrolling up");
    }
    if (viewScrolled > nestedScrollView.getScrollY()){
        viewScrolled = nestedScrollView.getScrollY();
        Log.d(TAG, "scrolling down");
    }
}
Spartan answered 14/6, 2019 at 21:12 Comment(0)
M
0

Webserveis answered right, but the condition should be like this

 if (scrollY == (v?.getChildAt(0)?.measuredHeight ?: 0) - (v?.measuredHeight ?: 0)) {
    //at bottom
    }
Misty answered 9/4, 2020 at 10:12 Comment(0)
S
0

This worked for me!

            my_scroll_view.setOnScrollChangeListener(new NestedScrollView.OnScrollChangeListener() {
            @Override
            public void onScrollChange(NestedScrollView v, int scrollX, int scrollY, int oldScrollX, int oldScrollY) {



                    if (scrollY == v.getChildAt(0).getMeasuredHeight() - v.getMeasuredHeight()) {
                        Log.d(TAG, "onScrollChange: SRCOLLED ==> scrollY: ======================================> THIS IS THE VERY END ");
                    }

                

            }
        });
Sidestroke answered 10/2, 2021 at 17:6 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.