Android 以编程方式更改权重后不会重新显示 LinearLayout

Android LinearLayout is not redisplayed after changing weights programmatically

我能够以编程方式构建包含数十个视图的 LinearLayout,并将其显示为 Activity 的内容视图。我能够遍历 LinearLayout 树并更改视图的背景颜色。

而且我能够遍历树并调整视图的相对权重,并在 onCreate() 快要结束时调用 setContentView() 来显示树。

我有一个 seekBar 可以交互式地调整颜色,而且很管用。同样,我有一个 seekBar 以交互方式调整权重。我知道权重正在正确更改。

但不知何故,视图在交互更改权重后不会重新显示,而在交互更改颜色后会重新显示。

为了在更改权重后重新显示内容视图,我必须做什么?

requestLayout() 适合我

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_height="match_parent"
    android:layout_width="match_parent"
    android:orientation="vertical">
    <SeekBar
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/seek"
        android:progress="50"
        android:max="100"/>
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        android:id="@+id/linear">
        <View
            android:layout_width="0dp"
            android:layout_height="20dp"
            android:layout_weight="1"
            android:id="@+id/blue"
            android:background="#00f"/>
        <View
            android:layout_width="0dp"
            android:layout_height="20dp"
            android:layout_weight="1"
            android:id="@+id/red"
            android:background="#f00"/>
    </LinearLayout>
</LinearLayout>

public class MainActivity extends AppCompatActivity {
    private LinearLayout linear;
    private View red;
    private View blue;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        SeekBar seek = (SeekBar) findViewById(R.id.seek);
        linear = (LinearLayout) findViewById(R.id.linear);
        red = findViewById(R.id.red);
        blue = findViewById(R.id.blue);
        seek.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
            @Override
            public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
                ((LinearLayout.LayoutParams) red.getLayoutParams()).weight = 100 - progress;
                ((LinearLayout.LayoutParams) blue.getLayoutParams()).weight = progress;

                linear.requestLayout();
            }

            @Override
            public void onStartTrackingTouch(SeekBar seekBar) {

            }

            @Override
            public void onStopTrackingTouch(SeekBar seekBar) {

            }
        });
    }
}

对于为什么即使调用 requestLayout() 权重也不会改变,我找到了一个答案。我制作了一个类似于 karokyo 的程序,但我没有使用 XML 布局文件。与上面的 karakyo 一样,它使用 seekBar 以交互方式更改权重。但它以编程方式创建所有视图。我发现在将视图添加到 ViewGroup(例如 LinearLayout)时,提供给 addView() 的 LayoutParams 不会复制到视图中,而是作为对象添加。因此,如果在多个 addView() 调用中提供了一个 LayoutParams,那么添加的视图将共享相同的 LayoutParams。然后,如果一个视图的权重发生变化(通过分配给 getLayoutParams()).weight),其他视图的权重也会发生变化,因为它们共享相同的 LayoutParams 对象。显然,当从 XML 布局扩展视图时,每个视图都会获得自己的 LayoutParams 对象。

package course.example.interactiveweightexperiment;

import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.LinearLayout;
import android.widget.SeekBar;


public class WeightSeekBar extends Activity {
    private final String TAG = "WeightSeekBar-TAG";
    private LinearLayout mainLayout;
    private LinearLayout linearColors;
    private View redView;
    private View blueView;
    SeekBar weightSeekBar;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        redView = new View(this);
        redView.setBackgroundColor(0xff770000);

        blueView = new View(this);
        blueView.setBackgroundColor(0xff000077);

        weightSeekBar = new SeekBar(this);
        weightSeekBar.setMax(100);
        weightSeekBar.setProgress(50);

        weightSeekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
            @Override
            public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
                ((LinearLayout.LayoutParams) redView.getLayoutParams()).weight = 100 - progress;
                ((LinearLayout.LayoutParams) blueView.getLayoutParams()).weight = progress;

                linearColors.requestLayout();
                // linearColors.invalidate();
            }

            @Override
            public void onStartTrackingTouch(SeekBar seekBar) {

            }

            @Override
            public void onStopTrackingTouch(SeekBar seekBar) {

            }
        });
        linearColors = new LinearLayout(this);
        linearColors.setOrientation(LinearLayout.VERTICAL);

        linearColors.addView(redView, new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, 0, 50));
        linearColors.addView(blueView, new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, 0, 50));

        /* the following does not allow the child Views to be assigned different weights.
        LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, 0, 50);
        linearColors.addView(redView, params);
        linearColors.addView(blueView, params);
        */

        mainLayout = new LinearLayout(this);
        mainLayout.setOrientation(LinearLayout.VERTICAL);
        mainLayout.addView(linearColors, new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, 0, 19));
        mainLayout.addView(weightSeekBar, new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, 0, 1));

        setContentView(mainLayout);
    }
}