web-dev-qa-db-fra.com

Icône de nombre de notifications de la barre d’action (badge) comme Google

Existe-t-il un badge ou une méthode standard Android permettant d'afficher l'icône de notification de la barre d'action avec un nombre similaire à celui des exemples Google?

count 3 on picture

Si non, alors quel est le meilleur moyen de le faire?
Je suis nouveau sur Android, aidez-moi s'il vous plaît.

142
AndrewS

Je ne sais pas si c'est la meilleure solution ou non, mais c'est ce dont j'ai besoin.

S'il vous plaît dites-moi si vous savez ce qui doit être changé pour une meilleure performance ou qualité. Dans mon cas, j'ai un bouton.

Élément personnalisé dans mon menu - main.xml

<item
    Android:id="@+id/badge"
    Android:actionLayout="@layout/feed_update_count"
    Android:icon="@drawable/shape_notification"
    Android:showAsAction="always">
</item>

Forme personnalisée pouvant être dessinée (carré d’arrière-plan) - shape_notification.xml

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:Android="http://schemas.Android.com/apk/res/Android"
   Android:shape="rectangle">
    <stroke Android:color="#22000000" Android:width="2dp"/>
    <corners Android:radius="5dp" />
    <solid Android:color="#CC0001"/>
</shape>

Mise en page pour ma vue - feed_update_count.xml

<?xml version="1.0" encoding="utf-8"?>
<Button xmlns:Android="http://schemas.Android.com/apk/res/Android"
     Android:id="@+id/notif_count"
     Android:layout_width="wrap_content"
     Android:layout_height="wrap_content"
     Android:minWidth="32dp"
     Android:minHeight="32dp"
     Android:background="@drawable/shape_notification"
     Android:text="0"
     Android:textSize="16sp"
     Android:textColor="@Android:color/white"
     Android:gravity="center"
     Android:padding="2dp"
     Android:singleLine="true">    
</Button>

MainActivity - Définition et mise à jour de ma vue

static Button notifCount;
static int mNotifCount = 0;    

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    MenuInflater inflater = getSupportMenuInflater();
    inflater.inflate(R.menu.main, menu);

    View count = menu.findItem(R.id.badge).getActionView();
    notifCount = (Button) count.findViewById(R.id.notif_count);
    notifCount.setText(String.valueOf(mNotifCount));
    return super.onCreateOptionsMenu(menu);
}

private void setNotifCount(int count){
    mNotifCount = count;
    invalidateOptionsMenu();
}
222
AndrewS

Éditer Depuis la version 26 de la bibliothèque de support (ou androidx), vous n'avez plus besoin d'implémenter un OnLongClickListener personnalisé pour afficher l'info-bulle. Appelez simplement ceci:

TooltipCompat.setTooltipText(menu_hotlist, getString(R.string.hint_show_hot_message));

