Aggiungi il conteggio del nuovo elemento all'icona sul pulsante - Android


87

Sono sviluppatore. Ho bisogno di implementare il design mostrato di seguito. Ho già un'app funzionale ma mi chiedo come approcciarla? In particolare, mi interessa come mostrare il numero di elementi "nuovi" nelle schede. Quello che SO come fare è creare nuove icone con punti rossi e visualizzarle solo quando sono disponibili nuove cose.

Ma non ho idea di come far fluttuare quei cerchi rotondi sopra il titolo E mostrare il numero all'interno. Qualcuno ha suggerimenti su cosa cercare? Campioni? Indicazioni?

Seconda domanda sulla separazione delle attività. Devo controllare per combinare pulsanti come questo e semplicemente gonfiarlo sulle attività? Altrimenti potrei creare attività a schede ma non sono sicuro se sia possibile modellarlo per farlo sembrare così.

Parte della navigazione in alto

Risposte:


164

Rendi il tuo badge a TextView, permettendoti di impostare il valore numerico su qualsiasi cosa tu voglia chiamando setText(). Imposta lo sfondo del TextViewcome un <shape>disegnabile XML , con il quale puoi creare un cerchio pieno o sfumato con un bordo. Un disegnabile XML si ridimensionerà per adattarsi alla vista mentre viene ridimensionato con più o meno testo.

res / drawable / badge_circle.xml:

<shape xmlns:android="http://schemas.android.com/apk/res/android"
  android:shape="oval">
  <solid
    android:color="#F00" />
  <stroke
    android:width="2dip"
    android:color="#FFF" />
  <padding
    android:left="5dip"
    android:right="5dip"
    android:top="5dip"
    android:bottom="5dip" />
</shape>

Tuttavia, dovrai dare un'occhiata a come l'ovale / cerchio scala con numeri grandi a 3-4 cifre. Se questo effetto non è desiderabile, prova un approccio a rettangolo arrotondato come di seguito. Con numeri piccoli, il rettangolo apparirà ancora come un cerchio mentre i raggi convergono insieme.

res / drawable / badge_circle.xml:

<shape xmlns:android="http://schemas.android.com/apk/res/android"
  android:shape="rectangle">
  <corners
    android:radius="10dip"/>
  <solid
    android:color="#F00" />
  <stroke
    android:width="2dip"
    android:color="#FFF" />
  <padding
    android:left="5dip"
    android:right="5dip"
    android:top="5dip"
    android:bottom="5dip" />
</shape>

Con lo sfondo scalabile creato, lo aggiungi semplicemente allo sfondo di un TextView, in questo modo:

<TextView
  android:layout_width="wrap_content"
  android:layout_height="wrap_content" 
  android:text="10"
  android:textColor="#FFF"
  android:textSize="16sp"
  android:textStyle="bold"
  android:background="@drawable/badge_circle"/>

Infine, questi TextViewbadge possono essere posizionati nel layout sopra i pulsanti / schede appropriati. Probabilmente lo farei raggruppando ogni pulsante con il suo badge in un RelativeLayoutcontenitore, in questo modo:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
  android:layout_width="wrap_content"
  android:layout_height="wrap_content">
  <Button
    android:id="@+id/myButton"
    android:layout_width="65dip"
    android:layout_height="65dip"/>
  <TextView
    android:id="@+id/textOne"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_alignTop="@id/myButton"
    android:layout_alignRight="@id/myButton" 
    android:text="10"
    android:textColor="#FFF"
    android:textSize="16sp"
    android:textStyle="bold"
    android:background="@drawable/badge_circle"/>
</RelativeLayout>

Spero che siano informazioni sufficienti per farti almeno indirizzare nella giusta direzione!


È possibile fare qualcosa di simile a questo con un TableLayout? Ho una griglia 2x2 di pulsanti e un layout relativo è più difficile da configurare rispetto a un layout relativo, tuttavia non posso usare attributi come aligntTop e alignRight
Nick

NM L'ho risolto semplicemente inserendo un layout relativo nella riga della tabella! Grazie, il codice funziona alla grande
Nick

3
@FelipeMosso Usa la ovalversione dell'esempio e aggiungi un <size>elemento per fornire proporzioni per larghezza / altezza
devunwired

4
L'icona del conteggio si nasconde dietro quel pulsante nel mio caso. Su Android 5.0. Non so cosa c'è che non va. Nel layout grafico sembra buono ma non nel dispositivo.
Braj

1
Se uso il pulsante per l'icona di conteggio, tutto funziona correttamente, ma se uso Textview va dietro al pulsante principale invece di apparire in alto!
Braj

10

Android ViewBadger

Un modo semplice per "contrassegnare" una data vista Android in fase di runtime senza dover occuparsene nel layout.

Aggiungi il .jarfile nella cartella libs

Fare clic per scaricare l' esempio

vedi Esempio su GitHub

Esempio semplice:

View target = findViewById(R.id.target_view);
BadgeView badge = new BadgeView(this, target);
badge.setText("1");
badge.show();

4
Questa libreria è deprecata.
wonsuc

3

