无法在v7 Toolbar的Button上绘制通知数字的问题求助
嘿,这个问题我之前折腾过好一阵,给你几个实战有效的解决思路:
放弃Button的drawableTop,改用组合布局
Button自带的drawable(不管是drawableTop/Left等)属于Button内部的绘制元素,它的渲染优先级会高于FrameLayout里的子TextView,哪怕你调bringToFront()也可能抢不过。不如把Button拆成「ImageView + 可点击容器」的组合:用LinearLayout或者FrameLayout装ImageView(对应原来的drawableTop图标)和通知TextView,然后给这个容器设置点击事件,完全替代原来的Button。这样TextView作为独立子View,层级关系完全由你控制,绝对不会被覆盖。XML里调整子View顺序,比代码调用更靠谱
FrameLayout的Z轴顺序默认是「XML里靠后的View在上层」,有时候代码里的bringToFront()会因为渲染时机(比如View还没完成测量布局)失效。直接把TextView写在Button的后面:<FrameLayout android:layout_width="wrap_content" android:layout_height="wrap_content"> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:drawableTop="@drawable/ic_question_answer_white_24dp" android:text="消息"/> <TextView android:id="@+id/notification_badge" android:layout_width="20dp" android:layout_height="20dp" android:background="@drawable/badge_bg" android:text="3" android:textColor="#fff" android:gravity="center" android:layout_gravity="top|end"/> </FrameLayout>这样TextView默认就在Button上层,不需要额外调用
bringToFront()。用官方BadgeDrawable替代自定义TextView
Android从API 28开始提供了BadgeDrawable,Material Components库也兼容低版本,这是官方推荐的通知角标实现方式,完全不会有层级冲突问题。示例代码:// 创建角标 val badge = BadgeDrawable.create(requireContext()) badge.number = 5 // 设置通知数 badge.badgeGravity = BadgeDrawable.TOP_END // 位置:右上角 badge.backgroundColor = ContextCompat.getColor(requireContext(), R.color.red) // 绑定到Button上 BadgeUtils.attachBadgeDrawable(badge, yourToolbarButton, null)这种方式系统会自动处理Z轴层级,省心又规范。
调整elevation属性强制提升TextView层级
如果一定要保留drawableTop的写法,可以给TextView设置更高的elevation值,把它的Z轴层级拉高:<TextView ... android:elevation="8dp"/>同时把Button的elevation设低一点(比如
android:elevation="2dp"),因为Android的Z轴优先级是elevation高的View在上,这比bringToFront()更直接有效。检查Button的样式属性
如果你用的是MaterialButton这类带样式的Button,它可能自带foreground属性(比如波纹效果),这个foreground会覆盖在所有子View之上。可以试试把Button的android:foreground="@null"去掉前景层,或者改用普通的AppCompatButton,看看是不是样式导致的遮挡。
内容的提问来源于stack exchange,提问作者marfin

