Agregar nuevo recuento de elementos al ícono del botón - Android

87

Soy desarrollador. Necesito implementar el diseño que se muestra a continuación. Ya tengo una aplicación funcional, pero me pregunto cómo abordar esto. En particular, estoy interesado en cómo mostrar el número de elementos "nuevos" en las pestañas. Lo que SÉ cómo hacer es crear nuevos iconos con puntos rojos y mostrarlos cuando haya cosas nuevas disponibles.

Pero no tengo idea de cómo hacer que esos círculos redondos floten en la parte superior del título Y muestren el número dentro. ¿Alguien tiene alguna sugerencia sobre qué buscar también? Muestras ¿Direcciones?

Segunda pregunta sobre la separación de actividades. ¿Debería hacer el control para combinar botones como este y simplemente inflarlo en actividades? De lo contrario, puedo crear una actividad con pestañas, pero no estoy seguro de si es posible darle estilo para que se vea así.

Parte de la navegación superior

Katit
fuente

Respuestas:

164

Haga que su insignia sea a TextView, lo que le permite establecer el valor numérico en cualquier cosa que desee llamando setText(). Establezca el fondo del TextViewcomo un elemento de <shape>diseño XML , con el que puede crear un círculo sólido o degradado con un borde. Un elemento de diseño XML se escalará para adaptarse a la vista a medida que cambia de tamaño con más o menos texto.

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>

Sin embargo, tendrá que observar cómo el óvalo / círculo se escala con números grandes de 3-4 dígitos. Si este efecto no es deseable, pruebe con un enfoque de rectángulo redondeado como el siguiente. Con números pequeños, el rectángulo aún se verá como un círculo cuando los radios converjan.

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 el fondo escalable creado, simplemente agréguelo al fondo de a TextView, así:

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

Finalmente, estas TextViewinsignias se pueden colocar en su diseño encima de los botones / pestañas correspondientes. Probablemente haría esto agrupando cada botón con su insignia en un RelativeLayoutcontenedor, así:

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

¡Con suerte, es suficiente información para que al menos apunte en la dirección correcta!

desconectado
fuente
¿Es posible hacer algo similar a esto con un TableLayout? Tengo una cuadrícula de botones de 2x2 y un diseño relativo es más complicado de configurar que un diseño relativo, sin embargo, no puedo usar atributos como aligntTop y alignRight
Nick
NM ¡Lo resolví simplemente poniendo un diseño relativo en la fila de la tabla! Gracias, el código funciona muy bien
Nick
3
@FelipeMosso Use la ovalversión del ejemplo y agregue un <size>elemento para proporcionar proporciones para el ancho / alto
devunwired
4
El ícono de conteo se esconde detrás de ese botón en mi caso. En Android 5.0. No sé qué pasa. En el diseño gráfico se ve bien pero no en el dispositivo.
Braj
1
Si uso el botón para el ícono de conteo, todo funciona bien, pero si uso Textview, ¡va detrás del botón principal en lugar de aparecer en la parte superior!
Braj
10

Android ViewBadger

Una forma sencilla de "marcar" cualquier vista de Android en tiempo de ejecución sin tener que atenderla en el diseño.

Agregue un .jararchivo en su carpeta libs

Haga clic para descargar Ejemplo

ver ejemplo en github

Ejemplo simple:

View target = findViewById(R.id.target_view);
BadgeView badge = new BadgeView(this, target);
badge.setText("1");
badge.show();
Mansukh Ahir
fuente
4
Esta biblioteca está obsoleta.
wonsuc
3

Truco más simple dando estilo 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" />

Resultado

Aks4125
fuente
1

para las personas que buscan Xamarin Android pueden usar este código

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

}

Y en 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;
    }
Ronak Shethia
fuente
¿Cómo hago el círculo más pequeño?
khalil
@khalil intenta crear usando SkiaSharp
Ronak Shethia
1

Solo para agregar. Si alguien quiere implementar una burbuja de círculo relleno usando la forma de anillo en lugar de óvalo, aquí está el ejemplo de código de cómo agregar el recuento de burbujas a los botones de la barra de acción. Pero esto se puede agregar a cualquier botón.

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

Puede que tenga que ajustar el grosor según sus necesidades.

El resultado será algo como esto:

ingrese la descripción de la imagen aquí

Aquí está el diseño para el botón (nómbrelo 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>

En el menú crear elemento:

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

En onCreateOptionsMenuobtener referencia al elemento del menú:

    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();
            }
        }
    });

Después de recibir una notificación de mensajes, configure el recuento:

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

Este código usa Iconify-fontawesome .

compile 'com.joanzapata.iconify:android-iconify-fontawesome:2.1.+'
Abdullah Umer
fuente