kefs
kefs

Reputation: 3686

ScrollView .scrollTo not working? Saving ScrollView position on rotation

Ok.. I must be overlooking something real simple here, but i think i'm trying to do something fairly basic.. Simply retain the scrollbar position of a ScrollView on orientation change...

Here is the code for my onSaveInstanceState and onRestoreInstanceState.. sView is the container for the ScrollView layout. Within my scrollview is a linearlayout with a lot of textviews.

    @Override 
public void onSaveInstanceState(Bundle outState) 
{
    //---save whatever you need to persist—

    outState.putInt("sViewX",sView.getScrollX());
    outState.putInt("sViewY",sView.getScrollY());

super.onSaveInstanceState(outState);

}

@Override
public void onRestoreInstanceState(Bundle savedInstanceState) 
{
    super.onRestoreInstanceState(savedInstanceState);

    sViewX = savedInstanceState.getInt("sViewX");   
    sViewY = savedInstanceState.getInt("sViewY");

    sView.scrollTo(sViewX, sViewY);

}

If I set a Toast with the values of sViewX and sViewY on the Restore, the values are kept and correct.

Edit: I just tried to do a sView.scrollTo(0,150); in my onCreate.. just to see if that would open the activity at 150px down, and it didn't. I think my issue has to do with the .scrollTo method.

Upvotes: 46

Views: 39265

Answers (7)

ivan.panasiuk
ivan.panasiuk

Reputation: 1259

You should NOT start scroll before components are drawn, since scroll does not work until components are not created:

@Override
public void onWindowFocusChanged(boolean hasFocus) {
    scrollView.scrollTo(.... 

Upvotes: 2

Ruslan Kayumov
Ruslan Kayumov

Reputation: 11

this code worked for me for dynamically scrolling tabs, maybe it will be useful for u

TabHost tabHost;
int currentActiveTab;
HorizontalScrollView tabsHorizontalScrollView;
//some code ...
tabHost = getTabHost();
tabsHorizontalScrollView = findViewById(R.id.tabsHorizontalScrollView);
currentActiveTab = 8;
//some code ...
tabHost.setCurrentTab(currentActiveTab);
tabHost.getTabWidget().getChildAt(currentActiveTab).post(new Runnable() {
  @Override
  public void run() {
    tabsHorizontalScrollView.scrollTo(tabHost.getTabWidget().getChildAt(currentActiveTab).getLeft(), tabsHorizontalScrollView.getScrollY());
  }
});

Upvotes: 1

kefs
kefs

Reputation: 3686

I figured it out.

Since I'm using setText to TextViews in my onCreate, calling .scrollTo won't work.

So now I'm using the following:

sView.post(new Runnable() {
    @Override
    public void run() {
        sView.scrollTo(sViewX, sViewY);
    } 
});

Upvotes: 131

Kirill
Kirill

Reputation: 8311

Instead of sending scroll action to next run-loop, you can scroll your view in global layout callback:

@Override
public void onRestoreInstanceState(Bundle savedInstanceState) {
    super.onRestoreInstanceState(savedInstanceState);
    sView.getViewTreeObserver().addOnGlobalLayoutListener(
        new ViewTreeObserver.OnGlobalLayoutListener() {
            @Override
            public void onGlobalLayout() {
                sView.scrollTo(sViewX, sViewY);
            }
        }
    );
}

Upvotes: 0

Anisetti Nagendra
Anisetti Nagendra

Reputation: 341

This is working for me

@Override
protected void onSaveInstanceState(Bundle outState) {
    outState.putInt(SystemGlobal.SCROLL_Y, mRelativeLayoutMain.getTop());
}

@Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
    // TODO Auto-generated method stub
    super.onRestoreInstanceState(savedInstanceState);
    mRelativeLayoutMain.scrollTo(0, savedInstanceState.getInt(SystemGlobal.SCROLL_Y));
}

Upvotes: 1

akd005
akd005

Reputation: 538

onRestoreInstanceState() is just to early to scroll the view. That's why posting new Runnable helps, but not always. Sometimes one even have to use postDelayed() to let it work. For Fragment one can use onViewCreated() instead :

@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
    super.onViewCreated(view, savedInstanceState);
    sViewX = savedInstanceState.getInt("sViewX");   
    sViewY = savedInstanceState.getInt("sViewY");
    sView.scrollTo(sViewX, sViewY);
}

Upvotes: 1

Rodolfo De Los Santos
Rodolfo De Los Santos

Reputation: 311

For MVVMCross:

protected override void OnSaveInstanceState(Bundle outState)
{
    base.OnSaveInstanceState(outState);

    ScrollView sv = FindViewById<ScrollView>(Resource.Id.dispatchScrollView);
    int posY = sv.ScrollY;

    outState.PutInt("scrollY", posY);
}

protected override void OnRestoreInstanceState(Bundle savedInstanceState)
{
    base.OnRestoreInstanceState(savedInstanceState);

    ScrollView sv = FindViewById<ScrollView>(Resource.Id.dispatchScrollView);
    int posY = savedInstanceState.GetInt("scrollY");

    sv.Post(new Runnable(new Action(() => sv.ScrollTo(0, posY))));
}

Upvotes: 0

Related Questions