¿Existe una insignia o método estándar de Android para mostrar el icono de notificación de la barra de acción con un recuento como en los ejemplos de Google?
Si no, ¿cuál es la mejor manera de hacerlo?
Soy nuevo en Android, por favor ayuda.
¿Existe una insignia o método estándar de Android para mostrar el icono de notificación de la barra de acción con un recuento como en los ejemplos de Google?
Si no, ¿cuál es la mejor manera de hacerlo?
Soy nuevo en Android, por favor ayuda.
Respuestas:
No estoy seguro de si esta es la mejor solución o no, pero es lo que necesito.
Por favor, dígame si sabe qué se debe cambiar para obtener un mejor rendimiento o calidad. En mi caso, tengo un botón.
Elemento personalizado en mi menú - main.xml
<item
android:id="@+id/badge"
android:actionLayout="@layout/feed_update_count"
android:icon="@drawable/shape_notification"
android:showAsAction="always">
</item>
Forma personalizada dibujable (cuadrado de fondo) - 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>
Diseño para mi vista: 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: configuración y actualización de mi vista
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();
}
MenuItem item = menu.findItem(R.id.badge); MenuItemCompat.setActionView(item, R.layout.feed_update_count); notifCount = (Button) MenuItemCompat.getActionView(item);
android:icon="..."
elemento XML en el elemento del menú. El android:actionLayout="..."
es suficiente, allí. Para el Button
XML de diseño, puede usar la etiqueta de cierre automático <Button ... />
porque la etiqueta no puede tener contenido. Necesita cerrar la <shape>
etiqueta (de nuevo: cierre automático). Y no necesitas el invalidateOptionsMenu()
. Para mí, eso ni siquiera funciona, ya que la insignia siempre se infla desde XML nuevamente. Entonces, el todo setNotifCount(...)
es inútil. Solo llama setText(...)
a la insignia. Y usted puede echar getActionView()
a Button
directamente.
Editar Desde la versión 26 de la biblioteca de soporte (o androidx) ya no necesita implementar una costumbre OnLongClickListener
para mostrar la información sobre herramientas. Simplemente llame a esto:
TooltipCompat.setTooltipText(menu_hotlist, getString(R.string.hint_show_hot_message));
Compartiré mi código en caso de que alguien quiera algo como esto:
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
Estilo de nota y Android: propiedades clicables . estos hacen que el diseño sea del tamaño de un botón y hacen que el fondo sea gris cuando se toca.
<?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
Una imagen de 64x64 píxeles con rellenos de 10 píxeles de ancho desde todos los lados. Se supone que tiene rellenos de 8 píxeles de ancho, pero creo que la mayoría de los elementos predeterminados son un poco más pequeños que eso. Por supuesto, querrás usar diferentes tamaños para diferentes densidades.
drawable / rounded_square.xml
Aquí, # ff222222 (color # 222222 con alfa #ff (totalmente visible)) es el color de fondo de mi Barra de acción.
<?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
¡Aquí lo hacemos clicable y actualizable! Creé un oyente abstracto que proporciona la creación de Toast en onLongClick, el código fue tomado de las fuentes 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;
}
}
app:actionLayout="@layout/action_bar_notifitcation_icon"
lugar de android:actionLayout="@layout/action_bar_notifitcation_icon"
si tiene que usar en MenuItemCompat.getActionView
lugar de menu.findItem(R.id.menu_hotlist).getActionView();
para problemas de compatibilidad. MenuItem.getActionView
no es compatible con el nivel API <11.
android:actionLayout
; AppCompat: app:actionLayout
en su elemento del menú.
Solo para agregar. Si alguien quiere implementar una burbuja de círculo llena, aquí está el código (nómbrelo 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.
EDITAR:
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 onCreateOptionsMenu
obtener 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 la notificación de mensajes, establezca 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.+'
No me gustan las ActionView
soluciones basadas, mi idea es:
TextView
, que TextView
se completará por aplicacióncuando necesitas dibujar un MenuItem
:
2.1. diseño inflado
2.2. call measure()
& layout()
(de lo contrario view
será 0px x 0px, es demasiado pequeño para la mayoría de los casos de uso)
2.3. establecer el TextView
texto de
2.4. hacer una "captura de pantalla" de la vista
2.6. conjunto MenuItem
de iconos basado en mapa de bits creado en 2.4
¡lucro!
entonces, el resultado debería ser algo como
<?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
es que TextView
el fondo
verde @drawable/ic_menu_gallery
no es realmente necesario aquí, es solo para obtener una vista previa del resultado del diseño en IDE.
agregar código en 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;
}
Implemente el método 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);
}
El código completo está aquí: https://github.com/cvoronin/ActionBarMenuItemCounter
Ok, para que la solución @AndrewS funcione con la biblioteca 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();
}
El resto del código es el mismo.
android:actionLayout
a app:actionLayout
lo workes como encanto.
Intente mirar las respuestas a estas preguntas, particularmente la segunda que tiene un código de muestra:
Cómo implementar valores dinámicos en el elemento del menú en Android
¿Cómo obtener texto en un icono de ActionBar?
Por lo que veo, deberás crear tu propia ActionView
implementación personalizada . Una alternativa podría ser una costumbre Drawable
. Tenga en cuenta que no parece haber una implementación nativa de un recuento de notificaciones para la Barra de acciones.
EDITAR: la respuesta que estaba buscando, con el código: Vista de notificación personalizada con implementación de muestra
Drawable
s como se ve en los siguientes dos enlaces: stackoverflow.com/questions/6691818/… y stackoverflow.com/questions/3972445/…
Drawable
algo a través de algo como el enlace aquí y luego hacer un atributo para su costumbre Drawable
que tenga texto sobre él para que pueda crear todo en XML y ajústelo como desee. Alternativamente, puede agregar el Drawable en Java si esto es demasiado difícil.
Cuando usas la barra de herramientas:
....
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);
}
y en su carga de datos llame a refreshMenu ():
private void refreshMenu() {
comment_count.setVisibility(View.VISIBLE);
comment_count.setText("" + post_data.getComment_count());
}
Encontré una muy buena solución aquí , la estoy usando con Kotlin.
Primero, en la carpeta dibujable debes crear 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>
En su Activity_Main
diseño, algunos como:
<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>
Y puedes modificar como:
btnBadge.setOnClickListener { view ->
Snackbar.make(view,"badge click", Snackbar.LENGTH_LONG) .setAction("Action", null).show()
txtBadge.text = "0"
}
Encontré una mejor manera de hacerlo. si quieres usar algo como esto
Usa esta dependencia
compile 'com.nex3z:notification-badge:0.1.0'
cree un archivo xml en drawable y guárdelo como 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>
Ahora, donde quiera usar esa insignia, use el siguiente código en xml. Con la ayuda de esto, podrá ver esa insignia en la esquina superior derecha de su imagen o cualquier cosa.
<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>
Ahora finalmente en yourFile.java use esta cosa simple 2. 1) Definir
NotificationBadge mBadge;
2) donde su bucle o cualquier cosa que cuente este número use esto:
mBadge.setNumber(your_LoopCount);
aquí, mBadge.setNumber(0)
no mostrará nada.
Espero que esto ayude.