ActionBar в PreferenceFragment не пересчитывает высоту и размер шрифта

Используя последнюю библиотеку AppCompat-v21, я использовал ActionBarActivity для создания и заполнения PreferenceFragment. Тем не менее, ActionBar, похоже, не изменяет высоту и размер текста при изменении ориентации или размера экрана. Испытывая это на другие действия, это поведение, похоже, происходит только в PreferenceActivity (в отличие от этого вопроса, заданного здесь: Емкость/переполнение ActionBar не меняется при изменении ориентации).

Прежде всего, чтобы обработать изменения ориентации, я добавил android:configChanges="keyboard|keyboardHidden|orientation|screenSize" в манифест. Я подозреваю, что это основная причина этой проблемы, но, как я упоминал ранее, это работает на других Activity s.

Вот несколько скриншотов, которые объясняют проблему:

Запущен PreferenceActivity в портретном режиме:

Portrait start

Поворот в альбомный пейзаж:

rotate to landscape

Запущен PreferenceActivity в альбомном режиме:

landscape

Поворот в портрет из пейзажа:

rotate to portrait

Дополнительная информация

Вот класс PreferenceActivity:

import android.os.Bundle;
import android.support.v7.app.ActionBarActivity;

public class PrefsActivity extends ActionBarActivity {

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

        getFragmentManager().beginTransaction().replace(android.R.id.content, new PrefsFragment()).commit();
    }

}

Является ли это поведение ошибкой? Если нет, есть ли обходной путь или исправление?


РЕДАКТИРОВАТЬ I

Я попытался использовать новый виджет ToolBar, но не повезло.

import android.os.Bundle;
import android.support.v7.app.ActionBarActivity;
import android.support.v7.widget.Toolbar;

public class PrefsActivity extends ActionBarActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_preference);

        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar_pref);
        setSupportActionBar(toolbar);
        getSupportActionBar().setDisplayHomeAsUpEnabled(true);

        getFragmentManager().beginTransaction().replace(R.id.pref_frame, new PrefsFragment()).commit();
    }

}

Ответ 1

android:configChanges не рекомендуется, так как ориентация, клавиатура не являются единственными причинами активного отдыха.

Итак, лучший подход - удалить это из манифеста и установить setRetainInstance(true); в классе Fragment. Это обходит этот цикл уничтожения и воссоздания фрагмента, обновляя Activity.

Поскольку Toolbar включен в Activity, а не в Fragment, это обновит панель инструментов, сохранив фрагмент.

В случае Dialogs использование Fragment Lifecycle для закрытия/повторного открытия будет работать.

Источник: http://developer.android.com/guide/topics/resources/runtime-changes.html

Ответ 2

Я могу предложить это решение.

Работает с системой ActionBar, с панелью инструментов Lollipop и панелью инструментов AppCompat.

public static void fixActionBar(Activity activity, View toolbar)
{
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP)
    {
        if (toolbar == null)
        {
            int id = activity.getResources().getIdentifier("action_bar", "id", "android");
            if (id != 0) toolbar = (Toolbar) activity.findViewById(id);
        }
        if (toolbar != null)
        {
            Context context = toolbar.getContext();
            TypedArray typedArray = context.obtainStyledAttributes(new int[]
                    {android.R.attr.actionBarStyle, android.R.attr.actionBarSize});
            int actionStyle = typedArray.getResourceId(0, 0);
            int actionHeight = typedArray.getDimensionPixelSize(1, 0);
            typedArray.recycle();
            try
            {
                View container = (View) toolbar.getParent();
                Field field = container.getClass().getDeclaredField("mHeight");
                field.setAccessible(true);
                field.setInt(container, actionHeight);
                View overlay = (View) container.getParent();
                field = overlay.getClass().getDeclaredField("mActionBarHeight");
                field.setAccessible(true);
                field.setInt(overlay, actionHeight);
            }
            catch (Exception e)
            {

            }
            toolbar.getLayoutParams().height = actionHeight;
            toolbar.setMinimumHeight(actionHeight);
            typedArray = context.obtainStyledAttributes(actionStyle, new int []
                    {android.R.attr.titleTextStyle});
            ((Toolbar) toolbar).setTitleTextAppearance(context, typedArray.getResourceId(0, 0));
            typedArray.recycle();
        }
    }
}

Вызвать этот метод из onConfigurationChanged вашей деятельности.

Ответ 3

Выполняют ли другие действия, которые вы тестировали, с объявлением android:configChanges в манифесте?

Как вы сказали, проблема в том, что

android:configChanges="keyboard|keyboardHidden|orientation|screenSize"

не обрабатывает вращение. Это фактически останавливает активность и представления от воссоздания, заставляя представления не читать соответствующие значения после изменения конфигурации.

Учитывая тот факт, что вы используете фрагменты, я бы удалил атрибут android:configChanges и сохранил экземпляр PrefsFragment.