How to re-adjust views according to new configuration change?
Asked Answered
M

4

6

Background

I have an app (here) that has Admob banners in it, and I don't like the fact that the banners get re-loaded every time I change orientation, so for a long time I had the same workaround for this, to avoid re-creation of the Activity, and therefore avoid re-creation of the Admob view :

<activity ... android:configChanges="keyboard|keyboardHidden|orientation|screenLayout|uiMode|screenSize|smallestScreenSize" android:screenOrientation="fullUser" ...>

The problem

This works nice, but it's not really a good solution or recommended. Just a workaround that I had to use because of this issue (wrote about it here).

The problem is that some UI elements, such as the toolbar, don't get change according to the new orientation.

This causes a behavior that the toolbar stays on the same height and same font size as it was when the app started.

Example on portrait->landscape :

enter image description here

As you can see, the height stayed large for landscape, and the font size stayed large too.

Example on landscape->portrait :

enter image description here

Here you see the opposite. The height stayed small, and the font size stayed small too.

The layout is basically something as such:

<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
    android:layout_height="match_parent">

    <androidx.drawerlayout.widget.DrawerLayout
        android:id="@+id/activity_app_list__drawerLayout" android:layout_width="match_parent"
        android:layout_height="match_parent">

        <LinearLayout
            android:layout_width="match_parent" android:layout_height="match_parent"
            android:orientation="vertical">

            <FrameLayout
                android:layout_width="match_parent" android:layout_height="?attr/actionBarSize"
                android:background="?attr/colorPrimary">

                <androidx.appcompat.widget.Toolbar
                    android:id="@+id/activity_main__toolbar" android:layout_width="match_parent"
                    android:layout_height="?attr/actionBarSize" android:background="@null"
                    android:theme="?attr/actionBarTheme" tools:ignore="UnusedAttribute"/>
            </FrameLayout>

            <RelativeLayout
                android:layout_width="match_parent" android:layout_height="match_parent">
                <FrameLayout
                    android:id="@+id/activity_app_list__fragmentContainer"
                    android:layout_width="match_parent" android:layout_height="match_parent"
                    android:layout_above="@+id/activity_app_list__adContainer"/>

                <ImageView
                  android:layout_width="match_parent" android:layout_height="wrap_content"
                    android:src="@drawable/msl__action_bar_shadow"
                    tools:ignore="ContentDescription"/>

                <FrameLayout
                    android:id="@+id/activity_app_list__adContainer"
                    android:layout_width="match_parent" android:layout_height="wrap_content"
                    android:layout_alignParentBottom="true"/>
            </RelativeLayout>
        </LinearLayout>

        <ScrollView
            android:id="@+id/activity_app_list__drawerView" android:layout_width="240dp"
            android:layout_height="match_parent" android:layout_gravity="start"
            android:background="?android:attr/windowBackground">

            <LinearLayout
                android:layout_width="match_parent" android:layout_height="wrap_content"
                android:orientation="vertical">

                <androidx.appcompat.widget.LinearLayoutCompat
                    android:id="@+id/activity_app_list__appToolsContainer"
                    android:layout_width="match_parent" android:layout_height="wrap_content"
                    android:divider="?attr/gridded_listview__divider" android:orientation="vertical"
                    android:showDividers="middle"
                    tools:ignore="MissingRegistered,UnusedAttribute"/>

                <View
                    android:layout_width="match_parent" android:layout_height="1dp"
                    android:layout_marginBottom="8dp" android:layout_marginTop="8dp"
                    android:background="?attr/activity_app_list__drawer_lisview_divider"/>

                <androidx.appcompat.widget.LinearLayoutCompat
                    android:id="@+id/activity_app_list__usefulShortcutsContainer"
                    android:layout_width="match_parent" android:layout_height="wrap_content"
                    android:divider="?attr/gridded_listview__divider" android:orientation="vertical"
                    android:showDividers="middle"
                    tools:ignore="MissingRegistered,UnusedAttribute"/>

                <View
                    android:layout_width="match_parent" android:layout_height="1dp"
                    android:layout_marginBottom="8dp" android:layout_marginTop="8dp"
                    android:background="?attr/activity_app_list__drawer_lisview_divider"/>

                <androidx.appcompat.widget.LinearLayoutCompat
                    android:id="@+id/activity_app_list__appOtherContainer"
                    android:layout_width="match_parent" android:layout_height="wrap_content"
                    android:divider="?attr/gridded_listview__divider" android:orientation="vertical"
                    android:showDividers="middle"
                    tools:ignore="MissingRegistered,UnusedAttribute"/>
            </LinearLayout>
        </ScrollView>
    </androidx.drawerlayout.widget.DrawerLayout>

