Android Toolbar带计数角标通知铃铛计数为0时点击无响应
问题现象
在Toolbar中实现带通知计数角标的通知铃铛图标时,非零计数场景功能运行符合预期,但通知计数为0时点击铃铛图标无法触发响应。初步推测问题与铃铛上层展示计数的actionLayout配置有关,但铃铛图标本身理论上应正常接收点击事件,暂未定位到代码异常位置。
已确认的现象:
- 通知计数为0时,
onMenuItemClick回调内的日志打印、Toast提示均不会执行 - 通知计数非0时,计数角标的点击事件可正常触发
相关实现代码
菜单项配置
<item android:id="@+id/notificationBell" android:title="" android:icon="@drawable/notification" app:actionLayout="@layout/menuitem_notification_count" android:visible="true" app:showAsAction="always"> </item>
自定义Action布局(menuitem_notification_count.xml)
<?xml version="1.0" encoding="utf-8"?> <FrameLayout style="?attr/actionButtonStyle" xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="wrap_content" android:layout_height="wrap_content" android:clipToPadding="false" android:focusable="true"> <ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:src="@drawable/notification"/> <TextView android:id="@+id/cart_badge" android:layout_width="22dp" android:layout_height="22dp" android:layout_gravity="end|top" android:layout_marginEnd="-10dp" android:layout_marginTop="1dp" android:padding="2dp" android:background="@drawable/notification_count_background" android:textAlignment="center" android:gravity="center" android:textColor="@android:color/white" android:textSize="12sp"/> </FrameLayout>
菜单初始化逻辑(onCreateOptionsMenu)
@Override public void onCreateOptionsMenu(final Menu menu, final MenuInflater inflater) { super.onCreateOptionsMenu(menu, inflater); inflater.inflate(R.menu.menu_notification, menu); MenuItem notificationBell = menu.findItem(R.id.notificationBell); textNotificationCount = notificationBell.getActionView().findViewById(R.id.cart_badge); Typeface fontFace = ResourcesCompat.getFont(getActivity(), R.font.roboto_medium_numbers); textNotificationCount.setTypeface(fontFace); notificationCount = getNotificationCount(); int checkCount = Integer.parseInt(notificationCount); Log.d(TAG, "run: Notification Count = " + notificationCount); notificationBell.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() { @Override public boolean onMenuItemClick(MenuItem menuItem) { if (checkCount==0){ // 此处Toast和日志始终无法触发 Log.d(TAG, "run: Notification Count Is 0"); Toast.makeText(getActivity(), "No New Notifications.", Toast.LENGTH_SHORT).show(); } return false; } }); if (checkCount == 0) { if (textNotificationCount.getVisibility() != View.GONE) { textNotificationCount.setVisibility(View.GONE); } } else if (checkCount > 99) { textNotificationCount.setText("99+"); if (textNotificationCount.getVisibility() != View.VISIBLE) { textNotificationCount.setVisibility(View.VISIBLE); } } else { textNotificationCount.setText(notificationCount); if (textNotificationCount.getVisibility() != View.VISIBLE) { textNotificationCount.setVisibility(View.VISIBLE); } } textNotificationCount.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { // 计数非0时该点击事件可正常触发 } }); }
问题根因
给MenuItem设置自定义actionLayout后,菜单项的点击事件分发会被自定义Action视图完全接管,外层的onMenuItemClick回调只有在Action视图及其子View都不消费点击事件时才会触发。
代码存在两个直接导致点击失效的问题:
- 自定义布局的根FrameLayout设置了
android:focusable="true",同时继承了?attr/actionButtonStyle自带的可点击属性,会优先拦截整个菜单项区域的触摸事件,但没有给这个根布局设置点击监听,事件被它直接消费,根本不会传到外层的onMenuItemClick。 - 非零计数时只给角标TextView设置了点击监听,点角标能触发响应只是因为点到了绑定了监听的TextView,点铃铛图标本身其实也不会触发
onMenuItemClick,只是之前测试非0场景时大概率点到了角标才误以为功能正常;计数为0时角标被设为GONE,整个可点击区域只剩未绑定监听的根布局和ImageView,点击后自然没有任何响应。
修复方案
- 删掉自定义Action布局根FrameLayout上多余的
android:focusable="true"属性,避免不必要的焦点抢占。 - 不要依赖
setOnMenuItemClickListener处理带自定义Action视图的菜单项点击,直接给Action视图的根布局绑定统一的点击监听,覆盖整个铃铛的点击区域,不管角标是否显示、点在铃铛哪个位置都能正常触发逻辑。 - 删掉之前单独给角标TextView设置的点击监听,点击角标时事件会自动冒泡到上层根布局,无需重复绑定。
核心修复代码参考:
@Override public void onCreateOptionsMenu(final Menu menu, final MenuInflater inflater) { super.onCreateOptionsMenu(menu, inflater); inflater.inflate(R.menu.menu_notification, menu); MenuItem notificationBell = menu.findItem(R.id.notificationBell); // 先拿到自定义Action的根视图 View actionRoot = notificationBell.getActionView(); textNotificationCount = actionRoot.findViewById(R.id.cart_badge); // ... 省略原有字体设置、计数获取逻辑 ... // 给根视图绑定统一点击监听,覆盖整个铃铛区域 actionRoot.setOnClickListener(v -> { if (checkCount == 0){ Log.d(TAG, "run: Notification Count Is 0"); Toast.makeText(getActivity(), "No New Notifications.", Toast.LENGTH_SHORT).show(); } else { // 此处写非零计数时的跳转逻辑,比如打开通知列表页 } }); // ... 省略原有角标显隐、文本赋值逻辑 ... // 删掉之前给textNotificationCount单独设置的setOnClickListener即可 }
内容的提问来源于stack exchange,提问作者Ritu
相关产品推荐
相关产品推荐

