ActionBarSherlock中的强制溢出菜单

时间:2012-11-01 14:51:22

标签: android android-actionbar actionbarsherlock android-holo-everywhere

我想在预ICS设备(2.3 - 2.1)上使用4.0+溢出菜单。我正在使用带ActionBarSherlock的HoloEverywhere。

我尝试了以下解决方案:

ActionBarSherlock & HoloEverywhere - Forcing Overflow?

但它不起作用,因为absForceOverflow不存在。是在最新版本中删除了什么?我已经检查了ABS和HE库项目的R个文件,而且该字段根本就没有。

我的应用主题设置为@style/Holo.Theme.Sherlock.Light,这是我尝试继承的主题,并将absForceOverflow参数集添加到true

4 个答案:

答案 0 :(得分:36)

从ActionbarSherlock 4.2开始,我们失去了管理溢出菜单可见性的能力。 为了使其工作,您需要结合两种方法:

  1. 要强制Android 3.x(蜂窝)和更高版本的菜单可见性,您需要使用this hack + add check Android版本:

    public static final int DEVICE_VERSION   = Build.VERSION.SDK_INT;
    public static final int DEVICE_HONEYCOMB = Build.VERSION_CODES.HONEYCOMB;
    if (DEVICE_VERSION >= DEVICE_HONEYCOMB)
        // Code from answer above
    
  2. 预蜂窝设备的打开菜单:

    • 打开ActionBarSherlock/src/com/actionbarsherlock/internal/view/menu/ActionMenuPresenter.java,转到方法reserveOverflow
    • 用以下内容替换原文:

      public static boolean reserveOverflow(Context context){     返回true; }

    这会强制菜单显示......

    • 但是点击菜单按钮菜单弹出窗口时没有显示。为实现此目的,我们需要在活动类中重写此内容:

      @Override
      public boolean onKeyUp(int keyCode, KeyEvent event) {
          if (DEVICE_VERSION < DEVICE_HONEYCOMB) {
              if (event.getAction() == KeyEvent.ACTION_UP &&
                  keyCode == KeyEvent.KEYCODE_MENU) {
                  openOptionsMenu();
                  return true;
              }
          }
          return super.onKeyUp(keyCode, event);
      }
      
  3. 完成此操作后,您应该为所有Android版本提供绝对正常的溢出操作栏菜单。

答案 1 :(得分:27)

作为Siddharth Lele has pointed out,它已在最后的ABS版本中删除,以便与实际的操作栏相同。因此,乍一看放弃显示此菜单是最佳选择。

然而,在我看来,在某些设备的屏幕上显示溢出菜单而不显示其他设备是Android的Action Bar中的一个重大设计缺陷。原因如下:

在具有硬件菜单键的设备中,菜单不会显示在操作栏中。最近设备的趋势是将硬件按钮的数量减少到最小,因为它被认为更加用户友好(并且因为iphone没有按钮,所以他们复制了这个设计)。其他制造商确实包括菜单按钮,但除非你按下它,否则它是隐藏的(是的,当你不再需要灯时,它会亮起。不是明智的设计,但是当所有的按钮都关闭时,手机看起来更加iphonish)。 / p>

为了更好地理解这个含义,让我们看一个例子: 用户A有一个带菜单键的设备。他正在使用他最喜欢的邮件客户端。配置邮件帐户的选项放在溢出菜单中,以及常用选项(帮助,关于等)。他想添加第二个帐户,但他不知道如何进入这个菜单。屏幕上没有任何信息可以帮助他意识到该怎么做。 因此,用户A会询问他的朋友B,他也在使用此邮件客户端。用户B拥有最新的Nexus N + 1 Googlephone,并且他可以在操作栏中查看溢出图标,因为他的设备没有使用硬件菜单键。他显示A如何通过打开此菜单添加第二个帐户。用户A现在完全混淆了,因为他们使用相同的应用版本。沮丧,A可能会认为问题在于他的手机太老了。 B也被混淆了。

此时您可能会认为AB都是无法理解如何使用智能手机的傻瓜。但与桌面应用程序不同,绝大多数智能手机用户不了解其设备的基础知识。他们以前的手机很可能是一个带有简单固件的键盘设备。电池坏了,他们去了商店替换,但它缺货了。他们本可以在互联网上订购一台,但它比购买新手机更贵。所以他们卖了一部支持触摸屏的手机,因为这就是现在的手机。现在,他们必须面对一台拥有完整操作系统的小型计算机。更糟糕的是,手机只有一个“快速入门指南”,要获得完整的手册,他们必须从互联网上下载pdf。你猜怎么着?他们不会。

如果您正在开发移动应用程序,您应该假设用户可能不了解有关计算机,操作系统或类似应用程序的事情。您应该使GUI在各种设备上看起来相似,以便人们可以学习并记住如何使用它。不要责怪Action Bar设计师:如果用户喜欢AB,那么首先不知道如何进入选项菜单这是你的错误。这就是为什么你应该包括一个始终可见的选项屏幕的方法。

后退键发生了类似的事情。某些设备可能具有HW后备密钥,较新的设备通常不具备。但每当我们回到我们的应用程序时,我们总是在Action Bar中显示箭头状按钮,对吧?是的,我知道一个按钮在“导航树”中导航,而另一个按钮“回到过去”,但这也是另一个设计缺陷:对于普通用户,后面只是回来了。他在屏幕上有这个按钮,他也可以使用HW,但这是可选的。应该使用溢出菜单完成相同的操作。