Hack più semplice dando stile a TextViewsolo.

        <TextView
                android:id="@+id/fabCounter"
                style="@style/Widget.Design.FloatingActionButton"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_alignParentEnd="true"
                android:layout_centerVertical="true"
                android:layout_marginEnd="10dp"
                android:padding="5dp"
                android:text="10"
                android:textColor="@android:color/black"
                android:textSize="14sp" />

Risultato


1

per le persone che cercano Xamarin Android può usare questo codice

public class CountDrawable : Drawable
{
    private float mTextSize;
    private Paint mBadgePaint;
    private Paint mTextPaint;
    private Rect mTxtRect = new Rect();

    private String mCount = "";
    private bool mWillDraw = false;


    public CountDrawable(Context context)
    {
        float mTextSize = context.Resources.GetDimension(Resource.Dimension.badge_count_textsize);
        mBadgePaint = new Paint();
        // mBadgePaint.SetCol(ContextCompat.GetColor(context.ApplicationContext, Resource.Color.background_color));
        mBadgePaint.Color = new Color(Color.Red);
        mBadgePaint.AntiAlias = true;
        mBadgePaint.SetStyle(Paint.Style.Fill);

        mTextPaint = new Paint();
        mTextPaint.Color = new Color(Color.White);
        mTextPaint.SetTypeface(Typeface.DefaultBold);
        mTextPaint.TextSize = mTextSize;
        mTextPaint.AntiAlias = true;
        mTextPaint.TextAlign = Paint.Align.Center;
    }


    public override void Draw(Canvas canvas)
    {
        if(!mWillDraw)
        {
            return;
        }



        Rect bounds = GetBounds;
        float width = bounds.Right - bounds.Left;
        float height = bounds.Bottom - bounds.Top;

        float radius = ((Math.Max(width, height) / 2)) / 2;
        float centerX = (width - radius - 1) + 5;
        float centerY = radius - 5;
        if (mCount.Length <= 2)
        {
            // Draw badge circle.
            canvas.DrawCircle(centerX, centerY, (int)(radius + 5.5), mBadgePaint);
        }
        else
        {
            canvas.DrawCircle(centerX, centerY, (int)(radius + 6.5), mBadgePaint);
        }

        mTextPaint.GetTextBounds(mCount, 0, mCount.Length, mTxtRect);
        float textHeight = mTxtRect.Bottom - mTxtRect.Top;
        float textY = centerY + (textHeight / 2f);
        if (mCount.Length > 2)
            canvas.DrawText("99+", centerX, textY, mTextPaint);
        else
            canvas.DrawText(mCount, centerX, textY, mTextPaint);
    }

    public Rect GetBounds { get; set; }


    public void setCount(String count)
    {
        mCount = count;

        // Only draw a badge if there are notifications.
       // mWillDraw = !count.equalsIgnoreCase("0");
        mWillDraw = !string.Equals(count, "0", StringComparison.OrdinalIgnoreCase);
       // invalidateSelf();
    }

    public override void SetAlpha(int alpha)
    {

    }

    public override void SetColorFilter(ColorFilter colorFilter)
    {

    }

    public override int Opacity
    {
        get;
    }

}

E in MainActivity

public override bool OnCreateOptionsMenu(IMenu menu)
    {
        // return base.OnCreateOptionsMenu(menu);
        MenuInflater.Inflate(Resource.Menu.actionmenu, menu);
        // var dd = menu.FindItem(Resource.Id.icon_group);
        IMenuItem item = menu.FindItem(Resource.Id.ic_group);
        LayerDrawable icon = item.Icon as LayerDrawable;

        // LayerDrawable icon = (LayerDrawable)item.Icon;
        CountDrawable badge;
        Drawable reuse = icon.FindDrawableByLayerId(Resource.Id.ic_group_count);
        if (reuse != null && reuse is CountDrawable)
        {
            badge = (CountDrawable)reuse;
        }
        else
        {
            badge = new CountDrawable(this);

        }
        badge.setCount("8");
        badge.GetBounds=icon.Bounds;

        icon.Mutate();
        icon.SetDrawableByLayerId(Resource.Id.ic_group_count, badge);
        return true;
    }

come si rimpicciolisce il cerchio?
khalil

@khalil prova a creare usando SkiaSharp
Shethia

1

Solo per aggiungere. Se qualcuno desidera implementare una bolla circolare piena utilizzando la forma ad anello anziché l'ovale, ecco l'esempio di codice per aggiungere il conteggio delle bolle ai pulsanti della barra delle azioni. Ma questo può essere aggiunto a qualsiasi pulsante.

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

Potrebbe essere necessario regolare lo spessore in base alle proprie esigenze.

Il risultato sarà qualcosa del genere:

inserisci qui la descrizione dell'immagine

Ecco il layout per il pulsante (chiamalo 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>

Nel menu crea elemento:

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

Per onCreateOptionsMenuottenere il riferimento alla voce di 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();
            }
        }
    });

Dopo aver ricevuto la notifica per i messaggi, imposta il conteggio:

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

Questo codice utilizza Iconify-fontawesome .

compile 'com.joanzapata.iconify:android-iconify-fontawesome:2.1.+'
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.