android 4.0,操作栏上的文本永远不会显示

发布于 2025-01-05 18:08:10 字数 259 浏览 1 评论 0原文

我正在尝试使用 google 的新 api,特别是操作栏。

当构建设置为 api 10 时,如果我按下菜单按钮,我会看到漂亮的菜单选项,每个选项都有图片和图标。使用 api 14 时,无论我尝试什么,它总是将图标放在操作栏中,没有任何文本。我已经尝试了我能想到的一切。我给了它“with text”属性,将文本更改为单个字符(以防房间问题),但什么也没有。

我以前见过这样做,甚至在 android.developer 的开发人员指南中,但我似乎找不到如何让它显示的答案。

I am trying to use the new api's from google, specifically the action bar.

When the build was set at api 10, if I pressed the menu button, I got nice looking menu options, each with a picture and icon. When using api 14, No matter what I try, it always puts the icon in the action bar with NO text. I have tried everything I can think of. I gave it the "with text" property, changed the text to a single character (in case it was a room issue), but nothing.

I have seen this done before, even in the developer guide at android.developer, but I can't seem to find an answer as to HOW to get it to show up.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

我怀疑 Android 开发人员有意识地决定永远不会在狭窄的操作栏上显示单个菜单项的文本和图标。但如果你真的想这样做,你可以使用 android:actionLayout 在你的 menu.xml 文件中。 Android ActionBar 文档 有更好的解释。

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:id="@+id/menu_foo"
          android:title="@string/menu_foo"
          android:icon="@drawable/ic_menu_foo"
          android:showAsAction="always"
          android:actionLayout="@layout/action_button_foo" />
</menu>

然后创建您的 action_button_foo.xml 布局:

<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:paddingTop="14dp"
    android:paddingBottom="14dp"
    android:gravity="center"
    android:text="@string/menu_foo"
    android:drawableLeft="@drawable/ic_menu_foo"
    android:background="@drawable/bg_btn_action_bar"
    android:clickable="true" />

并为其背景使用选择器 bg_btn_action_bar.xml,这样当您点击它时它就会改变颜色:

<?xml version="1.0" encoding="utf-8" ?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item
        android:state_pressed="true"
        android:drawable="@drawable/bg_action_bar_pressed" />
    <item
        android:drawable="@color/transparent" />
</selector>

现在您需要制作您的自定义视图处理点击事件。在您的 Activity 中,我喜欢这样做,这样我就可以处理 onOptionsItemSelected 中的点击以及所有其他非自定义项目。

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    getMenuInflater().inflate(R.menu.my_menu, menu);

    final MenuItem item = menu.findItem(R.id.menu_foo);
    item.getActionView().setOnClickListener(new OnClickListener() {
        @Override
        public void onClick(View v) {
            onOptionsItemSelected(item);
        }
    });

    return super.onCreateOptionsMenu(menu);
}

I suspect that it was a conscious decision by the Android developers to never display a single menu item's text and icon on a narrow action bar. But if you really want to do so, you can use android:actionLayout in your menu.xml file. The Android ActionBar documentation has a slightly better explanation.

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:id="@+id/menu_foo"
          android:title="@string/menu_foo"
          android:icon="@drawable/ic_menu_foo"
          android:showAsAction="always"
          android:actionLayout="@layout/action_button_foo" />
</menu>

Then create your action_button_foo.xml layout:

<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:paddingTop="14dp"
    android:paddingBottom="14dp"
    android:gravity="center"
    android:text="@string/menu_foo"
    android:drawableLeft="@drawable/ic_menu_foo"
    android:background="@drawable/bg_btn_action_bar"
    android:clickable="true" />

and use a selector for its background bg_btn_action_bar.xml, so it changes color when you tap it:

<?xml version="1.0" encoding="utf-8" ?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item
        android:state_pressed="true"
        android:drawable="@drawable/bg_action_bar_pressed" />
    <item
        android:drawable="@color/transparent" />
</selector>

