Android LinearLayout is not redisplayed after changing weights programmatically

832 views Asked by At

I am able to construct a LinearLayout of dozens of Views programmatically and to display it as the content view of an Activity. I am able to walk the LinearLayout tree and change the backgroundcolors of the Views.

And I am able to walk the tree and adjust the relative weights of the Views and display the tree using a call to setContentView() near the end of onCreate().

I have a seekBar to adjust the colors interactively, and that works. Similarly I have a seekBar to adjust the weights interactively. I know the weights are being changed correctly.

But somehow the view is not redisplayed after changing the weights interactively, whereas it is redisplayed after changing the colors interactively.

What do I have to do in order to redisplay the content view after changing the weights?

2

There are 2 answers

1
tachyonflux On BEST ANSWER

requestLayout() works for me

<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) {

            }
        });
    }
}
0
John Surname On

I found one answer to why weights wouldn't change even when requestLayout() is called. I made a program similar to karokyo's, but mine doesn't use an XML layout file. Like karakyo's above, it changes weights interactively, using a seekBar. But it creates all its views programmatically. I found that when adding a View to a ViewGroup (e.g., a LinearLayout), the LayoutParams supplied to addView() are not copied into the view, but are added as objects. So if a single LayoutParams is supplied in more than one addView() call, the Views so added will share the same LayoutParams. Then if the weight of one View is changed (by assigning to getLayoutParams()).weight), the weights of the others will also change, as they share the same LayoutParams object. Apparently when inflating a view from an XML layout, each view is given its own LayoutParams object.

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