web-dev-qa-db-fra.com

android 4.0, le texte sur la barre d'action ne montre JAMAIS

J'essaie d'utiliser les nouvelles API de Google, en particulier la barre d'action.

Lorsque la version a été définie à l'api 10, si j'ai appuyé sur le bouton de menu, j'ai obtenu de belles options de menu, chacune avec une image et une icône. Lors de l'utilisation de l'API 14, peu importe ce que j'essaie, il place toujours l'icône dans la barre d'action sans texte. J'ai essayé tout ce à quoi je peux penser. Je lui ai donné la propriété "avec texte", changé le texte en un seul caractère (au cas où c'était un problème de pièce), mais rien.

J'ai déjà vu cela fait auparavant, même dans le guide du développeur sur Android.developer, mais je n'arrive pas à trouver de réponse sur la façon de le faire apparaître.

59
BriCo84

Je soupçonne que les développeurs de Android $) n'ont jamais affiché le texte et l'icône d'un élément de menu sur une barre d'action étroite. Mais si vous voulez vraiment le faire, vous pouvez utiliser - Android: actionLayout dans votre fichier menu.xml. Le documentation Android ActionBar a une explication légèrement meilleure.

<?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>

Créez ensuite votre action_button_foo.xml disposition:

<?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" />

et utilisez un sélecteur pour son arrière-plan bg_btn_action_bar.xml, il change donc de couleur lorsque vous appuyez dessus:

<?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>

Vous devez maintenant faire en sorte que votre vue personnalisée gère les événements de clic. Dans votre activité, j'aime le faire, afin de pouvoir gérer le clic dans onOptionsItemSelected avec tous mes autres éléments non personnalisés.

@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);
}
83
dgmltn

C'est certainement la même chose que j'ai observée sur mon Nexus S exécutant 4.0.4. Mon application utilise une barre d'actions avec plusieurs onglets qui sont implémentés sous forme de fragments. Mes différents fragments apportent des ajustements aux options de menu affichées sur la barre d'action pendant que leur onglet est visible.

Cela semble être un bogue dans ICS, car il fonctionne régulièrement comme suit, à la fois sur mon Nexus S et dans l'émulateur (HVGA et WVGA800):

  1. En mode portrait, mon bouton logo/haut apparaît sur la ligne supérieure de la barre d'actions, les onglets apparaissent sur la deuxième ligne et toutes les actions apparaissent uniquement sous forme d'icônes (pas de texte) dans la partie droite de la ligne supérieure.
  2. Mais si lorsque je pivote en mode paysage, la barre d'action se réduit à une seule ligne et les onglets se déplacent vers la barre supérieure en tant que fileur (liste déroulante) à côté de mon bouton haut. Mais notamment, le texte apparaît à côté de mes icônes d'action.

J'ai remarqué quelques autres problèmes avec le spinner à onglets qui m'ont amené à croire que ce petit coin de ICS est un peu brouillon/buggy. Si je dis à l'application de diviser la barre d'action sur des écrans étroits ( en ajoutant Android:uiOptions="splitActionBarWhenNarrow" dans le manifeste, ICS pousse toujours ces éléments vers la barre inférieure, même s'il y a encore beaucoup de place en haut. Et même avec la barre supplémentaire, elle n'affiche toujours pas le texte, juste l'icône.

Sur mon Xoom exécutant 4.0.4, les onglets et les éléments d'action apparaissent toujours comme vous vous attendez à ce qu'ils apparaissent, car il y a beaucoup de place.

Solution: si vous voulez vraiment du texte sur la barre d'action en mode portrait, vous devez abandonner l'icône. Supprimez l'icône de votre élément de menu et le texte apparaîtra. Ce n'est pas exactement ce que nous recherchons.

J'ai publié un rapport de bogue ici: https://code.google.com/p/Android/issues/detail?id=3018 .

10
Steve Liddle

La propriété "withText" fonctionne avec la plupart des tablettes, mais un moyen simple d'obtenir des icônes et du texte sur des appareils plus petits consiste à ajouter le texte à côté de l'icône en une seule image (fichier PNG). De cette façon, le texte et l'icône seront considérés comme une seule icône et le tout s'affichera.

Vous pouvez utiliser l'icône d'origine pour les tablettes à l'aide de la propriété withText.

  • Vous devez créer un dossier de menu supplémentaire dans le répertoire res intitulé "menu-w600dp".

  • L'optionmenu.xml de ce dossier ne s'appliquera qu'aux largeurs d'écran supérieures à 600dp (celles qui afficheront les icônes et le texte sans problème).

3
Lukos

Si vous voulez que votre menu d'options apparaisse dans votre barre d'action avec Honeycomb, j'ai fait ceci:

Dans votre activité, remplacez cette fonction:

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

où R.menu.actionbar_universe définit votre élément de menu comme ceci:

<?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>

Notez le showAsAction = "always | withText" et spécifiez Android: title.

Si vous avez cela et que cela ne fonctionne pas, veuillez copier/coller votre ressource de menu ici.

EDIT: Cela répond à la mauvaise question, mais c'est le texte original.

J'utilise ce morceau de code pour définir le titre de la barre d'action et le peindre en rouge avec le logo de mon entreprise. Cela fonctionne bien dans 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;
}
3
knaak

