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 ?

android developer
  • 114,585
  • 152
  • 739
  • 1,270
  • 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? – Jitesh Mohite Sep 09 '18 at 17:01
  • 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). – android developer Sep 09 '18 at 19:55
  • 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. – Jitesh Mohite Sep 10 '18 at 05:38
  • @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. – android developer Sep 10 '18 at 08:04
  • Is it possible for you to create different layouts for your different `orientation`s?, if yes then you should use layouts for landscape and portrait mode differently. – Jeel Vankhede Sep 13 '18 at 05:36
  • @JeelVankhede I think that putting them in the appropriate folders wouldn't work, because it's locked on one qualifier when you use configChanges . – android developer Sep 13 '18 at 07:06
  • @android developer can you post the xml file with toolbar – Kevin Kurien Sep 15 '18 at 09:32
  • @KevinKurien Updated, but it doesn't matter. This issue exists even if the Toolbar is all you use. – android developer Sep 15 '18 at 13:35
  • i didnt mean that . I meant can you post that file in this site – Kevin Kurien Sep 15 '18 at 13:37
  • @KevinKurien I don't understand what you mean. Sorry. – android developer Sep 15 '18 at 14:02

4 Answers4

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();
}
Ashvin solanki
  • 4,802
  • 3
  • 25
  • 65
  • 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. – android developer Sep 15 '18 at 13:29
  • @androiddeveloper sorry for that sir i will edited my answer – Ashvin solanki Sep 15 '18 at 13:33
  • 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. – android developer Sep 15 '18 at 14:03
  • @androiddeveloper you want to change Admob banner size ? – Ashvin solanki Sep 15 '18 at 14:07
  • 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. – android developer Sep 15 '18 at 14:09
  • @androiddeveloper u mean oncofig chage toolbar not changing its size ? – Ashvin solanki Sep 15 '18 at 14:12
  • @androiddeveloper edited my answer i hope its helps u – Ashvin solanki Sep 15 '18 at 14:34
  • 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 : https://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. – android developer Sep 15 '18 at 17:41
  • @androiddeveloper sir cant find the problem in the video please explain – Ashvin solanki Sep 15 '18 at 17:57
  • @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........... – Ashvin solanki Sep 15 '18 at 18:10
  • 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 : https://ufile.io/wh6yt . Maybe I should make a POC to show this – android developer Sep 15 '18 at 19:24
  • @androiddeveloper sir capture layout from android studio tools window – Ashvin solanki Sep 15 '18 at 19:44
  • 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? – android developer Sep 15 '18 at 22:40
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();
    }
}
Ahmet Zorer
  • 122
  • 1
  • 8
  • 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" ? – android developer Jul 22 '18 at 22:34
  • Or, how can I tell the Toolbar to have the style of the new configuration? – android developer Sep 15 '18 at 14:13
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.

Niravdas
  • 371
  • 2
  • 19
  • Why the button? The trigger is not a button. It's configuration change. And, what should I put there? – android developer Sep 15 '18 at 07:31
  • 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. – Niravdas Sep 15 '18 at 17:55
  • 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. – android developer Sep 15 '18 at 19:15
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

Kevin Kurien
  • 812
  • 6
  • 14
  • 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. – android developer Sep 15 '18 at 14:12