Android 4.0, текст на панели действий НИКОГДА не отображается

Я пытаюсь использовать новый API от Google, в частности, панель действий.

Когда сборка была установлена ​​​​на API 10, если я нажал кнопку меню, у меня появились красивые пункты меню, каждый с изображением и значком. При использовании API 14, что бы я ни пытался, он всегда помещает значок на панель действий без текста. Я пробовал все, что мог придумать. Я дал ему свойство «с текстом», изменил текст на один символ (на случай, если это была проблема с комнатой), но ничего.

Я видел это раньше, даже в руководстве разработчика на android.developer, но я не могу найти ответ на вопрос, КАК заставить его отображаться.


person BriCo84    schedule 14.02.2012    source источник
comment
не могли бы вы показать свой menu.xml для активности? у меня может быть решение   -  person Patrick    schedule 06.03.2012


Ответы (7)


Я подозреваю, что разработчики 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>

Теперь вам нужно сделать так, чтобы ваше пользовательское представление обрабатывало события кликов. В вашей деятельности мне нравится делать это, чтобы я мог обрабатывать щелчок в 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);
}
person dgmltn    schedule 01.09.2012
comment
Если вы используете ActionBarSherlock, @color/ и @dimen/ будут иметь некоторые параметры, начинающиеся с abs__ . Это значения, которые использует ActionBarSherlock; вы можете использовать их, чтобы ваш собственный макет выглядел правильно. Например, вы хотите использовать @color/abs__holo_blue_light в качестве цвета подсветки. - person Catherine Darrow; 28.04.2013
comment
Этот подход довольно прост, но сложно подобрать правильный стиль. Я нашел атрибуты стиля, которые используются в ABS, поэтому они идентичны собственному стилю. Я помещаю это в этот список на случай, если кто-то еще сочтет это полезным: gist.github.com/marczych/6908324< /а> - person marczych; 10.10.2013
comment
Вы спасли мне жизнь, жаль, что я не могу дать вам 10 голосов. - person Ray; 28.01.2014

Это определенно то же самое, что я наблюдал на своем Nexus S с версией 4.0.4. В моем приложении используется панель действий с несколькими вкладками, реализованными в виде фрагментов. Мои различные фрагменты вносят коррективы в параметры меню, отображаемые на панели действий, когда их вкладка видна.

Похоже, это ошибка в ICS, потому что она последовательно работает следующим образом как на моем Nexus S, так и в эмуляторе (как HVGA, так и WVGA800):

  1. В портретном режиме мой логотип/кнопка вверх отображается в верхней строке панели действий, вкладки отображаются во второй строке, а любые действия отображаются только в виде значков (без текста) в правой части верхней строки.
  2. Но если я поворачиваюсь в альбомную ориентацию, панель действий сворачивается до одной строки, а вкладки перемещаются на верхнюю панель в виде счетчика (раскрывающегося списка) рядом с моей кнопкой вверх. Но примечательно то, что текст появляется рядом с моими значками действий.

