Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ScrollView does not resize directly after child changes

I've run into a very annoying problem regarding ScrollView resizing, and I'm running out of possible solutions.

I have a FragmentPager containing several different Fragments, one of which has a ScrollView. The Fragment with the ScrollView is made up of a Spinner and the ScrollView containing a LinearLayout with several rows of other Views (such as SeekBars, Buttons, Edittexts) in it. Depending on which option is select in the Spinner, the ScrollView shows different views. To do so, some Views have their visibility turned to Gone, while others are turned to Visible. This works great, except for the fact that the ScrollView does not seem to resize itself properly upon choosing a different option using the Spinner.

When the ScrollView is full of Views, and therefore scrollable, if the user selects an option which shows less Viewsthan required to fill the ViewPort the ScrollView still scrolls. When the user then chooses the old option again, the ScrollView is now unable to scroll since it took on the size required for the previous option. When the user then chooses the SAME option again, the ScrollView suddenly is scrollable, since it is now resized to the actual size required.

What is going on here? And better yet, how can I fix this annoying problem?

My layout:

<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/control_scroll"
    android:layout_width="fill_parent"
    android:layout_height="0dp"
    android:layout_weight="1"
    android:background="#99000000"
    android:fillViewport="true" >

    <LinearLayout
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_marginBottom="20dp"
        android:orientation="vertical" >

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background="#DD000000"
            android:gravity="bottom"
            android:orientation="vertical" >

            <TextView
                android:id="@+id/lamp_choose_tv"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_marginBottom="2dp"
                android:paddingLeft="5dp"
                android:text="@string/choose_lamp_text"
                android:textColor="#FFFFFF"
                android:textSize="14sp" />
        </LinearLayout>

        <Spinner
            android:id="@+id/lamp_select_spinner"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="5dp"
            android:textColor="#FFFFFF" />

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background="#DD000000"
            android:gravity="bottom"
            android:orientation="vertical" >

            <TextView
                android:id="@+id/lamp_settings_tv"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_marginBottom="2dp"
                android:background="#44000000"
                android:paddingLeft="5dp"
                android:text="@string/lamp_settings_text"
                android:textColor="#FFFFFF"
                android:textSize="14sp" />
        </LinearLayout>
        <!-- Lamp name -->

        <LinearLayout
            android:id="@+id/naam_bar"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:gravity="bottom"
            android:paddingBottom="3dp"
            android:paddingLeft="10dp"
            android:paddingRight="10dp"
            android:paddingTop="3dp" >

            <TextView
                android:id="@+id/bridge_naam"
                style="@style/ConfigText"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_weight="1"
                android:text="@string/config_lightname"
                android:textColor="#FFFFFF"
                android:textSize="16sp" />

            <EditText
                android:id="@+id/lamp_naam_input"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_weight="2"
                android:background="@drawable/tasstextfield"
                android:inputType="textNoSuggestions"
                android:textColor="#FFFFFF" >
            </EditText>
        </LinearLayout>

        <View
            android:id="@+id/separator"
            android:layout_width="fill_parent"
            android:layout_height="0.5dp"
            android:background="@android:color/black"
            android:visibility="visible" />
<!-- Rest of the views -->

Things I already tried:

  • ForceLayout/requestLayout on the parent ScrollView
  • Invalidate the ScrollView
  • ForceLayout/requestLayout on the containing LinearLayout
  • Invalidating the LinearLayout
  • Invalidating all children of the ScrollView
  • ForceLayout/requestLayout on all children of the ScrollView
like image 387
Sander van't Veer Avatar asked Mar 22 '13 14:03

Sander van't Veer


1 Answers

This might not be the most enjoyable solution, but it might work. Use a handler to post a delayed message to refresh the view a second time, as if the user would choose the same option twice after having click on the refresh button.

// The code when the user wants to update the views 
myButton.setOnClickListener(new OnClickListener{
  @Override
  public void onClick(View view) {
    updateView();
    Message m = Message.obtain();
    m.what = UPDATE_TAG;
    mHandler.sendMessageDelayed(msg, 200);
  }
})

...

final int UPDATE_TAG = 1;

public void updateView() {
  // Code where View.GONE and View.VISIBLE + invalidate is used.
}

Handler mHandler = new Handler {
  @Override
  public void handleMessage(Message input_msg) {
    if(msg.what == UPDATE_TAG) {
      updateView();
    }
  }
}
like image 148
Mikaël Mayer Avatar answered Sep 28 '22 10:09

Mikaël Mayer