【问题标题】:ScrollView does not resize directly after child changes子更改后,ScrollView 不会直接调整大小
【发布时间】:2013-03-12 10:15:21
【问题描述】:

我遇到了一个非常烦人的关于调整 ScrollView 大小的问题,而且我已经没有可能的解决方案了。

我有一个 FragmentPager,其中包含几个不同的 Fragment,其中一个有一个 ScrollView。 带有 ScrollView 的 Fragment 由 Spinner 和包含 LinearLayout 的 ScrollView 组成,其中包含几行其他 View(例如 SeekBars、Buttons、Edittexts)。 根据在 Spinner 中选择的选项,ScrollView 显示不同的视图。为此,一些视图的可见性变为已消失,而另一些视图则变为可见。 这很好用,除了 ScrollView 在使用 Spinner 选择不同选项时似乎无法正确调整自身大小。

当 ScrollView 充满视图并因此可滚动时,如果用户选择的选项显示的 Views 少于填充 ViewPort 所需的 Views,则 ScrollView 仍会滚动。 当用户再次选择旧选项时,ScrollView 现在无法滚动,因为它采用了前一个选项所需的大小。 当用户再次选择 SAME 选项时,ScrollView 突然可滚动,因为它现在已调整为所需的实际大小。

这里发生了什么?更好的是,我该如何解决这个烦人的问题?

我的布局:

<?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 -->

我已经尝试过的事情:

  • 父 ScrollView 上的 ForceLayout/requestLayout
  • 使 ScrollView 无效
  • 包含 LinearLayout 的 ForceLayout/requestLayout
  • 使线性布局无效
  • 使 ScrollView 的所有子级无效
  • ScrollView 的所有子项上的 ForceLayout/requestLayout

【问题讨论】:

  • 您是否尝试过使用ListView 而不是构建您自己的列表视图?忽略该页面上的Loader 示例——您可以简单地为每段文本创建一个String[]List&lt;String&gt;,并将其提供给ArrayAdapter,然后覆盖getView 以控制外观。
  • 我明白你为什么会这么想。实际上,我停止使用 TextViews,因为那基本上只是为了测试目的,现在我使用不同的 Views,例如 Buttons、EditTexts 和 Seekbars。然而,问题仍然存在。
  • 我认为问题在于ScrollView 需要为新的Views 调整自身大小。当您将内部视图设置为 View.VISIBLE 时,在父 ScrollView 上调用 requestLayout()forceLayout() 以安排布局传递。
  • 用我已经尝试过的东西更新了我的问题,似乎他们第一次没有坚持。可悲的是,我已经尝试在所有视图上使 requestLayout 和 forceLayout 失效。问题依然存在。
  • 嗯...您可以尝试其他选项,不要使用View.GONE,而是根据需要添加/删除它们。这可能是最终迫使调整大小的原因。增加了开销,但并不比你已经尝试做的多得多。只需坚持Views 的引用,您就不必重新膨胀它们。把它们放进去。

标签: android resize scrollview


【解决方案1】:

我想LinearLayout 使用某种缓存机制来避免每次都测量孩子。或者我错了。

但是,您可以尝试使用RelativeLayout 而不是一堆LinearLayout。这将解决您的问题,而且效率更高,因为嵌套的 ViewGroups 不利于性能。

【讨论】:

    【解决方案2】:

    您可以继续将 ScrollView 高度设置为“wrap_content”,这样即使子视图发生更改,ScrollView 也可以调整为新设置

    【讨论】:

    • 显然,我尝试的第一件事。但这并不能解决问题。
    【解决方案3】:

    试试这个改动

    <ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/control_scroll"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    
    android:background="#99000000"
    android:fillViewport="true" >
    

    退出android:layout_weight="1"

    【讨论】:

    • 我尝试的第一件事是wrap_content,但这并不能解决问题。
    【解决方案4】:

    这可能不是最令人愉快的解决方案,但它可能会奏效。 使用处理程序发布延迟消息以第二次刷新视图,就像用户在单击刷新按钮后会选择两次相同的选项一样。

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

    【讨论】:

    • 愉快吗?不,但它确实有效!非常感谢,希望这个答案也能帮助其他人。
    • 我只需要更新视图中的可见性更改。我不必做任何无效操作。
    • 我仍然认为必须有更好的解决方案来解决这个错误。
    猜你喜欢
    • 2012-02-05
    • 2012-12-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多