How to get percentage of scroll in NestedScrollView any time (smoothly)?
Asked Answered
T

4

13

I want to change the alpha of toolbar base on scroll, like below:

enter image description here

At first, the toolbar is transparent and by scrolling to the bottom it will more and more visible and at the end it will be fully opaque (visible).

The structure of my layout is:

<android.support.design.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">

    <android.support.design.widget.AppBarLayout
    android:id="@+id/app_bar_layout"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

    <android.support.design.widget.CollapsingToolbarLayout
        android:id="@+id/collapsing_toolbar"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:contentScrim="?attr/colorPrimary"
        app:layout_scrollFlags="scroll|exitUntilCollapsed">

        <RelativeLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            app:layout_collapseMode="parallax">

            ....

        </RelativeLayout>

    </android.support.design.widget.CollapsingToolbarLayout>

    </android.support.design.widget.AppBarLayout>

    <android.support.v4.widget.NestedScrollView
    android:id="@+id/scroll"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:clipToPadding="false"
    app:layout_behavior="@string/appbar_scrolling_view_behavior">

         ....

    </android.support.v4.widget.NestedScrollView>

</android.support.design.widget.CoordinatorLayout>

Content of nested scrollview will be change dynamically from server so I don't know it's height.

I just found 2 ways to detect scrollY:

  1. addOnScrollChangedListener:

    scroll.getViewTreeObserver().addOnScrollChangedListener(new ViewTreeObserver.OnScrollChangedListener() {
     @Override
     public void onScrollChanged() {
        // use scroll.getScrollY()     
    }
    });
    
  2. setOnScrollChangeListener:

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

But none of these ways are not smooth. for example if you check the value of scrollY (by using log.d()) you will see something like:

scrollY: 58
scrollY: 117
scrollY: 167
scrollY: 192
scrollY: 195
scrollY: 238
scrollY: 281
scrollY: 338 

There is a large gap between numbers.

My question is: How to get percentage of scroll every moment (smoothly)? Or any other way to change alpha of toolbar base on current position of scroll?

Tansy answered 30/10, 2016 at 21:55 Comment(0)
A
7

You can add an scrollListener to ScrollView.

The calculation of scrolled percentage of your scrollView:

double percent = ((((float) scrollY) / ((float) (scrollContentHeight - screenHeight + statusBarHeight))));

enter image description here


  • The top edge of the displayed part of your view: scrollY = scrollView.getScrollY()

  • The scrollView has one child and scrollContentHeight = scrollView.getChildAt(0).getHeight() is the height of the content of scrollView.

  • We need to calculate the max height of top edge in full scrolled state: scrollContentHeight - screenHeight + statusBarHeight

  • Finished! percent = scrollY*100 / (scrollContentHeight - screenHeight + statusBarHeight)

  • And set the color: view.setBackgroundColor(Color.argb((int) (255.0 * (percent/100)), r, g, b));


scrollView.getViewTreeObserver().addOnScrollChangedListener(new ViewTreeObserver.OnScrollChangedListener() {
        @Override
        public void onScrollChanged() {
            int scrollY = scrollView.getScrollY();
            int scrollContentHeight = scrollView.getChildAt(0).getHeight();
            int screenHeight = Utility.getScreenHeight(context);
            int statusBarHeight = Utility.getStatusBarHeight(context);

            int color = getResources().getColor(R.color.colorPrimary);
            int r = (color >> 16) & 0xFF;
            int g = (color >> 8) & 0xFF;
            int b = (color >> 0) & 0xFF;

            double percent = ((((float) scrollY) / ((float) (scrollContentHeight - screenHeight + statusBarHeight))));
            if (percent >= 0 && percent <= 1)
                toolbar.setBackgroundColor(Color.argb((int) (255.0 * percent), r, g, b));
        }
    });
Aikido answered 17/7, 2017 at 11:31 Comment(4)
Thumbs up for drawing.Cinchonidine
which height is this Utility.getScreenHeight(context);? Do you mean to say device screen height?Localize
@VivekBarai Yes, Utility.getScreenHeight() returns the device screen height.Aikido
Using the screen's own height in this formula seems a bit unnecessary as the scroll percentage is only relative to the content of the ScrollView. Which is why you are having to take into account the status bar height. @JimmyCram has the simpler formula that is much more portable as it is self contained to the ScrollView. Your colour calculation makes sense, but I would use the Color.red(), Color.green(), and Color.blue() utility functions instead of the bit operations to keep code readable and reliable.Pentastyle
E
7

try this

scrollview.getViewTreeObserver().addOnScrollChangedListener(new ViewTreeObserver.OnScrollChangedListener() {
            @Override
            public void onScrollChanged() {
                double scrollViewHeight = scrollview.getChildAt(0).getBottom() - scrollview.getHeight();
                double getScrollY = scrollview.getScrollY();
                double scrollPosition = (getScrollY / scrollViewHeight) * 100d;
                Log.i("scrollview", "scroll Percent Y: " + (int) scrollPosition);
            }
        });

it will show the percentage from 0 to 100%

Enigmatic answered 7/12, 2018 at 21:17 Comment(2)
Can you explain why we have to do scrollview.getChildAt(0).getBottom() - scrollview.getHeight()? Does scrollview.getheight not return the height we want?Spaak
Oh I see that this is to calculate how much you can actually scroll.Spaak
P
4

Try this method:

    nestedScrollView.setOnScrollChangeListener((NestedScrollView.OnScrollChangeListener) (v, scrollX, scrollY, oldScrollX, oldScrollY) -> {
                int verticalScrollableHeight = v.getChildAt(0).getMeasuredHeight() - v.getMeasuredHeight();
                float verticalPercentage = ((float) scrollY) / verticalScrollableHeight;
Passover answered 23/12, 2020 at 8:13 Comment(1)
This should be considered the right answer.Levesque
C
0

These answers are ignoring the effect of any top or bottom padding on the scroll view, which is effectively extra scroll span, so I found I needed:

val verticalScrollableHeight = firstChild.measuredHeight - scrollView.measuredHeight + scrollView.paddingBottom + scrollView.paddingTop
        listener(scrollView.scrollY.toFloat() / verticalScrollableHeight)
Correggio answered 30/9, 2021 at 9:22 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.