J'ai essayé de nombreuses options et j'ai trouvé une simple "astuce" sans toute ligne de code bizarre, sans images. Et la première solution avec actionLayout personnalisée ne fonctionnait tout simplement pas pour moi avec la compatibilité API niveau 10.

Si vous souhaitez afficher le texte ET l'icône sur une petite barre d'action, cela signifie que vous savez que vous avez l'espace, non? Vous pouvez donc utiliser 2 éléments de menu:

  • D'abord avec l'icône UNIQUEMENT (ignorer l'avertissement, si vous définissez un titre, les tablettes le montreront deux fois)
  • Deuxième avec le texte UNIQUEMENT

Et choisissez l'action de texte sur 'ifRoom' si nécessaire afin que si vous avez besoin d'espace, le texte disparaisse. Cela prendra plus d'espace sur la barre d'action, mais c'était un bon compromis pour moi. Je me retrouve avec le code suivant:

<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 Où "pelmel" est le nom de votre application END EDIT)

Et puis, votre gestionnaire de sélection n'a plus qu'à intercepter les deux 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;
    }
}
1

Correction de ce problème en lisant la section " Si votre application utilise la bibliothèque de support " sous Spécifiez les actions en XML .

... pour la compatibilité sur des versions aussi basses que Android 2.1, l'attribut showAsAction n'est pas disponible à partir de Android: espace de noms. Au lieu de cela, cet attribut est fourni par la bibliothèque de support et vous devez définir votre propre espace de noms XML et utiliser cet espace de noms comme préfixe d'attribut. (Un espace de noms XML personnalisé doit être basé sur le nom de votre application, mais il peut s'agir de n'importe quel nom et n'est accessible que dans la portée du fichier dans lequel vous le déclarez.) Par exemple:

 <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>

Si aucune de ces autres choses ne fonctionne pour vous, cela peut arriver.

1
ejb

Voici une autre option, basée à peu près sur celle de dgmltn. Les avantages:

  • Plus de contrôle - par ex. J'ai échangé le texte et l'image dans ma mise en page.
  • Plus facile à utiliser - ne nécessite que deux lignes supplémentaires dans vos activités/fragments.
  • Ne nécessite que deux fichiers supplémentaires.
  • Peut-être un peu plus correct, mais c'est toujours un peu un hack IMO.

J'ai supposé que vous utilisez ActionBarSherlock dans cet exemple. Commencez par créer la disposition de vue souhaitée. Celui-ci est basé sur ActionBarSherlock. Tout ce que j'ai changé était de permuter l'image/la vue, de réduire la marge/le remplissage partagés à 0 afin qu'ils soient plus proches et de résoudre tous les styles 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>

Créez ensuite la classe View correspondante. Vous voudrez peut-être copier CapitalizingButton si vous avez peur d'utiliser des choses internes. Oh, je n'ai jamais non plus fixé la largeur minimale. Ne pensez pas que cela compte vraiment.

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 maintenant vous êtes prêt à l'utiliser. Dans vos éléments de menu que vous souhaitez avoir du texte, vous faites la même chose que ce que dgmltn a dit:

<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.

Et enfin, ajoutez simplement ce code à votre activité/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);

Et c'est tout!

0
Timmmm