How to programmatically scroll an HorizontalScroll

2019-03-14 12:14发布

问题:

I have an HorizontalScrollView which contains a RelativeLayout. This layout is empty in the XML, and is populated from java in the onCreate.

I would like this scroll view to be initially somewhere in the middle of the RelativeLayout, which is way larger than the screen.

I tried mHorizScrollView.scrollTo(offsetX, 0); which doesn't work. I don't know what's wrong with this.

I could post the code, but it is not really relevant. What matters is that everything is done programatically (has to :s), and that the initial position of the HorizontalScrollView has to be set programmatically.

Thanks for reading. Please tell me if you need more details or if this is not clear enough.

回答1:

I found that if you extend the HorizontalScrollView and override the onLayout, you can cleanly scroll, after the super call to onLayout:

MyScrollView extends HorizontalScrollView {
    protected void onLayout (boolean changed, int l, int t, int r, int b) {
        super.onLayout(changed, l, t, r, b);
        this.scrollTo(wherever, 0);
    }
}

EDIT: For scrolling to start or end you can use:

this.fullScroll(HorizontalScrollView.FOCUS_RIGHT/FOCUS_LEFT);

instead of

this.scrollTo(wherever, 0);


回答2:

public void autoSmoothScroll() {

        final HorizontalScrollView hsv = (HorizontalScrollView) view.findViewById(R.id.horiscroll);
        hsv.postDelayed(new Runnable() {
            @Override
            public void run() {
                //hsv.fullScroll(HorizontalScrollView.FOCUS_RIGHT);
                hsv.smoothScrollBy(500, 0);
            }
        },100);
    }


回答3:

To test whether it's a timing issue (which I think it is), instead of calling scrollTo() in onStart, call postDelayed() with a Runnable that calls scrollTo, with a delay of 30 or so.



回答4:

A better approach would be using the ViewTreeObserver to observe layouts.

View interestedInView;
onCreate(){
  //Code

  //Observe for a layout change
  ViewTreeObserver viewTreeObserver = interestedInView.getViewTreeObserver();
  if (viewTreeObserver.isAlive()) {
    viewTreeObserver.addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
      @Override
      public void onGlobalLayout() {
        //REMOVE THE VIEWTREE OBSERVER
        //interestedInView is ready for size and position queries because it has been laid out
      }
    });
  }
}


回答5:

The problem is that the view doesn't have a size yet. The Clean way to do this is to implement the onSizeChanged of the ScrollView to send a message to a Handler in your activity to in order to notify the activity that the view has a size and that scrolling is possible.



回答6:

Use view.post and write scrollTo(x,y) inside run method. This the way to invalidate view in post method as per android API document.



回答7:

The scrollTo function should work. What is the layout_width of the HSV, and the view inside of it?



回答8:

The onSizeChanged function should work. What you fail to understand is that the onSizeChanged should send a message to a Handler of your activity and not any callback function, because a handler will execute code in the UI thread. You cannot do UI operations outside it. Have a look at handlers.