Now you'll need to make your custom view handle click events. In your Activity, I like to do this, so that I can handle the click in onOptionsItemSelected along with all my other, non-custom items.

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    getMenuInflater().inflate(R.menu.my_menu, menu);

    final MenuItem item = menu.findItem(R.id.menu_foo);
    item.getActionView().setOnClickListener(new OnClickListener() {
        @Override
        public void onClick(View v) {
            onOptionsItemSelected(item);
        }
    });

    return super.onCreateOptionsMenu(menu);
}
遗心遗梦遗幸福 2025-01-12 18:08:10

这绝对与我在运行 4.0.4 的 Nexus S 上观察到的情况相同。我的应用程序使用一个带有多个选项卡的操作栏,这些选项卡作为片段实现。我的各种片段对操作栏上显示的菜单选项进行调整,同时其选项卡可见。

这似乎是 ICS 中的一个错误,因为它在我的 Nexus S 和模拟器(HVGA 和 WVGA800)上的执行情况一致如下:

  1. 在纵向模式下,我的徽标/向上按钮出现在操作栏的顶行,选项卡显示在第二行,任何操作仅显示为顶行右侧的图标(无文本)。
  2. 但是,如果当我旋转到横向时,操作栏会折叠成一行,并且选项卡会作为向上按钮旁边的微调器(下拉列表)向上移动到顶部栏。 但值得注意的是,然后文本出现在我的操作图标旁边。

我注意到选项卡微调器的一些其他故障使我相信 ICS 的这个小角落有点混乱/有缺陷。如果我告诉应用程序在窄显示屏上拆分操作栏(通过在清单中添加 android:uiOptions="splitActionBarWhenNarrow" ),ICS 总是将这些项目推到底部栏,即使仍然有很多即使有额外的栏,它仍然不显示文本,只显示图标,

在我运行 4.0.4 的 Xoom 上,选项卡和操作项始终按照您期望的方式显示,因为。 解决方法:如果您确实希望在纵向模式下在操作栏上显示文本,则

需要从菜单项中删除该图标,然后才会显示文本。不过,这并不是我们想要的。

我在这里发布了错误报告:https://code.google.com/p/android/issues/detail?id=30180

This is definitely the same thing I've observed on my Nexus S running 4.0.4. My app uses an action bar with several tabs that are implemented as fragments. My various fragments make adjustments to the menu options displayed on the action bar while the their tab is visible.

This appears to be a bug in ICS, because it performs consistently as follows, both on my Nexus S and in the emulator (both HVGA and WVGA800):

  1. In portrait mode, my logo/up button appears on the top row of the action bar, tabs appear on the second row, and any actions appear as icons only (no text) in the right side of the top row.
  2. But if when I rotate to landscape, the action bar collapses to a single row, and tabs move up to the top bar as a spinner (drop-down list) next to my up button. But notably, then the text appears next to my action icons.

I noticed some other glitches with the tab spinner that lead me to believe that this little corner of ICS is a bit messy/buggy. If I tell the application to split the action bar on narrow displays (by adding android:uiOptions="splitActionBarWhenNarrow" in the manifest, ICS always pushes those items to the bottom bar, even though there's still plenty of room at the top. And even with the extra bar, it still doesn't display the text, just the icon.

On my Xoom running 4.0.4, tabs and action items always appear the way you'd expect them to appear because there's plenty of room.

Workaround: if you really want text on the action bar in portrait mode, you need to give up the icon. Remove the icon from your menu item and the text will appear. This isn't exactly what we're after though.

I've posted a bug report here: https://code.google.com/p/android/issues/detail?id=30180.

〆一缕阳光ご 2025-01-12 18:08:10

如果您希望选项菜单显示在带有 Honeycomb 的操作栏中,我这样做了:

在您的活动中,覆盖此函数:

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    MenuInflater inflater = getMenuInflater();
    inflater.inflate(R.menu.actionbar_universe, menu);
    return true;
}