</RelativeLayout>

What I've tried

I tried to reset the height of the toolbar to the height it's supposed to have using the attribute, but it didn't work. Also tried to set the text appearance of the title of the toolbar to get to the new orientation, and it didn't help.

I also tried to call requestLayout, but it didn't work either.

The question

How can I tell various UI elements, such as the toolbar, that it should change based on the new configuration change?

As an alternative, is it possible to apply the style and height of the Toolbar to be based on the new configuration, even though I use configChanges ?

Maintenon answered 22/7, 2018 at 20:48 Comment(10)
That was the standard size for the toolbar. It looks like this only in landscape mode. Can you detect orientation detect callback and set the height of the toolbar based on the configuration?Greathearted
I guess it could be a solution, but it assumes that the various heights for the toolbar are determined only by orientation (which I' almost sure is wrong).Maintenon
But that is the standard height of toolbar in landscape mode. If it reduced it will not look good. It will be good if you rearrange your cards according to that.Greathearted
@jiteshmohite Incorrect. In normal cases, the height of the toolbar changes when you change the orientation. Just try any normal app, or one of Google's apps, and see for yourself.Maintenon
Is it possible for you to create different layouts for your different orientations?, if yes then you should use layouts for landscape and portrait mode differently.Raposa
@JeelVankhede I think that putting them in the appropriate folders wouldn't work, because it's locked on one qualifier when you use configChanges .Maintenon
@android developer can you post the xml file with toolbarWarehouse
@KevinKurien Updated, but it doesn't matter. This issue exists even if the Toolbar is all you use.Maintenon
i didnt mean that . I meant can you post that file in this siteWarehouse
@KevinKurien I don't understand what you mean. Sorry.Maintenon
T
3

Ref : Android - ActionBar not resizing with onConfigurationChanged ( AppCompat )

pointed out you should save and restore the instance state instead of handling configuration changes yourself if possible. If you have good reason not to do that you can try to update the toolbar's height and text appearance after the configuration change.

The following code should work for the support library version of Toolbar. The attributes actionBarSize, titleTextAppearance and subtitleTextAppearance are provided by the support library.

The code assumes that you have a custom attribute appToolbarStyle declared in attrs.xml. If you don't need that you can adapt the code to use R.style.Widget_AppCompat_Toolbar directly instead.

import android.support.v7.widget.Toolbar;

...

private Toolbar toolbar;

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

    setContentView(R.layout.main_activity);

    toolbar = findViewById(R.id.toolbar);
}

@Override
public void onConfigurationChanged(Configuration newConfig) {
    super.onConfigurationChanged(newConfig);

    updateToolbar();
}

private void updateToolbar() {
    if (toolbar == null)
        return;

    final Context context = toolbar.getContext();

    int[] attr = new int[] { R.attr.actionBarSize, R.attr.appToolbarStyle };
    int idxActionBarSize = 0;
    int idxAppToolbarStyle = 1;
    TypedArray a = context.obtainStyledAttributes(attr);
    int actionBarSize = a.getDimensionPixelSize(idxActionBarSize, 0);
    int appToolbarStyle = a.getResourceId(idxAppToolbarStyle, R.style.Widget_AppCompat_Toolbar);
    a.recycle();

    if (actionBarSize != 0) {
        ViewGroup.LayoutParams layoutParams = toolbar.getLayoutParams();
        if (layoutParams != null) {
            layoutParams.height = actionBarSize;
        }

        toolbar.setMinimumHeight(actionBarSize);
    }

    attr = new int[] { R.attr.titleTextAppearance, R.attr.subtitleTextAppearance };
    int idxTitleTextAppearance = 0;
    int idxSubtitleTextAppearance = 1;
    a = context.obtainStyledAttributes(appToolbarStyle, attr);
    int titleTextAppearance = a.getResourceId(idxTitleTextAppearance, 0);
    int subtitleTextAppearance = a.getResourceId(idxSubtitleTextAppearance, 0);
    a.recycle();

    if (titleTextAppearance != 0) {
        toolbar.setTitleTextAppearance(context, titleTextAppearance);
    }

    if (subtitleTextAppearance != 0) {
        toolbar.setSubtitleTextAppearance(context, subtitleTextAppearance);
    }

    toolbar.requestLayout();
}
Tonatonal answered 15/9, 2018 at 11:19 Comment(13)
First of all, you didn't mention what to put there. Second, those qualifiers will be ignored anyway, as I use configChanges . So unless you know how to overcome this for specific views, your solution can't work.Maintenon
@androiddeveloper sorry for that sir i will edited my answerTonatonal
If I remove configChanges , it won't solve the issue with Admob, and then it loses the point of the question, and also there's no reason to create multiple layout files.Maintenon
@androiddeveloper you want to change Admob banner size ?Tonatonal
No. I don't want Admob to re-load itself upon every orientation change, so I used configChanges, but then it causes the Toolbar to stay on its initial size and style, instead of re-adjusting itself to the new configuration.Maintenon
@androiddeveloper u mean oncofig chage toolbar not changing its size ?Tonatonal
@androiddeveloper edited my answer i hope its helps uTonatonal
By far the best answer here, but... For some reason, if I start from landscape and change to portrait, the icons of the toolbar (action items and the nav drawer) aren't aligned the same as the text of it (the title). Weird thing is that I don't think this issue exists if I change from portrait to landscape. I will now accept your answer and give +1, but not the bounty, as it has this issue. Here's a video showing this issue : ufile.io/03erw . If you solve this, I will grant the bounty. I also wonder if there is a way to avoid all of the properties that need to change.Maintenon
@androiddeveloper sir cant find the problem in the video please explainTonatonal
@androiddeveloper sir don't posted answer for the bounty.. i answered because this question also helps me when i am working on this type of project and i am get this type of problem...........Tonatonal
OK, it's a bit hard to see on the video, so compare these 2 screenshots (look at the title of the toolbar) of portrait vs when I switch from landscape to portrait : ufile.io/wh6yt . Maybe I should make a POC to show thisMaintenon
@androiddeveloper sir capture layout from android studio tools windowTonatonal
Never mind. On the way to put the code into my app, I've accidentally removed the part of setMinimumHeight . Seems to work fine now. Why is it needed, if you already put the layout params height? Also, do you think it's possible to generalize this solution, so that you won't have to get the properties yourself, and just tell the views that the configuration has changed, so that they should refresh their properties?Maintenon
F
0