所以如果你认为(像我一样)这是一个重要的按钮,不要放弃。 提供常规主选项菜单并使用相关子菜单填充。将其设为操作按钮并为其指定描述性图标,甚至是“MENU”等文本说明。您还可以模仿溢出菜单图标,只需使用其中一个drawable:

    // For ActionBarSherlock
    abs__ic_menu_moreoverflow_normal_holo_dark.png
    abs__ic_menu_moreoverflow_normal_holo_light.png

    // For ActionBar
    ic_menu_moreoverflow_normal_holo_light.png
    ic_menu_moreoverflow_normal_holo_dark.png

此外:将图像复制粘贴到项目资源文件夹中。您永远无法知道ABS的未来版本或ActionBar的下一个实现是否会包含它们。

答案 2 :(得分:18)

如果您使用的是版本4.2.0,那么.ForceOverflow主题实际上已被删除。

来源: Version 4.2.0 Changelog

更改日志的摘录:

Add SearchView widget for standard search interaction (API 8+ only)
Fix: ShareActionProvider in the split action bar no longer fills the entire screen.
Fix: ShareActionProvider now does file I/O on a background thread.
Fix: Automatically correct ColorDrawable not respecting bounds when used as a stacked background.
Fix: Ensure fragments collection is present before dispatching events.
Fix: XML-defined onClick searches the correct context for the declared method.
Fix: Ensure action mode start/finish callbacks are invoked on the activity for the native action bar.
Fix: Allow tab callbacks to have a fragment transaction instance for any FragmentActivity.
Fix: Ensure CollapsibleActionView callbacks are dispatched in both native and compatbility action bars.
Fix: Remove .ForceOverflow themes. These never should have been included.

如果您绝对需要强制溢出,则需要下载早期版本的ABS。您可以在此处根据其发布历史记录获取下载列表:http://actionbarsherlock.com/download.html

我个人仍然使用ABS版本4.1.0,因为我目前不想在我的应用程序中进行辅助更改。我也在我的theme.xml

中使用了这个
<style name="MyTheme" parent="@style/Theme.Sherlock.ForceOverflow">
    <item name="android:windowBackground">@color/background</item>
    <item name="actionBarStyle">@style/Widget.Styled.ActionBar</item>
    <item name="android:actionBarStyle">@style/Widget.Styled.ActionBar</item>
</style>

<style name="MyTheme.ForceOverflow">
    <item name="absForceOverflow">true</item>
</style>

Activity中为manifest.xml应用主题时,我将其用作属性:"@style/Theme.SociallyYOU"

同样,如果你必须绝对强制溢出,你可能还想在另一个问题中阅读CommonsWare的想法:https://stackoverflow.com/a/12872537/450534

注意:话虽如此,如果权衡不重要,最好使用最新版本。通过发布我强制溢出菜单的方式,我既不建议您使用旧版本,也不建议使用旧版本。它只是告诉你可能性。

答案 3 :(得分:0)

我发现Exterminator13的答案在某些Android设备上不起作用(我认为总数很小),但为了适应尽可能多的设备,我使用对话框并使用一个菜单与android:showAsAction = “总是”作为溢出菜单按钮。毕竟,actionbarsherlock的溢出菜单的效果是通过它的来源实现的,所以如果它不那么麻烦,为什么不实现我们自己的效果。如果您了解中文,您还可以看到my blog

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android" >
    <item
        android:id="@+id/more"
        android:icon="@drawable/overflow"
        android:showAsAction="always" 
    />
</menu>

private Dialog popupDialog;
private Boolean popupState=false;

    public boolean onOptionsItemSelected(MenuItem item) {
    switch (item.getItemId()) {
    case android.R.id.home:
        this.finish();
        return true;
    case R.id.more:
        if (!popupState) {
            showPop();
        }else {
            popupDialog.dismiss();
        }
    default:
        return super.onOptionsItemSelected(item);
    }
}

private void showPop(){
    LayoutInflater inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    View view = inflater.inflate(ResID, null);
    ListView listView = (ListView) view.findViewById(ResID);
    listView.setAdapter(yourOwnAdapter);
    popupDialog = new Dialog(WifiAuthWireActivity.this);
    popupDialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
    popupDialog.getWindow().setBackgroundDrawable(new ColorDrawable(Color.WHITE));
    popupDialog.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);
    popupDialog.setContentView(view);
    // Calculate ActionBar height
    TypedValue tv = new TypedValue();
    ActionBar maActionBar=getSupportActionBar();
    int actionBarHeight=maActionBar.getHeight();
    if (getTheme().resolveAttribute(android.R.attr.actionBarSize, tv, true))
    {
        actionBarHeight = TypedValue.complexToDimensionPixelSize(tv.data,getResources().getDisplayMetrics());
    }
    WindowManager.LayoutParams wmlp = popupDialog.getWindow().getAttributes();
    wmlp.gravity = Gravity.TOP | Gravity.RIGHT;
    wmlp.x+=12;
    wmlp.y+=actionBarHeight;
    popupDialog.getWindow().setAttributes(wmlp);
    popupDialog.show();
}