Search code examples
javaandroidmarginsscreen-sizelayoutparams

Adjusting layouts for different screen sizes for API 14-17, 17-30, 30+


EDIT 09.05.2021:

In general, I would like to programatically adjust the LayoutParams of some Buttons depending on the display size of the smartphone by adjusting some geometry values in onCreate(). Apparently it's not quite that simple.

Finally found found an approach for that, which is possibly working between API 14-17, 17-30, 30+.

My goal would be to determine the "real screen size" without insets / navigation bar elements for all APIs between 14-30+.

I still have to adapt the approach for < API 17, as the navigation bar elements may not yet be deducted in this case (I am currently trying to determine the navigation bar size for these use cases).


QUERY OF THE SCREENSIZE (width, height):

 //++++++++++++++ DISPLAY SIZES +++++++++++++

DisplayMetrics realDisplayMetrics = new DisplayMetrics();

int realDisplayWidth;
int realDisplayHeight;

//++++++++++++++ GET HORIZONTAL SCREENSIZE +++++++++

public int getRealScreenWidth(){

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
        // TARGETING BUILDVERSIONS GREATER EQUAL API:30

        WindowMetrics windowMetrics = getWindowManager().getCurrentWindowMetrics();
        // HORIZONTAL DISPLAY SIZE INCLUDING INSETS

        WindowInsets windowInsets = windowMetrics.getWindowInsets();
        Insets insets = windowInsets.getInsetsIgnoringVisibility(WindowInsets.Type.navigationBars()
                | WindowInsets.Type.displayCutout());

        int insetsWidth = insets.right + insets.left;
        // GET THE SIZE OF HORIZONTAL INSETS

        Rect bounds = windowMetrics.getBounds();
        realDisplayWidth = bounds.width() - insetsWidth;
        // HORIZONTAL SCREEN SIZE WITHOUT INSETS

        return realDisplayWidth;

    }

    else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
        // TARGETING BUILDVERSIONS ABOVE API:17, UNTIL API:30

        Display display = this.getWindowManager().getDefaultDisplay();

        display.getRealMetrics(realDisplayMetrics);
        realDisplayWidth = realDisplayMetrics.widthPixels;

        return realDisplayWidth;
    }

    else if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
        //REFLECTION FOR BUILDVERSIONs ABOVE API:14 UNTIL API:17

        Display display = this.getWindowManager().getDefaultDisplay();

        try {
            Method getHorizontalSize = Display.class.getMethod("getWidth");
            realDisplayWidth = (Integer) getHorizontalSize.invoke(display);
        } catch (Exception e) {
            realDisplayWidth = 1000;
        }
        return realDisplayWidth;
    }
    else {
    return realDisplayWidth = 1000;
    }
}

//++++++++++++++ GET VERTICAL SCREENSIZE +++++++++

public int getRealScreenHeight(){

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
        // TARGETING BUILDVERSIONS GREATER EQUAL API:30

        WindowMetrics windowMetrics = getWindowManager().getCurrentWindowMetrics();
        // VERTICAL DISPLAY SIZE INCLUDING INSETS

        WindowInsets windowInsets = windowMetrics.getWindowInsets();
        Insets insets = windowInsets.getInsetsIgnoringVisibility(WindowInsets.Type.navigationBars()
                | WindowInsets.Type.displayCutout());

        int insetsHeight = insets.top + insets.bottom;
        // GET THE SIZE OF VERTICAL INSETS

        Rect bounds = windowMetrics.getBounds();
        realDisplayHeight = bounds.height() - insetsHeight;
        // HORIZONTAL SCREEN SIZE WITHOUT INSETS

        return realDisplayHeight;

    }

    else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
        // TARGETING BUILDVERSIONS ABOVE API:17, UNTIL API:30

        Display display = this.getWindowManager().getDefaultDisplay();

        display.getRealMetrics(realDisplayMetrics);
        realDisplayHeight = realDisplayMetrics.heightPixels;

        return realDisplayHeight;
    }

    else if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
        //REFLECTION FOR BUILDVERSIONs ABOVE API:14 UNTIL API:17

        Display display = this.getWindowManager().getDefaultDisplay();

        try {
            Method getVerticalSize = Display.class.getMethod("getHeight");
            realDisplayHeight = (Integer) getVerticalSize.invoke(display);
        } catch (Exception e) {
            realDisplayHeight = 1500;
        }
        return realDisplayHeight;
    }
    else {
        return realDisplayHeight = 1500;
    }
}

public void getLog(){
    Log.i("screenWide:", String.valueOf(getRealScreenWidth()));
    Log.i("screenHeight:", String.valueOf(getRealScreenHeight()));
}

CHANGING LAYOUTPARAMS:

//++++++++++++++ EXAMPLE METHOD FOR CHANGING PARAMS IN ONCREATE() ++++++++++