其中 R.menu.actionbar_universe 定义您的菜单项,如下所示:

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:id="@+id/crossholdings" android:showAsAction="always|withText"
      android:title="Cross Holdings" android:icon="@drawable/actionbar_cross"/>
</menu>

注意 showAsAction="always|withText"并指定 android:title。

如果您有该资源但无法正常工作,请在此处复制|粘贴您的菜单资源。

编辑:这回答了错误的问题,但它是原文。

我使用这段代码来设置操作栏的标题,并用我公司的徽标将其涂成红色。在3.0中运行良好。

public ActionBar setActionBarStyle(String title) {
    ActionBar actionBar = setActionBarStyle();
    actionBar.setTitle(title);
    return actionBar;
}

public ActionBar setActionBarStyle() {
    ActionBar actionBar = getActionBar();
    ShapeDrawable actionBackground = new ShapeDrawable();
    actionBackground.getPaint().setColor(Color.RED);
    actionBackground.setBounds(0, 0, 5, 5);
    actionBar.setBackgroundDrawable(actionBackground);
    actionBar.setDisplayUseLogoEnabled(true);
    actionBar.setDisplayHomeAsUpEnabled(true);

    return actionBar;
}

If you want your Options Menu to show up in your action bar with Honeycomb, I did this:

In your activity, override this function:

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    MenuInflater inflater = getMenuInflater();
    inflater.inflate(R.menu.actionbar_universe, menu);
    return true;
}

where R.menu.actionbar_universe define your menu item like this:

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:id="@+id/crossholdings" android:showAsAction="always|withText"
      android:title="Cross Holdings" android:icon="@drawable/actionbar_cross"/>
</menu>

Note the showAsAction="always|withText" and specify android:title.

If you have that and its not working please copy|paste your menu resource here.

EDIT: This answers the wrong question, but it is the original text.

I use this bit of code to set the title of the action bar, and paint it red with my companies logo. It works well in 3.0.

public ActionBar setActionBarStyle(String title) {
    ActionBar actionBar = setActionBarStyle();
    actionBar.setTitle(title);
    return actionBar;
}

public ActionBar setActionBarStyle() {
    ActionBar actionBar = getActionBar();
    ShapeDrawable actionBackground = new ShapeDrawable();
    actionBackground.getPaint().setColor(Color.RED);
    actionBackground.setBounds(0, 0, 5, 5);
    actionBar.setBackgroundDrawable(actionBackground);
    actionBar.setDisplayUseLogoEnabled(true);
    actionBar.setDisplayHomeAsUpEnabled(true);

    return actionBar;
}
末骤雨初歇 2025-01-12 18:08:10

“withText”属性适用于大多数平板电脑,但在小型设备上获取图标和文本的一种简单方法是将图标旁边的文本添加为​​一个图像(PNG 文件)。
这样,文本和图标都将被视为一个图标,并且整个内容都会显示。

您可以通过使用 withText 属性来使用平板电脑的原始图标。

  • 您必须在 res 目录中创建一个名为“menu-w600dp”的额外菜单文件夹。

  • 此文件夹中的 optionmenu.xml 仅适用于大于 600dp 的屏幕宽度
    (将毫无问题地显示图标和文本)。

The "withText" property works with most tablets, but an easy way to get icons and text on smaller devices is to add the text next to the icon as one image (PNG file).
That way, both the text and icon will be seen as one icon and the whole thing will display.

You can use the original icon for tablets by using the withText property.

  • You have to create an extra menu folder in the res directory titled "menu-w600dp".

  • The optionmenu.xml in this folder will only apply to screen widths bigger than 600dp
    (the ones that will show the icons and text with no problems).

〆凄凉。 2025-01-12 18:08:10

通过阅读 在 XML 中指定操作

