1

There are already some solution here on how to change button dimensions programmatically

But, the one that worked for me was: Here in this site

In it the author does something like this:

ImageButton someView = (ImageButton)findViewById(R.id.myimage);
someView.requestLayout();
someView.getLayoutParams().width = newWidth;
someView.getLayoutParams().height = newHeight;

Now I just tried doing this excluding someView.requestLayout() and it still works. I read the docs about this function but I couldn't get anything out of it(I'm still a beginner). What is the use of this function and would excluding it cause any harm or exceptions in the long term?

juztcode
  • 1,196
  • 2
  • 21
  • 46
  • That function is used to request a layout pass. What that means is if you have changed some property of the view which will affect its child or parent you can call this function to make sure the new view with new measurements would be drawn. – NIKHIL MAURYA Dec 04 '19 at 09:41
  • @NIKHILMAURYA, then why should we call it in the beginning? Should we not call it after all the new width and height are set? – juztcode Dec 04 '19 at 10:10
  • I am not sure if it's required here but for more discussions on this topic you can refer here https://stackoverflow.com/questions/13856180/usage-of-forcelayout-requestlayout-and-invalidate – NIKHIL MAURYA Dec 04 '19 at 10:17

1 Answers1

1

Setting the width and height by itself will not trigger a layout of the widget. Either a layout pass is already scheduled which will be true if your code is in the onCreate() method of an activity or there is another piece of code that triggers the layout. For example, if, in addition to setting the width and height, you also set the scale type the method to set the scale type will trigger the layout.

From ImageView.java

/**
     * Controls how the image should be resized or moved to match the size
     * of this ImageView.
     *
     * @param scaleType The desired scaling mode.
     *
     * @attr ref android.R.styleable#ImageView_scaleType
     */
    public void setScaleType(ScaleType scaleType) {
        if (scaleType == null) {
            throw new NullPointerException();
        }

        if (mScaleType != scaleType) {
            mScaleType = scaleType;

            requestLayout();
            invalidate();
        }
    }

As you can see, setting the scale type triggers a request for a layout if the scale type has changed.

Here is a small app to test the concepts. In a nutshell, the size can be changed prior to the initial layout (in onCreate()), after the initial layout completed (in onGlobalLayout()) or via some user action (in onClick()). See the comments in the code regarding how the app works.

MainActivity.java

public class MainActivity extends AppCompatActivity implements View.OnClickListener,
        ViewTreeObserver.OnGlobalLayoutListener {
    private View theView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        theView = findViewById(R.id.view);
        // If the following line execute, it is before the initial layout pass,
        // so the new width will take effect during that layout pass.
        // Comment and uncomment this line to see the effect.
//        theView.getLayoutParams().width *= 2;

        // Uncomment the following to change size after the initial layout.
        theView.getViewTreeObserver().addOnGlobalLayoutListener(this);
    }

    @Override
    public void onClick(View v) {
//        theView.getLayoutParams().width *= 2;
        // The layout pass has completed since the button is available to click.
        // Here setting the width without requesting a layout will not change the
        // width of the widget - at least not until there is a layout pass requested.
        // Comment and uncomment this line to see the effect.
//        theView.requestLayout();
    }

    @Override
    public void onGlobalLayout() {
        theView.getViewTreeObserver().removeOnGlobalLayoutListener(this);
        theView.getLayoutParams().width *= 2;
        theView.requestLayout();
    }
}

activity_main.xml

<androidx.constraintlayout.widget.ConstraintLayout 
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".MainActivity">

        <View
            android:id="@+id/viewStatic"
            android:layout_width="100dp"
            android:layout_height="50dp"
            android:layout_marginBottom="16dp"
            android:background="@android:color/holo_red_light"
            android:text="Hello World!"
            app:layout_constraintBottom_toTopOf="@+id/view"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintRight_toRightOf="parent"
            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintVertical_chainStyle="packed" />

        <View
            android:id="@+id/view"
            android:layout_width="100dp"
            android:layout_height="50dp"
            android:background="@android:color/holo_red_light"
            android:text="Hello World!"
            app:layout_constraintBottom_toTopOf="@+id/button"
            app:layout_constraintHorizontal_bias="0.5"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintRight_toRightOf="parent"
            app:layout_constraintTop_toBottomOf="@+id/viewStatic" />

        <Button
            android:id="@+id/button"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="24dp"
            android:text="Make larger"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintHorizontal_bias="0.5"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toBottomOf="@+id/view" />

    </androidx.constraintlayout.widget.ConstraintLayout>
Cheticamp
  • 61,413
  • 10
  • 78
  • 131
  • but both of them are in the onCreate, when do we figure when the layout pass is called? – juztcode Dec 09 '19 at 12:29
  • @juztcode The _onClick()_ listener does not execute on the _onCreate()_ method. I updated the code to make this clearer. I also added the global layout listener which is what you may be looking for. – Cheticamp Dec 09 '19 at 13:05
  • what does the GlobalLayoutListener do? Could you please explain a bit more about what it is doing in the code? – juztcode Dec 09 '19 at 13:30
  • @juztcode [_OnGlobalLayoutListener_](https://developer.android.com/reference/android/view/ViewTreeObserver.OnGlobalLayoutListener) let's you execute some code after views are measured and laid out. It is in this code that you can change the width of your view. – Cheticamp Dec 09 '19 at 15:47
  • but, can you add detail when the requestLayout should be called? It's mentioned when it is called but not when it should be called, and why does it work even if I change the width and height in the `onResume` method without a requestLayout? – juztcode Dec 11 '19 at 03:11
  • 1
    @juztcode Take a look at [this answer](https://stackoverflow.com/a/25846243/6287910). Changing the width and height in _onResume()_ must have an implied _requestLayout()_. – Cheticamp Dec 11 '19 at 16:33