Je partagerai simplement mon code au cas où quelqu'un voudrait quelque chose comme ceci: enter image description here

  • layout/menu/menu_actionbar.xml

    <?xml version="1.0" encoding="utf-8"?>
    
    <menu xmlns:Android="http://schemas.Android.com/apk/res/Android">
        ...
        <item Android:id="@+id/menu_hotlist"
            Android:actionLayout="@layout/action_bar_notifitcation_icon"
            Android:showAsAction="always"
            Android:icon="@drawable/ic_bell"
            Android:title="@string/hotlist" />
        ...
    </menu>
    
  • layout/action_bar_notifitcation_icon.xml

    Remarque style et Android: propriétés cliquables . ceux-ci font la mise en page la taille d'un bouton et rendent l'arrière-plan gris lorsque vous le touchez.

    <?xml version="1.0" encoding="utf-8"?>
    <RelativeLayout xmlns:Android="http://schemas.Android.com/apk/res/Android"
        Android:layout_width="wrap_content"
        Android:layout_height="fill_parent"
        Android:orientation="vertical"
        Android:gravity="center"
        Android:layout_gravity="center"
        Android:clickable="true"
        style="@Android:style/Widget.ActionButton">
    
        <ImageView
            Android:id="@+id/hotlist_bell"
            Android:src="@drawable/ic_bell"
            Android:layout_width="wrap_content"
            Android:layout_height="wrap_content"
            Android:gravity="center"
            Android:layout_margin="0dp"
            Android:contentDescription="bell"
            />
    
        <TextView xmlns:Android="http://schemas.Android.com/apk/res/Android"
            Android:id="@+id/hotlist_hot"
            Android:layout_width="wrap_content"
            Android:minWidth="17sp"
            Android:textSize="12sp"
            Android:textColor="#ffffffff"
            Android:layout_height="wrap_content"
            Android:gravity="center"
            Android:text="@null"
            Android:layout_alignTop="@id/hotlist_bell"
            Android:layout_alignRight="@id/hotlist_bell"
            Android:layout_marginRight="0dp"
            Android:layout_marginTop="3dp"
            Android:paddingBottom="1dp"
            Android:paddingRight="4dp"
            Android:paddingLeft="4dp"
            Android:background="@drawable/rounded_square"/>
    </RelativeLayout>
    
  • drawable-xhdpi/ic_bell.png

    Une image de 64 x 64 pixels avec des rembourrages de 10 pixels de large de tous les côtés. Vous êtes censé avoir un remplissage de 8 pixels de large, mais je trouve que la plupart des éléments par défaut sont légèrement plus petits que cela. Bien sûr, vous voudrez utiliser différentes tailles pour différentes densités.

  • drawable/rounded_square.xml

    Ici, # ff222222 (couleur # 222222 avec alpha #ff (entièrement visible)) est la couleur d’arrière-plan de ma barre d’action.

    <?xml version="1.0" encoding="utf-8"?>
    
    <shape
        xmlns:Android="http://schemas.Android.com/apk/res/Android"
        Android:shape="rectangle">
        <corners Android:radius="2dp" />
        <solid Android:color="#ffff0000" />
        <stroke Android:color="#ff222222" Android:width="2dp"/>
    </shape>
    
  • com/ubergeek42/WeechatAndroid/WeechatActivity.Java

    Ici, nous le rendons cliquable et modifiable! J'ai créé un écouteur abstrait qui fournit la création de Toast sur onLongClick, le code provient de les sources de ActionBarSherlock .

    private int hot_number = 0;
    private TextView ui_hot = null;
    
    @Override public boolean onCreateOptionsMenu(final Menu menu) {
        MenuInflater menuInflater = getSupportMenuInflater();
        menuInflater.inflate(R.menu.menu_actionbar, menu);
        final View menu_hotlist = menu.findItem(R.id.menu_hotlist).getActionView();
        ui_hot = (TextView) menu_hotlist.findViewById(R.id.hotlist_hot);
        updateHotCount(hot_number);
        new MyMenuItemStuffListener(menu_hotlist, "Show hot message") {
            @Override
            public void onClick(View v) {
                onHotlistSelected();
            }
        };
        return super.onCreateOptionsMenu(menu);
    }
    
    // call the updating code on the main thread,
    // so we can call this asynchronously
    public void updateHotCount(final int new_hot_number) {
        hot_number = new_hot_number;
        if (ui_hot == null) return;
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                if (new_hot_number == 0)
                    ui_hot.setVisibility(View.INVISIBLE);
                else {
                    ui_hot.setVisibility(View.VISIBLE);
                    ui_hot.setText(Integer.toString(new_hot_number));
                }
            }
        });
    }
    
    static abstract class MyMenuItemStuffListener implements View.OnClickListener, View.OnLongClickListener {
        private String hint;
        private View view;
    
        MyMenuItemStuffListener(View view, String hint) {
            this.view = view;
            this.hint = hint;
            view.setOnClickListener(this);
            view.setOnLongClickListener(this);
        }
    
        @Override abstract public void onClick(View v);
    
        @Override public boolean onLongClick(View v) {
            final int[] screenPos = new int[2];
            final Rect displayFrame = new Rect();
            view.getLocationOnScreen(screenPos);
            view.getWindowVisibleDisplayFrame(displayFrame);
            final Context context = view.getContext();
            final int width = view.getWidth();
            final int height = view.getHeight();
            final int midy = screenPos[1] + height / 2;
            final int screenWidth = context.getResources().getDisplayMetrics().widthPixels;
            Toast cheatSheet = Toast.makeText(context, hint, Toast.LENGTH_SHORT);
            if (midy < displayFrame.height()) {
                cheatSheet.setGravity(Gravity.TOP | Gravity.RIGHT,
                        screenWidth - screenPos[0] - width / 2, height);
            } else {
                cheatSheet.setGravity(Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL, 0, height);
            }
            cheatSheet.show();
            return true;
        }
    }
    
127
squirrel

Juste pour ajouter. Si quelqu'un veut implémenter une bulle de cercle rempli, voici le code (nommez-le bage_circle.xml):