...为了兼容低至 Android 2.1 的版本,showAsAction 属性在 android: 命名空间中不可用。相反,该属性由支持库提供,您必须定义自己的 XML 命名空间并使用该命名空间作为属性前缀。 (自定义 XML 命名空间应基于您的应用程序名称,但它可以是您想要的任何名称,并且只能在您声明它的文件范围内访问。)例如:

 <menu xmlns:android="http://schemas.android.com/apk/res/android"
   xmlns:yourapp="http://schemas.android.com/apk/res-auto" >
 <!-- Search, should appear as action button -->
 <item android:id="@+id/action_search"
       android:icon="@drawable/ic_action_search"
       android:title="@string/action_search"
       yourapp:showAsAction="ifRoom"  />
 ...
 </menu>

如果这些其他内容都不适合您,这个可能。

Fixed this issue by reading "If your app is using the Support Library" section under Specify the Actions in XML.

...for compatibility on versions as low as Android 2.1, the showAsAction attribute is not available from the android: namespace. Instead this attribute is provided by the Support Library and you must define your own XML namespace and use that namespace as the attribute prefix. (A custom XML namespace should be based on your app name, but it can be any name you want and is only accessible within the scope of the file in which you declare it.) For example:

 <menu xmlns:android="http://schemas.android.com/apk/res/android"
   xmlns:yourapp="http://schemas.android.com/apk/res-auto" >
 <!-- Search, should appear as action button -->
 <item android:id="@+id/action_search"
       android:icon="@drawable/ic_action_search"
       android:title="@string/action_search"
       yourapp:showAsAction="ifRoom"  />
 ...
 </menu>

If none of these other things work for you, this may.

冬天的雪花 2025-01-12 18:08:10

我尝试了很多选项,并想出了一个简单的“技巧”,没有任何奇怪的代码行,没有图像。第一个使用自定义 actionLayout 的解决方案根本不适合我,具有 API 级别 10 兼容性。

如果您想在小操作栏上显示文本和图标,则意味着您知道有空间,对吗?因此,您可以使用 2 个菜单项:

  • 第一个仅使用图标(忽略警告,如果您设置标题平板电脑将显示两次)
  • 第二个仅使用文本