public void changingLayoutParams(){

    // EXAMPLE FOR CHANGING HORIZONTAL LAYOUT PARAMS FOR API ABOVE 17:

    Button number1 = (Button) findViewById(R.id.number1);
    Button sidebar_v_1 = (Button) findViewById(R.id.sidebar_v_1);

    if (getRealScreenWidth() >= 1000){

        ViewGroup.MarginLayoutParams params = (ViewGroup.MarginLayoutParams) number1.getLayoutParams();
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
            params.setMarginStart((int) getResources().getDimension(R.dimen.levelSymbolLeftMargin));
            params.setMargins(params.getMarginStart(), params.topMargin, params.getMarginEnd(), params.bottomMargin);
        }

        ViewGroup.MarginLayoutParams params2 = (ViewGroup.MarginLayoutParams) sidebar_v_1.getLayoutParams();
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
            params2.setMarginStart((int) getResources().getDimension(R.dimen.levelSymbolLeftMargin));
            params2.setMargins(params2.getMarginStart(), params2.topMargin, params2.getMarginEnd(), params2.bottomMargin);
        }
    }
    else if (getRealScreenWidth() < 1000){

        ViewGroup.MarginLayoutParams params = (ViewGroup.MarginLayoutParams) number1.getLayoutParams();
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
            params.setMarginStart((int) getResources().getDimension(R.dimen.lockerMarginLeft));
            params.setMargins(params.getMarginStart(), params.topMargin, params.getMarginEnd(), params.bottomMargin);
        }

        ViewGroup.MarginLayoutParams params2 = (ViewGroup.MarginLayoutParams) sidebar_v_1.getLayoutParams();
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
            params2.setMarginStart((int) getResources().getDimension(R.dimen.lockerMarginLeft));
            params2.setMargins(params2.getMarginStart(), params2.topMargin, params2.getMarginEnd(), params2.bottomMargin);
        }
    }

}

I have built a ConstraintLayout with several nested layouts inside, with the following rough structure (reduced amount of elements inside):

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
    android:id="@+id/outerBlock"
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <androidx.core.widget.NestedScrollView
        android:id="@+id/scroll"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_marginRight="@dimen/nestedScroll_mR"
        android:layout_marginEnd="@dimen/nestedScroll_mR"
        android:layout_marginLeft="@dimen/nestedScroll_mL"
        android:layout_marginStart="@dimen/nestedScroll_mL"
        android:layout_marginTop="@dimen/nestedScroll_mT"
        android:layout_marginBottom="@dimen/nestedScroll_mB"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        android:fillViewport="true">

        <androidx.constraintlayout.widget.ConstraintLayout
            android:id="@+id/wrapper"
            android:layout_width="match_parent"
            android:layout_height="match_parent">

            <androidx.constraintlayout.widget.ConstraintLayout
                android:id="@+id/innerBlock0"
                android:layout_width="match_parent"
                android:layout_height="@dimen/firstInnerBlockH"
                app:layout_constraintTop_toTopOf="parent"
                app:layout_constraintStart_toStartOf="parent"
                app:layout_constraintLeft_toLeftOf="parent"
                app:layout_constraintEnd_toEndOf="parent"
                app:layout_constraintRight_toRightOf="parent">

            </androidx.constraintlayout.widget.ConstraintLayout>


            <androidx.constraintlayout.widget.ConstraintLayout
                android:id="@+id/innerBlock1"
                android:layout_width="match_parent"
                android:layout_height="@dimen/innerBlockH"
                app:layout_constraintTop_toBottomOf="@id/innerBlock0"
                app:layout_constraintStart_toStartOf="parent"
                app:layout_constraintLeft_toLeftOf="parent"
                app:layout_constraintEnd_toEndOf="parent"
                app:layout_constraintRight_toRightOf="parent">

                <Button
                    android:id="@+id/number1"
                    android:layout_width="@dimen/levelSymbol"
                    android:layout_height="@dimen/levelSymbol"
                    android:background="@drawable/number1"
                    android:layout_marginTop="@dimen/numberMarginTop"
                    android:layout_marginLeft="@dimen/numberMarginLeft"
                    android:layout_marginStart="@dimen/numberMarginLeft"
                    app:layout_constraintTop_toTopOf="parent"
                    app:layout_constraintLeft_toLeftOf="parent" />

                <Button
                    android:id="@+id/sidebar_v_1"
                    android:layout_width="@dimen/sidebarVWidth"
                    android:layout_height="@dimen/sidebarVHeight"
                    android:background="@drawable/side_v"
                    android:layout_marginLeft="@dimen/sideMarginLeft"
                    android:layout_marginStart="@dimen/sideMarginLeft"
                    app:layout_constraintTop_toBottomOf="@id/number1"
                    app:layout_constraintLeft_toLeftOf="parent" />

            </androidx.constraintlayout.widget.ConstraintLayout>

            <androidx.constraintlayout.widget.ConstraintLayout
                android:id="@+id/innerBlock2"
                android:layout_width="match_parent"
                android:layout_height="@dimen/innerBlockH"
                app:layout_constraintTop_toBottomOf="@id/innerBlock1">

            </androidx.constraintlayout.widget.ConstraintLayout>

        </androidx.constraintlayout.widget.ConstraintLayout>

    </androidx.core.widget.NestedScrollView>

</androidx.constraintlayout.widget.ConstraintLayout>

By changing the marginLeft and marginStart LayoutParam the layout would better fit into the display. At the beginning i just designed it for 1 screensize.


Solution

  • I noticed you're trying to change the margin values of 2 buttons in onCreate(). This will have the same effect as changing the margin values in your activity_main.xml file.

    If you're trying to do something else, for instance, change these values when you click a button, you can just set an onClickListener to another button, and then put this code in that onClick listener. Hope this helps. Thanks.