By declaring configChange, you confirm that you will handle the change by yourselves on onConfigurationChanged() method. Here is the sample provided by Android docs:

@Override
public void onConfigurationChanged(Configuration newConfig) {
    super.onConfigurationChanged(newConfig);

    // Checks the orientation of the screen
    if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) {
        Toast.makeText(this, "landscape", Toast.LENGTH_SHORT).show();
    } else if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT){
        Toast.makeText(this, "portrait", Toast.LENGTH_SHORT).show();
    }
}
Fleisher answered 22/7, 2018 at 21:34 Comment(2)
I'm talking about the views, and more specifcally the Toolbar. I already use this function, but I don't know what to do for the Toolbar, for example. How do I tell it: " use the new orientation now" ?Maintenon
Or, how can I tell the Toolbar to have the style of the new configuration?Maintenon
H
0

you may use simple refresh button to refresh any of your View Control. put refresh button as simple button as below , you may change Button's proparties as you want.

<Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Refresh"
        android:onClick="btnrefresh"/>

now as simpally you can code here in click event.

public void btnrefresh(View view)
{
 //Do your task here to change any View Control(including Layout Changes).
}

it will make changes on UI as you code.

Hueston answered 14/9, 2018 at 21:44 Comment(3)
Why the button? The trigger is not a button. It's configuration change. And, what should I put there?Maintenon
it is an alternative way to refresh Controls. you can put same code in any event , if you put this in onCreat() mathod then problem arises , because you trying to put control on view which actually not have been created.Hueston
The important code is missing here. Where's the part of re-adjusting the views according to the new configuration ? All you've added here is a button that does nothing.Maintenon
W
0

Instead of android:titleTextAppearance try app:titleTextAppearance

<android.support.v7.widget.Toolbar
    android:id="@+id/main_toolbar"
    android:layout_width="match_parent"
    android:layout_height="?attr/actionBarSize"
    android:background="?attr/colorPrimary"
    app:titleTextAppearance="@style/ToolbarTitle"
    android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
    app:popupTheme="@style/ThemeOverlay.AppCompat.Light" />  

Toolbar Style:

<style name="ToolbarTitle" parent="@style/TextAppearance.Widget.AppCompat.Toolbar.Title">
        <item name="android:textSize">20sp</item>
</style>  

I got this answer from here.Take a look

Warehouse answered 15/9, 2018 at 11:6 Comment(1)
The question isn't about the text. I don't even use titleTextAppearance . It's about the whole Toolbar View (and others in case I didn't notice. I've noticed its height and its text size not changing upon orientation change, because I use configChanges . What you've put would stay in same text size instead of using the proper standard sizes, which is what I'm trying to avoid.Maintenon

© 2022 - 2024 — McMap. All rights reserved.