如果需要,请选择“ifRoom”文本操作,以便您确实需要空间,文字就会消失。虽然它会占用操作栏上更多的空间,但对我来说是一个很好的妥协。
我最终得到以下代码:(

<item
    android:id="@+id/menu_save"
    android:icon="@drawable/save"
    pelmel:showAsAction="always">
</item>
<item
    android:id="@+id/menu_save_text"
    android:title="@string/profileSave"
    pelmel:showAsAction="ifRoom">
</item>

编辑其中“pelmel”是您的应用程序名称END EDIT

然后您的选择处理程序只需捕获两个ID:

public boolean onOptionsItemSelected(MenuItem item) {
    switch (item.getItemId()) {
    case R.id.menu_save:
    case R.id.menu_save_text:
        // Your code here
        return true;
    }
}

I tried many options and I came up with a simple "trick" without any weird line of code, without images. And first solution with custom actionLayout simply did not work for me with API level 10 compatibility.

If you want to display text AND icon on a small action bar it means you know you have the space, right? So you can use 2 menu items:

  • First with the icon ONLY (ignore warning, if you set a title tablets will show it twice)
  • Second with the text ONLY

And choose the text action to 'ifRoom' if needed so that if you do need space, the text will go away. It WILL take some more space on the action bar though but was a good compromise for me.
I end up with the following code:

<item
    android:id="@+id/menu_save"
    android:icon="@drawable/save"
    pelmel:showAsAction="always">
</item>
<item
    android:id="@+id/menu_save_text"
    android:title="@string/profileSave"
    pelmel:showAsAction="ifRoom">
</item>

(EDIT Where "pelmel" is your app name END EDIT)

And then your selection handler just has to catch both IDs :

public boolean onOptionsItemSelected(MenuItem item) {
    switch (item.getItemId()) {
    case R.id.menu_save:
    case R.id.menu_save_text:
        // Your code here
        return true;
    }
}
零度℉ 2025-01-12 18:08:10

这是另一个选项,大致基于 dgmltn。优点:

  • 更多控制 - 例如,我在布局中交换了文本和图像。
  • 更易于使用 - 只需要在您的活动/片段中添加两行。
  • 仅需要两个额外文件。
  • 可能稍微正确一些,但在我看来,它仍然有点像黑客。

我假设您在此示例中使用 ActionBarSherlock。首先,创建您想要的视图布局。这个是基于 ActionBarSherlock 的。我所做的所有更改就是交换图像/视图,将共享边距/填充减少到 0,以便它们更接近,并解决所有 ABS 样式。

<com.example.views.ActionMenuTextItemView xmlns:android="http://schemas.android.com/apk/res/android"
    style="@android:style/Widget.Holo.ActionButton"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_gravity="center"
    android:addStatesFromChildren="true"
    android:focusable="true"
    android:gravity="center"
    android:clickable="true"
    android:paddingLeft="4dip"
    android:paddingRight="4dip" >

    <com.actionbarsherlock.internal.widget.CapitalizingButton
        android:id="@+id/abs__textButton"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:background="@null"
        android:ellipsize="none"
        android:focusable="false"
        android:minHeight="48dip"
        android:minWidth="48dip"
        android:paddingBottom="4dip"
        android:paddingLeft="4dip"
        android:paddingRight="0dip"
        android:paddingTop="4dip"
        android:singleLine="true"
        android:textAppearance="@android:style/TextAppearance.Holo.Widget.ActionBar.Menu"
        android:textColor="#fff3f3f3" />

    <ImageButton
        android:id="@+id/abs__imageButton"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:layout_marginBottom="4dip"
        android:layout_marginLeft="0dip"
        android:layout_marginRight="4dip"
        android:layout_marginTop="4dip"
        android:adjustViewBounds="true"
        android:background="@null"
        android:focusable="false"
        android:scaleType="fitCenter"
        android:visibility="gone" />

</com.example.views.ActionMenuTextItemView>

然后创建相应的View类。如果您担心使用内部的东西,您可能需要复制CapitalizingButton。哦,我也从未修复过最小宽度的问题。但不认为这真的很重要。

package com.example.views;

import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.accessibility.AccessibilityEvent;
import android.widget.ImageButton;
import android.widget.LinearLayout;

import com.actionbarsherlock.R;
import com.actionbarsherlock.app.SherlockActivity;
import com.actionbarsherlock.app.SherlockFragment;
import com.actionbarsherlock.app.SherlockFragmentActivity;
import com.actionbarsherlock.app.SherlockListActivity;
import com.actionbarsherlock.app.SherlockListFragment;
import com.actionbarsherlock.internal.widget.CapitalizingButton;
import com.actionbarsherlock.view.MenuItem;

@SuppressLint({ "NewApi" })
public class ActionMenuTextItemView extends LinearLayout implements OnClickListener
{
    private ImageButton mImageButton;
    private CapitalizingButton mTextButton;
    private Object mTarget;
    private MenuItem mItem;

    // Set up all the data. Object must be a sherlock activity or fragment with an onMenuItemSelected().
    public void initialise(MenuItem item, Object target)
    {
        mItem = item;
        mTarget = target;
        setIcon(mItem.getIcon());
        setTitle(mItem.getTitle());
    }

    public ActionMenuTextItemView(Context context, AttributeSet attrs)
    {
        super(context, attrs);
    }
    public ActionMenuTextItemView(Context context, AttributeSet attrs, int defStyle)
    {
        super(context, attrs, defStyle);
    }

    @Override
    public void onFinishInflate()
    {
        super.onFinishInflate();
        mImageButton = (ImageButton) findViewById(R.id.abs__imageButton);
        mTextButton = (CapitalizingButton) findViewById(R.id.abs__textButton);
        mImageButton.setOnClickListener(this);
        mTextButton.setOnClickListener(this);
        setOnClickListener(this);
    }

    @Override
    public void setEnabled(boolean enabled)
    {
        super.setEnabled(enabled);
        mImageButton.setEnabled(enabled);
        mTextButton.setEnabled(enabled);
    }

    public void setIcon(Drawable icon)
    {
        mImageButton.setImageDrawable(icon);
        if (icon != null)
            mImageButton.setVisibility(VISIBLE);
        else
            mImageButton.setVisibility(GONE);
    }

    public void setTitle(CharSequence title)
    {
        mTextButton.setTextCompat(title);
        setContentDescription(title);
    }

    @Override
    public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event)
    {
        onPopulateAccessibilityEvent(event);
        return true;
    }

    @Override
    public void onPopulateAccessibilityEvent(AccessibilityEvent event)
    {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH)
            super.onPopulateAccessibilityEvent(event);
        final CharSequence cdesc = getContentDescription();
        if (!TextUtils.isEmpty(cdesc))
            event.getText().add(cdesc);
    }

    @Override
    public boolean dispatchHoverEvent(MotionEvent event)
    {
        // Don't allow children to hover; we want this to be treated as a single component.
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH)
            return onHoverEvent(event);
        return false;
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
    {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);

        int minWidth = 0;

        final int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        final int specSize = MeasureSpec.getSize(widthMeasureSpec);
        final int oldMeasuredWidth = getMeasuredWidth();
        final int targetWidth = widthMode == MeasureSpec.AT_MOST ? Math.min(specSize, minWidth) : minWidth;

        if (widthMode != MeasureSpec.EXACTLY && minWidth > 0 && oldMeasuredWidth < targetWidth)
        {
            // Remeasure at exactly the minimum width.
            super.onMeasure(MeasureSpec.makeMeasureSpec(targetWidth, MeasureSpec.EXACTLY), heightMeasureSpec);
        }
    }
    @Override
    public void onClick(View v)
    {
        if (mTarget == null)
            return;
        else if (mTarget instanceof SherlockActivity)
            ((SherlockActivity)mTarget).onOptionsItemSelected(mItem);
        else if (mTarget instanceof SherlockFragmentActivity)
            ((SherlockFragmentActivity)mTarget).onOptionsItemSelected(mItem);
        else if (mTarget instanceof SherlockListActivity)
            ((SherlockListActivity)mTarget).onOptionsItemSelected(mItem);
        else if (mTarget instanceof SherlockListFragment)
            ((SherlockListFragment)mTarget).onOptionsItemSelected(mItem);
        else if (mTarget instanceof SherlockFragment)
            ((SherlockFragment)mTarget).onOptionsItemSelected(mItem);
        else
            throw new IllegalArgumentException("Target must be a sherlock activity or fragment.");
    }

}

