Android 4.0, 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 construction a été définie sur api 10, si j’ai appuyé sur le bouton de menu, j’ai obtenu de jolies options de menu, chacune avec une image et une icône. Lorsque vous utilisez 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 que je peux penser. Je lui ai donné la propriété “with text”, j’ai changé le texte en un seul caractère (au cas où ce serait un problème de salle), mais rien.

Je l’ai déjà vu, même dans le guide du développeur sur android.developer, mais je n’arrive pas à trouver une réponse à la question de savoir comment l’obtenir.

Je pense que les développeurs Android ont délibérément décidé de ne jamais afficher le texte et l’icône d’un seul é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. La documentation Android ActionBar a une explication légèrement meilleure.

    

Ensuite, créez votre disposition action_button_foo.xml :

   

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

      

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 pour que je puisse 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); } 

C’est certainement la même chose que j’ai observée sur mon Nexus S sous 4.0.4. Mon application utilise une barre d’action avec plusieurs tabs implémentés sous forme de fragments. Mes divers fragments apportent des ajustements aux options de menu affichées dans la barre d’action pendant que leur onglet est visible.

Cela semble être un bogue dans ICS, car il fonctionne de la manière suivante, à 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’action, des tabs apparaissent sur la deuxième ligne et les actions apparaissent uniquement sous forme d’icons (pas de texte) dans la partie droite de la ligne supérieure.
  2. Mais si je passe en mode paysage, la barre d’action se réduit à une seule ligne et les tabs se déplacent vers la barre supérieure sous forme de sélecteur (liste déroulante) en regard du bouton Haut. Mais notamment, le texte apparaît à côté de mes icons d’action.

J’ai remarqué d’autres problèmes avec l’onglet spinner qui me porte à croire que ce petit coin d’ICS est un peu désordonné. Si je demande à 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 dans la barre inférieure, même s’il y a encore beaucoup d’espace en haut. avec la barre supplémentaire, il n’affiche toujours pas le texte, juste l’icône.

Sur mon Xoom exécutant la version 4.0.4, les tabs et les éléments d’action apparaissent toujours comme vous vous en doutez, car vous disposez de beaucoup d’espace.

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 après.

J’ai posté un rapport de bogue ici: https://code.google.com/p/android/issues/detail?id=30180 .

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:

     

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 bit 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 en 3.0.

 public ActionBar setActionBarStyle(Ssortingng 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; } 

La propriété “withText” fonctionne avec la plupart des tablettes, mais un moyen simple d’obtenir des icons et du texte sur des appareils plus petits consiste à append le texte à côté de l’icône sous la forme d’une image (fichier PNG). De cette façon, le texte et l’icône seront considérés comme une seule icône et l’ensemble s’affichera.

Vous pouvez utiliser l’icône d’origine pour les tablettes en utilisant la propriété withText.

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

  • Le fichier optionmenu.xml de ce dossier ne s’appliquera qu’aux largeurs d’écran supérieures à 600dp (celles qui afficheront les icons et le texte sans problème).

Ce problème a été résolu en lisant la section ” Si votre application utilise la bibliothèque de support ” sous Spécifier les actions en XML .

… pour des versions compatibles avec Android 2.1, l’atsortingbut showAsAction n’est pas disponible à partir de l’espace de noms android: :. Au lieu de cela, cet atsortingbut 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’atsortingbut. (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 scope du fichier dans lequel vous le déclarez.) Par exemple:

     ...  

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

J’ai essayé de nombreuses options et j’ai proposé un simple “truc” sans ligne de code étrange, sans images. Et la première solution avec actionLayout personnalisée ne fonctionnait tout simplement pas avec la compatibilité API niveau 10.

Si vous voulez 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 SEULEMENT (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 le texte disparaisse si vous avez besoin d’espace. Cela prendra encore plus de place sur la barre d’action mais c’est un bon compromis pour moi. Je me retrouve avec le code suivant:

     

( EDIT Où “pelmel” est le nom de votre application END EDIT )

Et alors votre gestionnaire de sélection n’a plus qu’à attraper les deux identifiants:

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

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

  • Plus de contrôle – par exemple, j’ai échangé le texte et l’image dans ma mise en page.
  • Plus facile à utiliser – nécessite seulement deux lignes supplémentaires dans vos activités / fragments.
  • Ne nécessite que deux fichiers supplémentaires.
  • Peut-être légèrement plus correct, mais c’est toujours un peu un bidouillage IMO.

Je suppose que vous utilisez ActionBarSherlock dans cet exemple. Tout d’abord, créez la disposition de vue souhaitée. Celui-ci est basé sur ActionBarSherlock. Tout ce que j’ai changé, c’est de changer l’image / la vue, de réduire la marge / le remplissage partagé à 0 pour qu’ils soient plus proches et de résoudre tous les styles ABS.

     

Ensuite, créez la classe View correspondante. Vous souhaiterez peut-être copier CapitalizingButton si vous craignez d’utiliser des éléments internes. Oh, aussi je n’ai jamais réparé la largeur minimum. 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.AtsortingbuteSet; 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, AtsortingbuteSet attrs) { super(context, attrs); } public ActionMenuTextItemView(Context context, AtsortingbuteSet 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 voulez avoir du texte, vous faites la même chose que ce que dit dgmltn:

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