Adicionar nova contagem de itens ao ícone no botão - Android

87

Sou desenvolvedor. Preciso implementar o design mostrado abaixo. Eu já tenho um aplicativo funcional, mas gostaria de saber como abordar isso? Particularmente, estou interessado em como mostrar o Número de itens "Novos" nas guias. O que eu SEI fazer - é criar novos ícones com pontos vermelhos e apenas exibi-los quando houver novidades disponíveis.

Mas não tenho ideia de como fazer esses círculos redondos flutuarem no topo do título E mostrar o número dentro. Alguém tem sugestão sobre o que procurar? Amostras? Instruções?

Segunda pergunta sobre a separação de atividades. Devo fazer o controle para combinar botões como este e apenas aumentá-lo nas atividades? Caso contrário, posso criar atividade com guias, mas não tenho certeza se é possível estilizá-la para que fique assim.

Parte da navegação superior

Katit
fonte

Respostas:

164

Faça seu crachá um TextView, permitindo que você defina o valor numérico para qualquer coisa que você quiser chamando setText(). Defina o fundo do TextViewcomo um <shape>drawable XML , com o qual você pode criar um círculo sólido ou gradiente com uma borda. Um drawable XML será dimensionado para se ajustar à visualização à medida que é redimensionado com mais ou 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>

Você terá que dar uma olhada em como o oval / círculo é dimensionado com grandes números de 3-4 dígitos, no entanto. Se este efeito for indesejável, tente uma abordagem de retângulo arredondado como abaixo. Com números pequenos, o retângulo ainda parecerá um círculo conforme os raios convergem juntos.

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>

Com o plano de fundo escalável criado, você simplesmente o adiciona ao plano de fundo de um TextView, assim:

<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, esses TextViewemblemas podem ser colocados em seu layout sobre os botões / guias apropriados. Eu provavelmente faria isso agrupando cada botão com seu emblema em um RelativeLayoutcontêiner, assim:

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

Esperançosamente, essa informação é suficiente para, pelo menos, levá-lo na direção certa!

sem fio
fonte
É possível fazer algo semelhante a isso com um TableLayout? Eu tenho uma grade 2x2 de botões e um layout relativo é mais difícil de configurar do que um layout relativo, no entanto, não posso usar atributos como aligntTop e alignRight
Nick
NM Eu resolvi isso apenas colocando um layout relativo na linha da tabela! Obrigado, o código funciona muito bem
Nick
3
@FelipeMosso Use a ovalversão do exemplo e adicione um <size>elemento para fornecer proporções para a largura / altura
desligada em
4
O ícone de contagem está escondido atrás desse botão no meu caso. No Android 5.0. Não sei o que está errado. No layout gráfico parece bom, mas não no dispositivo.
Braj
1
Se eu usar o botão para ícone de contagem, tudo funcionará bem, mas se eu usar o Textview ele vai atrás do botão principal em vez de aparecer no topo!
Braj
10

Android ViewBadger

Uma maneira simples de "identificar" qualquer visualização do Android em tempo de execução sem ter que atendê-la no layout.

Adicionar .jararquivo em sua pasta libs

Clique para baixar o exemplo

veja o exemplo no github

Exemplo simples:

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

O hack mais simples, dando estilo a TextViewapenas.

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

para as pessoas que procuram Xamarin Android podem 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;
    }

}

E em 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
fonte
como faço para tornar o círculo menor?
khalil
@khalil tente criar usando SkiaSharp
Ronak Shethia
1

Apenas para adicionar. Se alguém deseja implementar um círculo cheio de bolhas usando a forma de anel em vez de oval, aqui está o exemplo de código de adição da contagem de bolhas aos botões da barra de ação. Mas isso pode ser adicionado a qualquer botão.

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

Você pode ter que ajustar a espessura de acordo com sua necessidade.

O resultado será mais ou menos assim:

insira a descrição da imagem aqui

Este é o layout do botão (nomeie-o 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>

No menu criar item:

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

Para onCreateOptionsMenuobter referência ao item do 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();
            }
        }
    });

Após receber a notificação de mensagens, defina a contagem:

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
fonte