ActionBarCompat: скрыть ActionBar до создания активности (ошибка?)

Итак, я использовал ActionBarSherlock и решил переключиться на новый ActionBarCompat. С ABS, скрытие ActionBar было возможно, используя способ, описанный в этом сообщении: Как скрыть панель действий до создания активности, а затем снова показать ее?

Но с ActionBarCompat приложение вылетает из API14, потому что, когда вы устанавливаете android:windowActionBar как false, метод getSupportActionBar() возвращает значение null, даже если вы объявили getWindow().requestFeature(Window.FEATURE_ACTION_BAR); в метод onCreate().

Забавно, что если вы вызываете getActionBar() вместо этого, вы получаете объект, и все работает нормально.

Итак, это ошибка или я что-то упускаю? Любые идеи приветствуются!


styles.xml файл:

<style name="Theme.MyApp" parent="@style/Theme.AppCompat.Light.DarkActionBar">
    <item name="android:windowActionBar">false</item>
    <item name="android:windowTitleSize">0dp</item>
</style>

MyActivity.java файл:

...
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    // Get the action bar feature. This feature is disabled by default into the theme
    // for specific reasons.
    getWindow().requestFeature(Window.FEATURE_ACTION_BAR);
    ...
    // By default the action bar is hidden.
    getSupportActionBar().hide();
}

Ответ 1

Я застрял с той же проблемой и, как мне кажется, нашел причину этого странного поведения. Я просмотрел источник библиотеки поддержки и получил следующее:

Appcompat проверяет значение переменной mHasActionBar перед созданием новой панели действий в ActionBarActivityDelegate

final ActionBar getSupportActionBar() {
    // The Action Bar should be lazily created as mHasActionBar or mOverlayActionBar
    // could change after onCreate
    if (mHasActionBar || mOverlayActionBar) {
        if (mActionBar == null) {
            mActionBar = createSupportActionBar();
    ...

И мы можем изменить его значение, вызвав supportRequestWindowFeature(int featureId), который делегирован ActionBarActivity на ActionBarActivityDelegate.

Существует базовый класс делегата ActionBarDelegateBase и его потомки ActionBarDelegateHC, ActionBarActivityDelegateICS, ActionBarActivityJB, один из которых выбран в соответствии с версией бегущего андроида. И метод supportRequestWindowFeature на самом деле работает отлично почти во всех из них, но он переопределяется в ActionBarActivityDelegateICS как

@Override
public boolean supportRequestWindowFeature(int featureId) {
    return mActivity.requestWindowFeature(featureId);
}

Таким образом, это не влияет на переменную mHasActionBar, поэтому getSupportActionBar() возвращает значение null.

Мы почти там. Я пришел к двум различным решениям.

Первый способ

  • импортировать исходный проект appcompat из git

  • изменить переопределенный метод в ActionBarActivityDelegateICS.java на что-то вроде этого

    @Override
    public boolean supportRequestWindowFeature(int featureId) {
        boolean result = mActivity.requestWindowFeature(featureId);
        if (result) {
            switch (featureId) {
            case WindowCompat.FEATURE_ACTION_BAR:
                mHasActionBar = true;
            case WindowCompat.FEATURE_ACTION_BAR_OVERLAY:
                mOverlayActionBar = true;
            }
        }
        return result;
    }
    
  • поместите эту строку в действие onCreate до getSupportActionBar()

    supportRequestWindowFeature(WindowCompat.FEATURE_ACTION_BAR);
    

Второй способ

  • импортировать проект appcompat из SDK android (с пустым каталогом src)

  • добавьте этот метод в свою активность.

    private void requestFeature() {
        try {
            Field fieldImpl = ActionBarActivity.class.getDeclaredField("mImpl");
            fieldImpl.setAccessible(true);
            Object impl = fieldImpl.get(this);
    
            Class<?> cls = Class.forName("android.support.v7.app.ActionBarActivityDelegate");
    
            Field fieldHasActionBar = cls.getDeclaredField("mHasActionBar");
            fieldHasActionBar.setAccessible(true);
            fieldHasActionBar.setBoolean(impl, true);
    
        } catch (NoSuchFieldException e) {
            Log.e(LOG_TAG, e.getLocalizedMessage(), e);
        } catch (IllegalAccessException e) {
            Log.e(LOG_TAG, e.getLocalizedMessage(), e);
        } catch (IllegalArgumentException e) {
            Log.e(LOG_TAG, e.getLocalizedMessage(), e);
        } catch (ClassNotFoundException e) {
            Log.e(LOG_TAG, e.getLocalizedMessage(), e);
        }
    }
    
  • вызов requestFeature() в onCreate метод вашей деятельности, подобный этому

    if (Build.VERSION.SDK_INT >= 11) {
        requestFeature();
    }
    supportRequestWindowFeature(WindowCompat.FEATURE_ACTION_BAR);
    

Я использовал второй путь. Это все.

Ответ 2

Я использую это, чтобы скрыть ActionBar в AppCompat: style.xml

<style name="Theme.AppCompat.Light.NoActionBar" parent="@style/Theme.AppCompat.Light">
    <item name="android:windowNoTitle">true</item>
</style>

AndroidManifest.xml:

<activity
        android:name=".Splash"
        android:label="@string/title_activity_splash"
        android:theme="@style/Theme.AppCompat.Light.NoActionBar">
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />
            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
</activity>

Ответ 3

Я не знаю, правильно ли я понял ваш вопрос, но здесь я иду.

Я думаю, что вам нужно использовать оба: getSupportActionBar() для старых версий и getActionBar() для самых новых версий. Это не ошибка.

Перед использованием методов необходимо проверить версию устройства.

Надеюсь, я смог помочь.

Ответ 4

Увеличивает ли ваша активность ActionBarActivity? Вероятно, это не так, и поэтому он работает с методом getActionbar().