<shape xmlns:Android="http://schemas.Android.com/apk/res/Android"
    Android:shape="ring"
    Android:useLevel="false"
    Android:thickness="9dp"
    Android:innerRadius="0dp"
    >

    <solid
        Android:color="#F00"
        />
    <stroke
        Android:width="1dip"
        Android:color="#FFF" />

    <padding
        Android:top="2dp"
        Android:bottom="2dp"/>

</shape>

Vous devrez peut-être ajuster l'épaisseur en fonction de vos besoins.

enter image description here

EDIT: Voici la disposition du bouton (nommez-le badge_layout.xml):

<RelativeLayout xmlns:Android="http://schemas.Android.com/apk/res/Android"
    Android:layout_width="wrap_content"
    Android:layout_height="wrap_content">

    <com.joanzapata.iconify.widget.IconButton
        Android:layout_width="44dp"
        Android:layout_height="44dp"
        Android:textSize="24sp"
        Android:textColor="@color/white"
        Android:background="@drawable/action_bar_icon_bg"
        Android:id="@+id/badge_icon_button"/>

    <TextView
        Android:id="@+id/badge_textView"
        Android:layout_width="wrap_content"
        Android:layout_height="wrap_content"
        Android:layout_alignTop="@id/badge_icon_button"
        Android:layout_alignRight="@id/badge_icon_button"
        Android:layout_alignEnd="@id/badge_icon_button"
        Android:text="10"
        Android:paddingEnd="8dp"
        Android:paddingRight="8dp"
        Android:paddingLeft="8dp"
        Android:gravity="center"
        Android:textColor="#FFF"
        Android:textSize="11sp"
        Android:background="@drawable/badge_circle"/>
</RelativeLayout>

Dans le menu créer un article:

<item
        Android:id="@+id/menu_messages"
        Android:showAsAction="always"
        Android:actionLayout="@layout/badge_layout"/>

Dans onCreateOptionsMenu obtenez une référence à l'élément de menu:

    itemMessages = menu.findItem(R.id.menu_messages);

    badgeLayout = (RelativeLayout) itemMessages.getActionView();
    itemMessagesBadgeTextView = (TextView) badgeLayout.findViewById(R.id.badge_textView);
    itemMessagesBadgeTextView.setVisibility(View.GONE); // initially hidden

    iconButtonMessages = (IconButton) badgeLayout.findViewById(R.id.badge_icon_button);
    iconButtonMessages.setText("{fa-envelope}");
    iconButtonMessages.setTextColor(getResources().getColor(R.color.action_bar_icon_color_disabled));

    iconButtonMessages.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            if (HJSession.getSession().getSessionId() != null) {

                Intent intent = new Intent(getThis(), HJActivityMessagesContexts.class);
                startActivityForResult(intent, HJRequestCodes.kHJRequestCodeActivityMessages.ordinal());
            } else {
                showLoginActivity();
            }
        }
    });

Après avoir reçu une notification pour les messages, définissez le nombre:

itemMessagesBadgeTextView.setText("" + count);
itemMessagesBadgeTextView.setVisibility(View.VISIBLE);
iconButtonMessages.setTextColor(getResources().getColor(R.color.white));

Ce code utilise Iconify-fontawesome .

compile 'com.joanzapata.iconify:Android-iconify-fontawesome:2.1.+'
61
Abdullah Umer

