Android 4.0, текст на панели действий НИКОГДА не отображается
Я пытаюсь использовать новый api из google, в частности панель действий.
Когда сборка была установлена на api 10, если бы я нажал кнопку меню, у меня появились приятные варианты меню, каждый из которых имел изображение и значок. При использовании api 14, независимо от того, что я пытаюсь, он всегда помещает значок в панель действий без текста. Я пробовал все, что мог придумать. Я дал ему свойство "с текстом", изменил текст на один символ (в случае, если это был номер), но ничего.
Я видел это раньше, даже в руководстве разработчика в android.developer, но я не могу найти ответ о том, как заставить его отображаться.
Ответы
Ответ 1
Я подозреваю, что разработчики 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);
}
Ответ 2
Это, безусловно, то же самое, что я наблюдал на моем Nexus S, работающем 4.0.4. В моем приложении используется панель действий с несколькими вкладками, которые реализованы как фрагменты. Мои различные фрагменты корректируют параметры меню, отображаемые на панели действий, когда их вкладка видна.
Это похоже на ошибку в ICS, потому что она выполняется последовательно следующим образом, как на моем Nexus S, так и в эмуляторе (как HVGA, так и WVGA800):
- В портретном режиме в верхней строке панели действий отображается моя кнопка "вверх/вниз", во второй строке отображаются вкладки, а любые действия отображаются только в виде значков (без текста) в правой части верхней строки.
- Но если при повороте в ландшафт, панель действий сворачивается в одну строку, а вкладки перемещаются вверх по верхней панели в виде прядильного (раскрывающегося списка) рядом с моей кнопкой вверх. Но, в частности, текст появляется рядом с моими значками действий.
Я заметил некоторые другие сбои со счетчиком, который заставлял меня поверить, что этот маленький угол ICS немного грязный/глючный. Если я скажу приложению разбить панель действий на узких дисплеях (добавив android:uiOptions="splitActionBarWhenNarrow"
в манифест, ICS всегда подталкивает эти элементы к нижней панели, хотя в верхней части еще много места. И даже с дополнительным баром, он по-прежнему не отображает текст, просто значок.
В моем Xoom, запущенном 4.0.4, вкладки и элементы действия всегда появляются так, как вы ожидали, что они появятся, потому что там много места.
Обходной путь:, если вы действительно хотите текст на панели действий в портретном режиме, вам нужно отказаться от значка. Удалите значок из вашего пункта меню, и появится текст. Это не совсем то, что нам нужно.
Я разместил здесь отчет об ошибке: https://code.google.com/p/android/issues/detail?id=30180.
Ответ 3
Если вы хотите, чтобы ваше меню параметров отображалось в панели действий с помощью 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.
Если у вас есть это и его не работает, скопируйте | вставьте свой ресурс меню здесь.
EDIT: Это отвечает на неправильный вопрос, но это оригинальный текст.
Я использую этот бит кода для установки заголовка панели действий и крашу его красным цветом с логотипом своих компаний. Он хорошо работает в версии 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;
}
Ответ 4
Свойство "withText" работает с большинством планшетов, , но простой способ получить значки и текст на более мелких устройствах - это добавить текст рядом со значком в виде одного изображения (PNG файл).
Таким образом, и текст, и значок будут отображаться как один значок, и все это будет отображаться.
Вы можете использовать оригинальный значок для планшетов, используя свойство withText.
-
Вам нужно создать дополнительную папку меню в каталоге res под названием "menu-w600dp".
-
Файл optionsmenu.xml в этой папке применим только к ширине экрана, превышающей 600dp
(те, которые без проблем отображают значки и текст).
Ответ 5
Исправлена ошибка: "Если ваше приложение использует раздел" Библиотека поддержки "в разделе Укажите действия в 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>
Если ни одна из этих вещей не работает для вас, это может быть.
Ответ 6
Я пробовал много вариантов, и я придумал простой "трюк" без любой странной строки кода, без изображений. И первое решение с пользовательским 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>
(EDIT Где "pelmel" - ваше имя приложения END EDIT)
И тогда ваш обработчик выбора просто должен поймать оба идентификатора:
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.menu_save:
case R.id.menu_save_text:
// Your code here
return true;
}
}
Ответ 7
Здесь другой вариант, основанный примерно на 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);
И что это!