简体   繁体   中英

ScrollView scrollTo doesn't work

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?

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);
      }
 });

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

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.

Try this it works: (kotlin)

 myScrollView.post(Runnable { myScrollView.scrollTo(0, scrollValue) })

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM