7

Same issue as ScrollView .scrollTo not working? Saving ScrollView position on rotation

I dynamically add items to scrollView in onCreate. I try the following after all items were added:

    // no effect
    ScrollView mainScroll = (ScrollView) findViewById(R.id.average_scroll_mainScroll);

    // no effect
    ScrollView mainScroll = (ScrollView) findViewById(R.id.average_scroll_mainScroll);
    mainScroll.post(new Runnable() {
        public void run(){
            ScrollView mainScroll = (ScrollView) findViewById(R.id.average_scroll_mainScroll);
            mainScroll.scrollTo(0, 0);
        } 
    });

    // works like a charm
    ScrollView mainScroll = (ScrollView) findViewById(R.id.average_scroll_mainScroll);
    mainScroll.postDelayed(new Runnable() {
        public void run(){
            ScrollView mainScroll = (ScrollView) findViewById(R.id.average_scroll_mainScroll);
            mainScroll.scrollTo(0, 0);
        } 
    }, 30);

I conclude that there is some event like 'DOM-ready'? Are there any callbacks?

Community
  • 1
  • 1
user1284151
  • 875
  • 4
  • 12
  • 23
  • 1
    My best guess is that because the `ScrollView` hasn't been layed out or measured yet right after inflating it, the first approach doesn't work. By Adding a delay, you're giving the view hierarchy enough time to initialise. I would try attaching a `OnGlobalLayoutListener` to the `ScrollView`'s `ViewTreeObserver` to get notified of when the view is 'ready to scroll'. – MH. Oct 14 '12 at 18:35

4 Answers4

20

You don't need to extend the ScrollView and create your own as per the answer provided by David Daudelin for the this question.

Get the ViewTreeObserver of the ScrollView and add an OnGlobalLayoutListener to the ViewTreeObserver. Then call the ScrollView.scrollTo(x,y) method from the onGlobalLayout() method of the OnGlobalLayoutListener. Code:

 ScrollView mainScroll = (ScrollView) findViewById(R.id.average_scroll_mainScroll);

 ViewTreeObserver vto = scrollView.getViewTreeObserver();
 vto.addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
      public void onGlobalLayout() {
           mainScroll.scrollTo(0, 0);
      }
 });
Community
  • 1
  • 1
fahmy
  • 3,543
  • 31
  • 47
7

This works for me, replace scrollView.scrollTo() to

     scrollView.post(new Runnable() {
        @Override
        public void run() {
            scrollView.scrollTo(0, ScrollViewYPosition);//0 is x position
        }
    });

I was helped by Vasily Kabunov 's answer in

ScrollView .scrollTo not working? Saving ScrollView position on rotation

JC Wang
  • 266
  • 3
  • 4
  • If the above solution does not work, just add a PostDelayed interval of 50-100 millis, as Android might need some time to redraw your view – Denys Lobur May 12 '19 at 23:14
1

When you do some changes to a ScrollView, it takes a while for it to replicate the layout changes to the display list and notify the ScrollView that it is, indeed, allowed to scroll to a position.

I've managed to get it working by extending ScrollView with a ScrollView of my own, and adding a method that adds the OnGlobalLayoutListener (as suggested by MH) as needed and scrolls there later. It's a bit more automated than applying it to every case you need it (but then you need to use the new ScrollView). Anyway, this is the relevant code:

public class ZScrollView extends ScrollView {

    // Properties
    private int desiredScrollX = -1;
    private int desiredScrollY = -1;
    private OnGlobalLayoutListener gol;

    // ================================================================================================================
    // CONSTRUCTOR ----------------------------------------------------------------------------------------------------

    public ZScrollView(Context __context) {
        super(__context);
    }

    public ZScrollView(Context __context, AttributeSet __attrs) {
        super(__context, __attrs);
    }

    public ZScrollView(Context __context, AttributeSet __attrs, int __defStyle) {
        super(__context, __attrs, __defStyle);
    }

    // ================================================================================================================
    // PUBLIC INTERFACE -----------------------------------------------------------------------------------------------

    public void scrollToWithGuarantees(int __x, int __y) {
        // REALLY Scrolls to a position
        // When adding items to a scrollView, you can't immediately scroll to it - it takes a while
        // for the new addition to cycle back and update the scrollView's max scroll... so we have
        // to wait and re-set as necessary

        scrollTo(__x, __y);

        desiredScrollX = -1;
        desiredScrollY = -1;

        if (getScrollX() != __x || getScrollY() != __y) {
            // Didn't scroll properly: will create an event to try scrolling again later

            if (getScrollX() != __x) desiredScrollX = __x;
            if (getScrollY() != __y) desiredScrollY = __y;

            if (gol == null) {
                gol = new OnGlobalLayoutListener() {
                    @Override
                    public void onGlobalLayout() {
                        int nx = desiredScrollX == -1 ? getScrollX() : desiredScrollX;
                        int ny = desiredScrollY == -1 ? getScrollY() : desiredScrollY;
                        desiredScrollX = -1;
                        desiredScrollY = -1;
                        scrollTo(nx, ny);
                    }
                };

                getViewTreeObserver().addOnGlobalLayoutListener(gol);
            }
        }
    }
}

Very useful for me since I wanted to scroll to a given View inside a ScrollView right after having added it.

zeh
  • 10,130
  • 3
  • 38
  • 56
  • Not knowing why but this trick with OnGlobalLayoutListener does not work. (at least on nexus 7 with android 5) – matreshkin Mar 29 '15 at 11:08
  • Sorry, that was my fault :/ I had a linear layout with LayoutTransition set. On an item added, layout animation started. And until it ended, I was not able to scroll to the postition I wanted, only to the current (during the animation) layout width. – matreshkin Mar 30 '15 at 14:05
0

Try this it works: (kotlin)

             myScrollView.post(Runnable {
                 myScrollView.scrollTo(0, scrollValue)
             })
Biplob Das
  • 2,818
  • 21
  • 13