Je n'aime pas les solutions basées sur ActionView, mon idée est la suivante:

  1. créer une mise en page avec TextView, qui TextView sera rempli par l'application
  2. lorsque vous devez dessiner un MenuItem:

    2.1. gonfler la mise en page

    2.2. appelez measure() & layout() (sinon view sera 0px x 0px, il est trop petit pour la plupart des cas d'utilisation)

    2.3. définir le texte de TextView

    2.4. faire "capture d'écran" de la vue

    2.6 définir l'icône de MenuItem en fonction du bitmap créé sous 2.4

  3. profit!

alors, le résultat devrait être quelque chose comme enter image description here

  1. créer une mise en page, voici un exemple simple
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:Android="http://schemas.Android.com/apk/res/Android"
    Android:id="@+id/counterPanel"
    Android:layout_width="32dp"
    Android:layout_height="32dp"
    Android:background="@drawable/ic_menu_gallery">
    <RelativeLayout
        Android:id="@+id/counterValuePanel"
        Android:layout_width="wrap_content"
        Android:layout_height="wrap_content" >

        <ImageView
            Android:id="@+id/counterBackground"
            Android:layout_width="wrap_content"
            Android:layout_height="wrap_content"
            Android:background="@drawable/unread_background" />

        <TextView
            Android:id="@+id/count"
            Android:layout_width="wrap_content"
            Android:layout_height="wrap_content"
            Android:text="1"
            Android:textSize="8sp"
            Android:layout_centerInParent="true"
            Android:textColor="#FFFFFF" />
    </RelativeLayout>
</FrameLayout>

@drawable/unread_background est-ce que l'arrière-plan vert de TextView, @drawable/ic_menu_gallery n'est pas vraiment requis ici, il s'agit simplement de prévisualiser le résultat de la mise en page dans IDE.

  1. ajouter du code dans onCreateOptionsMenu/onPrepareOptionsMenu

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.menu_main, menu);
    
        MenuItem menuItem = menu.findItem(R.id.testAction);
        menuItem.setIcon(buildCounterDrawable(count, R.drawable.ic_menu_gallery));
    
        return true;
    }
    
  2. Implémentez la méthode build-the-icon:

    private Drawable buildCounterDrawable(int count, int backgroundImageId) {
        LayoutInflater inflater = LayoutInflater.from(this);
        View view = inflater.inflate(R.layout.counter_menuitem_layout, null);
        view.setBackgroundResource(backgroundImageId);
    
        if (count == 0) {
            View counterTextPanel = view.findViewById(R.id.counterValuePanel);
            counterTextPanel.setVisibility(View.GONE);
        } else {
            TextView textView = (TextView) view.findViewById(R.id.count);
            textView.setText("" + count);
        }
    
        view.measure(
                View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED),
                View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED));
        view.layout(0, 0, view.getMeasuredWidth(), view.getMeasuredHeight());
    
        view.setDrawingCacheEnabled(true);
        view.setDrawingCacheQuality(View.DRAWING_CACHE_QUALITY_HIGH);
        Bitmap bitmap = Bitmap.createBitmap(view.getDrawingCache());
        view.setDrawingCacheEnabled(false);
    
        return new BitmapDrawable(getResources(), bitmap);
    }
    

Le code complet est ici: https://github.com/cvoronin/ActionBarMenuItemCounter

28
cVoronin

Ok, pour @ AndrewS la solution à utiliser avec bibliothèque v7 appCompat:

<menu 
    xmlns:Android="http://schemas.Android.com/apk/res/Android"
    xmlns:someNamespace="http://schemas.Android.com/apk/res-auto" >

    <item
        Android:id="@+id/saved_badge"
        someNamespace:showAsAction="always"
        Android:icon="@drawable/shape_notification" />

</menu>

.

@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
    super.onCreateOptionsMenu(menu, inflater);
    menu.clear();
    inflater.inflate(R.menu.main, menu);

    MenuItem item = menu.findItem(R.id.saved_badge);
    MenuItemCompat.setActionView(item, R.layout.feed_update_count);
    View view = MenuItemCompat.getActionView(item);
    notifCount = (Button)view.findViewById(R.id.notif_count);
    notifCount.setText(String.valueOf(mNotifCount));
}

private void setNotifCount(int count){
    mNotifCount = count;
    supportInvalidateOptionsMenu();
}

Le reste du code est le même.

26
ILovemyPoncho

Essayez de regarder les réponses à ces questions, en particulier la seconde qui contient un exemple de code:

Comment implémenter des valeurs dynamiques sur un élément de menu sous Android

Comment obtenir du texte sur une icône ActionBar?

D'après ce que je vois, vous devrez créer votre propre implémentation personnalisée ActionView. Une alternative pourrait être une coutume Drawable. Notez qu'il semble n'y avoir aucune implémentation native d'un nombre de notifications pour la barre d'action.

EDIT: La réponse que vous recherchiez, avec le code: affichage de la notification personnalisée avec exemple de mise en oeuvre

3
pqn

Lorsque vous utilisez la barre d'outils:

....
private void InitToolbar() {
    toolbar = (Toolbar) findViewById(R.id.my_awesome_toolbar);
    toolbartitle = (TextView) findViewById(R.id.titletool);
    toolbar.inflateMenu(R.menu.show_post);
    toolbar.setOnMenuItemClickListener(this);
    Menu menu = toolbar.getMenu();
    MenuItem menu_comments = menu.findItem(R.id.action_comments);
    MenuItemCompat
            .setActionView(menu_comments, R.layout.menu_commentscount);
    View v = MenuItemCompat.getActionView(menu_comments);
    v.setOnClickListener(new OnClickListener() {

        @Override
        public void onClick(View arg0) {
            // Your Action
        }
    });
    comment_count = (TextView) v.findViewById(R.id.count);
}