Я заметил некоторые другие сбои со счетчиком вкладок, которые заставили меня поверить, что этот маленький уголок ICS немного запутан/глючит. Если я скажу приложению разделить панель действий на узкие дисплеи (добавляя android:uiOptions="splitActionBarWhenNarrow" в манифест, ICS всегда помещает эти элементы на нижнюю панель, даже если вверху еще достаточно места. И даже с дополнительной панелью это по-прежнему не отображает текст, только значок.

На моем Xoom с версией 4.0.4 вкладки и элементы действий всегда отображаются так, как вы ожидаете, потому что места достаточно.

Обходной путь: если вам действительно нужен текст на панели действий в портретном режиме, вам нужно отказаться от значка. Удалите значок из пункта меню, и появится текст. Это не совсем то, что нам нужно.

Я разместил отчет об ошибке здесь: https://code.google.com/p/android/issues/detail?id=30180.

person Steve Liddle    schedule 05.05.2012

Если вы хотите, чтобы ваше меню параметров отображалось на панели действий с помощью 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;
}
person knaak    schedule 14.02.2012
comment
Спасибо, но разве это не задает основной заголовок панели действий? Я хочу, чтобы отображался текст для каждого пункта меню. т. е. у меня есть пункт меню «Настройки» со значком гаечного ключа и пункт меню «Добавить» со значком +. Я хочу, чтобы для каждого элемента отображались и значок, и текст. Вместо этого я получаю изображение гаечного ключа в левом нижнем углу панели действий (в нижней части экрана) и знак + в правом нижнем углу. Нет текста. Если я запускаю с помощью имбирного пряника и нажимаю кнопку меню, я вижу всплывающие окна с текстом и значком... как и должно быть. - person BriCo84; 14.02.2012
comment
Вы правы, я неправильно понял. Я снова отвечу, как у меня отображаются текст и значок на панели действий. - person knaak; 15.02.2012
comment
Да, у меня есть эти наборы, и он все еще не работает. Вот мой xml ‹?xml version=1.0 encoding=utf-8?› ‹menu xmlns:android=schemas.android.com/apk/res/android › ‹item android:id=@+id/menu_add android:title=Добавить клиент android:icon=@android:drawable/ic_menu_add android:showAsAction=always| withText›‹/item›‹item android:id=@+id/menu_settings - person BriCo84; 15.02.2012
comment
android:icon=@android:drawable/ic_menu_manage android:title=@string/menu_settings android:showAsAction=always|withText/› ‹item android:id=@+id/menu_about android:title=Справка/Об android:icon=@ android:drawable/ic_menu_help android:showAsAction=always|withText›‹/item› ‹/menu› - person BriCo84; 15.02.2012
comment
Обратите внимание, это для смартфона под управлением Android 4.03. Не планшет. Уверен, что на планшете он будет работать, но на телефоне почему-то не работает. - person BriCo84; 15.02.2012
comment
Возможно, вы правы. Мой телефон все еще 2.3.3. Я заметил, что в объявлении схемы у вас есть лишняя точка с запятой. Вряд ли это проблема.. но кто знает. В противном случае я не вижу причин, почему это не сработает. - person knaak; 15.02.2012
comment
Да, проблема была не в этом... это сводит меня с ума. И, кажется, я единственный, с кем это происходит, поскольку я не могу найти никаких других сообщений об этом. - person BriCo84; 15.02.2012
comment
@user1209699, вы, конечно, не единственный, также проверьте - code.google.com/p/android/issues/ - person wired00; 03.12.2012

Свойство withText работает с большинством планшетов, но простой способ получить значки и текст на устройствах меньшего размера — добавить текст рядом со значком в виде одного изображения (файл PNG). Таким образом, и текст, и значок будут отображаться как один значок, и все это будет отображаться.

Вы можете использовать исходный значок для планшетов, используя свойство withText.

  • Вы должны создать дополнительную папку меню в каталоге res под названием «menu-w600dp».

  • Файл optionmenu.xml в этой папке будет применяться только к экранам с шириной более 600 dp (те, которые без проблем будут отображать значки и текст).

person Lukos    schedule 09.07.2013
comment
К сожалению, это не решение, если вы внедряете локализацию - person jaseelder; 25.07.2013
comment
@jaseelder Вам просто нужно реализовать локализацию так же, как и раньше, но теперь с изображением вместо текста. Я предполагаю, что эта проблема, вероятно, уже исправлена ​​в любом случае. - person Lukos; 07.11.2014

Чтобы устранить эту проблему, прочитайте раздел «Если ваше приложение использует библиотеку поддержки» в разделе Укажите действия в 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>

Если ни одна из этих других вещей не работает для вас, это может быть.

person ejb    schedule 16.04.2014

Я перепробовал множество вариантов и нашел простой «трюк» без какой-либо странной строчки кода, без изображений. И первое решение с пользовательским 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" — название вашего приложения ЗАВЕРШИТЬ ИЗМЕНЕНИЕ)

И тогда ваш обработчик выбора просто должен поймать оба идентификатора:

public boolean onOptionsItemSelected(MenuItem item) {
    switch (item.getItemId()) {
    case R.id.menu_save:
    case R.id.menu_save_text:
        // Your code here
        return true;
    }
}
person Christophe Fondacci    schedule 29.06.2014
comment
Я попробовал этот подход, но линия-разделитель, которую ActionBar размещает между элементами, делает их непересекающимися. Спасибо за предложение. - person N8allan; 26.08.2014
comment
Я отредактировал свой ответ, чтобы добавить эту точность, спасибо! - person Christophe Fondacci; 11.02.2015

Вот еще один вариант, примерно основанный на dgmltn. Преимущества:

  • Больше контроля - например. Я поменял местами текст и изображение в своем макете.
  • Проще в использовании - требуется только две дополнительные строки в ваших действиях/фрагментах.
  • Требуется только два дополнительных файла.
  • Возможно, немного более правильно, но это все еще немного взлома IMO.

Я предположил, что в этом примере вы используете 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);

И это все!

person Timmmm    schedule 24.10.2012