好的,现在您可以使用它了。在您想要有文本的菜单项中,您可以执行与 dgmltn 所说相同的操作:

<item
    android:id="@+id/menu_foo"
    android:icon="@drawable/..."
    android:showAsAction="always|withText" // Doesn't do anything really.
    android:title="Sell"
    android:titleCondensed="Sell"
    android:actionLayout="@layout/view_action_menu_text_item"/> // Or whatever you called it.

最后,只需将此代码添加到您的活动/片段中:

@Override
public boolean onCreateOptionsMenu(Menu menu)
{
    super.onCreateOptionsMenu(menu);
    getSupportMenuInflater().inflate(R.menu.activity_main, menu);

    // The magic lines.
    MenuItem it = menu.findItem(R.id.menu_foo);
    ((ActionMenuTextItemView)it.getActionView()).initialise(it, this);

就是这样!

Here's another option, based roughly on dgmltn's. The advantages:

  • More control - e.g. I've swapped the text and image over in my layout.
  • Easier to use - only requires two extra lines in your activities/fragments.
  • Only requires two extra files.
  • Possibly slightly more correct, but it's still a bit of a hack IMO.

I've assumed you're using ActionBarSherlock in this example. First, create the view layout you want. This one is based on ActionBarSherlock's. All I changed was swapping the image/view over, reducing the shared margin/padding to 0 so they are closer, and resolving all the ABS styles.

<com.example.views.ActionMenuTextItemView xmlns:android="http://schemas.android.com/apk/res/android"
    style="@android:style/Widget.Holo.ActionButton"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_gravity="center"
    android:addStatesFromChildren="true"
    android:focusable="true"
    android:gravity="center"
    android:clickable="true"
    android:paddingLeft="4dip"
    android:paddingRight="4dip" >

    <com.actionbarsherlock.internal.widget.CapitalizingButton
        android:id="@+id/abs__textButton"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:background="@null"
        android:ellipsize="none"
        android:focusable="false"
        android:minHeight="48dip"
        android:minWidth="48dip"
        android:paddingBottom="4dip"
        android:paddingLeft="4dip"
        android:paddingRight="0dip"
        android:paddingTop="4dip"
        android:singleLine="true"
        android:textAppearance="@android:style/TextAppearance.Holo.Widget.ActionBar.Menu"
        android:textColor="#fff3f3f3" />

    <ImageButton
        android:id="@+id/abs__imageButton"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:layout_marginBottom="4dip"
        android:layout_marginLeft="0dip"
        android:layout_marginRight="4dip"
        android:layout_marginTop="4dip"
        android:adjustViewBounds="true"
        android:background="@null"
        android:focusable="false"
        android:scaleType="fitCenter"
        android:visibility="gone" />

</com.example.views.ActionMenuTextItemView>

Then create the corresponding View class. You may want to copy CapitalizingButton if you are worried about using internal things. Oh, also I never fixed the minimum width stuff. Don't think it really matters though.

package com.example.views;

import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.accessibility.AccessibilityEvent;
import android.widget.ImageButton;
import android.widget.LinearLayout;

import com.actionbarsherlock.R;
import com.actionbarsherlock.app.SherlockActivity;
import com.actionbarsherlock.app.SherlockFragment;
import com.actionbarsherlock.app.SherlockFragmentActivity;
import com.actionbarsherlock.app.SherlockListActivity;
import com.actionbarsherlock.app.SherlockListFragment;
import com.actionbarsherlock.internal.widget.CapitalizingButton;
import com.actionbarsherlock.view.MenuItem;

@SuppressLint({ "NewApi" })
public class ActionMenuTextItemView extends LinearLayout implements OnClickListener
{
    private ImageButton mImageButton;
    private CapitalizingButton mTextButton;
    private Object mTarget;
    private MenuItem mItem;

    // Set up all the data. Object must be a sherlock activity or fragment with an onMenuItemSelected().
    public void initialise(MenuItem item, Object target)
    {
        mItem = item;
        mTarget = target;
        setIcon(mItem.getIcon());
        setTitle(mItem.getTitle());
    }

    public ActionMenuTextItemView(Context context, AttributeSet attrs)
    {
        super(context, attrs);
    }
    public ActionMenuTextItemView(Context context, AttributeSet attrs, int defStyle)
    {
        super(context, attrs, defStyle);
    }

    @Override
    public void onFinishInflate()
    {
        super.onFinishInflate();
        mImageButton = (ImageButton) findViewById(R.id.abs__imageButton);
        mTextButton = (CapitalizingButton) findViewById(R.id.abs__textButton);
        mImageButton.setOnClickListener(this);
        mTextButton.setOnClickListener(this);
        setOnClickListener(this);
    }

    @Override
    public void setEnabled(boolean enabled)
    {
        super.setEnabled(enabled);
        mImageButton.setEnabled(enabled);
        mTextButton.setEnabled(enabled);
    }

    public void setIcon(Drawable icon)
    {
        mImageButton.setImageDrawable(icon);
        if (icon != null)
            mImageButton.setVisibility(VISIBLE);
        else
            mImageButton.setVisibility(GONE);
    }

    public void setTitle(CharSequence title)
    {
        mTextButton.setTextCompat(title);
        setContentDescription(title);
    }

    @Override
    public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event)
    {
        onPopulateAccessibilityEvent(event);
        return true;
    }

    @Override
    public void onPopulateAccessibilityEvent(AccessibilityEvent event)
    {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH)
            super.onPopulateAccessibilityEvent(event);
        final CharSequence cdesc = getContentDescription();
        if (!TextUtils.isEmpty(cdesc))
            event.getText().add(cdesc);
    }

    @Override
    public boolean dispatchHoverEvent(MotionEvent event)
    {
        // Don't allow children to hover; we want this to be treated as a single component.
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH)
            return onHoverEvent(event);
        return false;
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
    {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);

        int minWidth = 0;

        final int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        final int specSize = MeasureSpec.getSize(widthMeasureSpec);
        final int oldMeasuredWidth = getMeasuredWidth();
        final int targetWidth = widthMode == MeasureSpec.AT_MOST ? Math.min(specSize, minWidth) : minWidth;

        if (widthMode != MeasureSpec.EXACTLY && minWidth > 0 && oldMeasuredWidth < targetWidth)
        {
            // Remeasure at exactly the minimum width.
            super.onMeasure(MeasureSpec.makeMeasureSpec(targetWidth, MeasureSpec.EXACTLY), heightMeasureSpec);
        }
    }
    @Override
    public void onClick(View v)
    {
        if (mTarget == null)
            return;
        else if (mTarget instanceof SherlockActivity)
            ((SherlockActivity)mTarget).onOptionsItemSelected(mItem);
        else if (mTarget instanceof SherlockFragmentActivity)
            ((SherlockFragmentActivity)mTarget).onOptionsItemSelected(mItem);
        else if (mTarget instanceof SherlockListActivity)
            ((SherlockListActivity)mTarget).onOptionsItemSelected(mItem);
        else if (mTarget instanceof SherlockListFragment)
            ((SherlockListFragment)mTarget).onOptionsItemSelected(mItem);
        else if (mTarget instanceof SherlockFragment)
            ((SherlockFragment)mTarget).onOptionsItemSelected(mItem);
        else
            throw new IllegalArgumentException("Target must be a sherlock activity or fragment.");
    }

}