et dans votre appel de données de chargement refreshMenu ():

private void refreshMenu() {
    comment_count.setVisibility(View.VISIBLE);
    comment_count.setText("" + post_data.getComment_count());
}
2
Omid Omidi

J'ai trouvé une très bonne solution ici , je l'utilise avec kotlin.

Tout d'abord, dans le dossier pouvant être dessiné, vous devez créer item_count.xml:

<?xml version="1.0" encoding="utf-8"?> <shape xmlns:Android="http://schemas.Android.com/apk/res/Android"
Android:shape="rectangle">
<corners Android:radius="8dp" />
<solid Android:color="#f20000" />
<stroke
    Android:width="2dip"
    Android:color="#FFF" />
<padding
    Android:bottom="5dp"
    Android:left="5dp"
    Android:right="5dp"
    Android:top="5dp" />
</shape>

Dans votre Activity_Main Layout, par exemple:

<RelativeLayout
                    Android:id="@+id/badgeLayout"
                    Android:layout_width="40dp"
                    Android:layout_height="40dp"
                    Android:layout_toRightOf="@+id/badge_layout1"
                    Android:layout_gravity="end|center_vertical"
                    Android:layout_marginEnd="5dp">

                <RelativeLayout
                        Android:id="@+id/relative_layout1"
                        Android:layout_width="wrap_content"
                        Android:layout_height="wrap_content">

                    <Button
                            Android:id="@+id/btnBadge"
                            Android:layout_width="match_parent"
                            Android:layout_height="match_parent"
                            Android:background="@mipmap/ic_notification" />

                </RelativeLayout>

                <TextView
                        Android:id="@+id/txtBadge"
                        Android:layout_width="18dp"
                        Android:layout_height="18dp"
                        Android:layout_alignRight="@id/relative_layout1"
                        Android:background="@drawable/item_count"
                        Android:text="22"
                        Android:textColor="#FFF"
                        Android:textSize="7sp"
                        Android:textStyle="bold"
                        Android:gravity="center"/>

            </RelativeLayout>

Et vous pouvez modifier comme:

btnBadge.setOnClickListener { view ->
        Snackbar.make(view,"badge click", Snackbar.LENGTH_LONG) .setAction("Action", null).show()
        txtBadge.text = "0"
    }
1
Álvaro Agüero

J'ai trouvé un meilleur moyen de le faire. si vous voulez utiliser quelque chose comme ça

enter image description here

Utilisez cette dépendance

   compile 'com.nex3z:notification-badge:0.1.0'

créer un fichier xml dans drawable et l'enregistrer en tant que Badge.xml

<?xml version="1.0" encoding="utf-8"?>
  <layer-list xmlns:Android="http://schemas.Android.com/apk/res/Android">

<item>
    <shape Android:shape="oval">
        <solid Android:color="#66000000"/>
        <size Android:width="30dp" Android:height="40dp"/>
    </shape>
</item>
<item Android:bottom="1dp" Android:right="0.6dp">
    <shape Android:shape="oval">
        <solid Android:color="@color/Error_color"/>
        <size Android:width="20dp" Android:height="20dp"/>
    </shape>
</item>
</layer-list>

Maintenant, partout où vous voulez utiliser ce badge, utilisez le code suivant en XML. avec l'aide de cela, vous pourrez voir ce badge dans le coin supérieur droit de votre image ou quoi que ce soit.

  <com.nex3z.notificationbadge.NotificationBadge
    Android:id="@+id/badge"
    Android:layout_toRightOf="@id/Your_ICON/IMAGE"
    Android:layout_alignTop="@id/Your_ICON/IMAGE"
    Android:layout_marginLeft="-16dp"
    Android:layout_marginTop="-8dp"
    Android:layout_width="28dp"
    Android:layout_height="28dp"
    app:badgeBackground="@drawable/Badge"
    app:maxTextLength="2"
    ></com.nex3z.notificationbadge.NotificationBadge>

Maintenant, enfin sur yourFile.Java, utilisez ces 2 choses simples .. 1) Définir

 NotificationBadge mBadge;

2) où votre boucle ou tout ce qui compte ce nombre utilise ceci:

 mBadge.setNumber(your_LoopCount);

ici, mBadge.setNumber(0) ne montrera rien.

J'espère que cette aide.

0
deep bhatt