【问题标题】:ActionBarCompat: Hide ActionBar before activity is created (bug?)ActionBarCompat:在创建活动之前隐藏 ActionBar(错误?)
【发布时间】:2013-08-30 06:11:54
【问题描述】:

所以我在使用 ActionBarSherlock 并决定切换到新的 ActionBarCompat。使用 ABS,可以使用本文中描述的方式隐藏 ActionBar: How to hide action bar before activity is created, and then show it again?

但是,使用 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();
}

【问题讨论】:

  • @Johnson accordingly to the docs,不。 “ActionBarCompat 包含它自己的 ActionBar 类,并且要检索附加到您的活动的 Action Bar,您调用 getSupportActionBar()。”
  • 你解决过这个问题吗?我遇到了同样的问题。
  • @Studio4Development 不,最好的选择是创建一个类来处理不同类型的 ActionBar(本机和支持库)并调用正确的类。这是一个想法,还没有使用它,仍然使用 ABS 而不是 ABC。 ://

标签: android android-actionbar android-actionbar-compat


【解决方案1】:

我遇到了同样的问题,在我看来,找到了这种奇怪行为的原因。我查看了support library 的来源并得到了这个:

Appcompat 在ActionBarActivityDelegate 中创建新操作栏之前检查mHasActionBar 变量的值

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及其后代ActionBarDelegateHCActionBarActivityDelegateICSActionBarActivityJB,根据运行的android版本选择其中一个。并且方法 supportRequestWindowFeature 实际上几乎在所有这些中都可以正常工作,但是它在 ActionBarActivityDelegateICS 中被覆盖了

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

所以它对变量mHasActionBar没有影响,这就是getSupportActionBar()返回null的原因。

我们快到了。我想到了两种不同的解决方案。

第一种方式

  1. git导入appcompat的源项目

  2. 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;
    }
    
  3. 将此行放在活动的onCreate方法中getSupportActionBar()之前

    supportRequestWindowFeature(WindowCompat.FEATURE_ACTION_BAR);
    

第二种方式

  1. 从android SDK导入appcompat项目(src目录为空)

  2. 将此方法添加到您的活动中

    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);
        }
    }
    
  3. 像这样在您的活动的onCreate 方法中调用requestFeature()

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

我使用了第二种方式。就是这样。

【讨论】:

  • 这对我有用。我意识到我需要 getSupportActionBar() 否则 Navigation DrawerToggle 无法正常工作。在 KitKat 上,我必须在 requestFeature() 方法之前调用 supportRequestWindowFeature(Window.FEATURE_ACTION_BAR) ,否则会出现异常。感觉有点像 hack 我希望它在支持库的未来版本中得到解决。
  • 使用 ProGuard 时,我必须在我的应用程序的 proguard .cfg 文件中添加这两行:-keepclassmembers class android.support.v7.app.ActionBarActivity { android.support.v7.app.ActionBarActivityDelegate mImpl; }-keepclassmembers class android.support.v7.app.ActionBarActivityDelegate { boolean mHasActionBar; } Maaan,cmets 格式很烂。
【解决方案2】:

我用它来隐藏 AppCompat 中的 ActionBar: 样式.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>

【讨论】:

  • 这会隐藏 Gingerbread 上的 ActionBar 吗?我正在为此苦苦挣扎。它适用于更高级别的 API。
  • 这适用于 API 级别 14+。谢谢
【解决方案3】:

我不知道我是否完全理解你的问题,但我开始了。

我认为您需要同时使用两者:getSupportActionBar() 用于旧版本,getActionBar() 用于最新版本。这不是错误。

使用方法前需要验证设备版本。

希望能帮到你。

【讨论】:

  • 我也试过了,问题是 getSupportActionBar() 和 getActionBar() 的类型不同,这样我就必须复制所有代码才能使用这两种类型。跨度>
【解决方案4】:

您的活动是否扩展了 ActionBarActivity?可能它没有,这就是它使用 getActionbar() 方法运行的原因。

【讨论】:

  • 抱歉回复晚了,是的,我正在扩展 ActionBarActivity。现在我有时间我会尝试一些东西并很快在这里放更多细节。 :)
猜你喜欢
  • 2015-02-20
  • 2023-03-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-01-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多