Ok now you're ready to use it. In your menu items that you want to have text, you do the same as what dgmltn said:

<item
    android:id="@+id/menu_foo"
    android:icon="@drawable/..."
    android:showAsAction="always|withText" // Doesn't do anything really.
    android:title="Sell"
    android:titleCondensed="Sell"
    android:actionLayout="@layout/view_action_menu_text_item"/> // Or whatever you called it.

And finally, just add this code to your activity/fragment:

@Override
public boolean onCreateOptionsMenu(Menu menu)
{
    super.onCreateOptionsMenu(menu);
    getSupportMenuInflater().inflate(R.menu.activity_main, menu);

    // The magic lines.
    MenuItem it = menu.findItem(R.id.menu_foo);
    ((ActionMenuTextItemView)it.getActionView()).initialise(it, this);

And that's it!

叹梦 2025-01-12 18:08:10
  • 添加到 @dgmltn 答案
  • 对于 Kotlin 用户:
  • 这是您在 Kotlin 代码中访问/设置项目侦听器的方式。
   override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
       super.onCreateOptionsMenu(menu, inflater)
       menu.clear()
       inflater.inflate(R.menu.my_menu, menu)
       val item = menu.findItem(R.id.menu_foo)
    
       item.actionView!!.setOnClickListener {
           Toast.makeText(
                requireContext(), "hello", Toast.LENGTH_SHORT
            ).show()
        }
    }
  • Adding to @dgmltn answer
  • For Kotlin users:
  • This is how you access/set listener on item in your Kotlin code.
   override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
       super.onCreateOptionsMenu(menu, inflater)
       menu.clear()
       inflater.inflate(R.menu.my_menu, menu)
       val item = menu.findItem(R.id.menu_foo)
    
       item.actionView!!.setOnClickListener {
           Toast.makeText(
                requireContext(), "hello", Toast.LENGTH_SHORT
            ).show()
        }
    }
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文