如何在不全局主题化的Android自定义通知布局中应用Material You动态色
仅为Android自定义通知应用Material You动态颜色的解决方案
核心思路
无需修改应用全局主题,只需创建仅作用于通知的专用主题,或直接通过API获取系统动态颜色值,再将其应用到自定义通知的RemoteViews中即可。
步骤1:创建通知专用动态主题(可选,推荐)
在res/values/styles.xml中创建继承自系统动态主题的通知专用主题,这样布局可直接引用主题属性,且不会影响全局主题:
<style name="NotificationDynamicTheme" parent="android:Theme.Material.DayNight.DynamicColors"> <!-- 可自定义通知专属的主题属性 --> <item name="android:textColor">?android:attr/textColorPrimary</item> <item name="android:background">?android:attr/colorSurface</item> </style>
针对Android 12+(API 31),可在res/values-v31/styles.xml中优化主题继承:
<style name="NotificationDynamicTheme" parent="android:Theme.Material.DynamicColors.DayNight"> <!-- 同上自定义属性 --> </style>
步骤2:直接获取Material You动态颜色值
若不想依赖主题,可通过DynamicColors API(Android 12+)直接提取系统动态颜色,低版本提供固定 fallback 值:
import android.os.Build import androidx.core.content.ContextCompat import com.google.android.material.color.DynamicColors // 获取动态主色 fun getDynamicPrimaryColor(context: Context): Int { return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { DynamicColors.getDynamicColor(context, android.R.attr.colorPrimary) } else { ContextCompat.getColor(context, R.color.default_primary) } } // 获取动态表面色 fun getDynamicSurfaceColor(context: Context): Int { return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { DynamicColors.getDynamicColor(context, android.R.attr.colorSurface) } else { ContextCompat.getColor(context, R.color.default_surface) } }
步骤3:构建自定义通知布局并应用颜色
假设自定义通知布局layout/custom_notification.xml结构如下:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/root_layout" android:layout_width="match_parent" android:layout_height="wrap_content" android:padding="16dp" android:orientation="vertical"> <TextView android:id="@+id/notification_title" android:layout_width="match_parent" android:layout_height="wrap_content" android:textSize="16sp" android:textStyle="bold"/> <TextView android:id="@+id/notification_content" android:layout_width="match_parent" android:layout_height="wrap_content" android:textSize="14sp" android:layout_marginTop="4dp"/> <View android:id="@+id/notification_divider" android:layout_width="match_parent" android:layout_height="1dp" android:layout_marginVertical="8dp"/> </LinearLayout>
方式一:通过主题绑定RemoteViews
使用ContextThemeWrapper将通知主题关联到RemoteViews,布局自动继承动态配色:
val contextThemeWrapper = ContextThemeWrapper(context, R.style.NotificationDynamicTheme) val remoteViews = RemoteViews(contextThemeWrapper.packageName, R.layout.custom_notification) // 直接设置文本,颜色自动继承主题属性 remoteViews.setTextViewText(R.id.notification_title, "动态主题通知") remoteViews.setTextViewText(R.id.notification_content, "仅通知应用Material You动态配色")
方式二:手动设置动态颜色
如需精细控制,直接将获取到的动态颜色赋值给布局元素:
val remoteViews = RemoteViews(context.packageName, R.layout.custom_notification) val primaryColor = getDynamicPrimaryColor(context) val surfaceColor = getDynamicSurfaceColor(context) val textColor = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { DynamicColors.getDynamicColor(context, android.R.attr.textColorPrimary) } else { ContextCompat.getColor(context, android.R.color.black) } remoteViews.setTextColor(R.id.notification_title, primaryColor) remoteViews.setTextColor(R.id.notification_content, textColor) remoteViews.setInt(R.id.notification_divider, "setBackgroundColor", primaryColor) remoteViews.setInt(R.id.root_layout, "setBackgroundColor", surfaceColor)
步骤4:构建并显示通知
将RemoteViews绑定到通知构建器,同时设置通知栏图标背景色与动态主色一致:
private const val CHANNEL_ID = "dynamic_notification_channel" private const val NOTIFICATION_ID = 1001 val notificationBuilder = NotificationCompat.Builder(context, CHANNEL_ID) .setSmallIcon(R.drawable.ic_notification) .setCustomContentView(remoteViews) .setColor(getDynamicPrimaryColor(context)) // 同步通知栏图标背景色 .setPriority(NotificationCompat.PRIORITY_DEFAULT) val notificationManager = ContextCompat.getSystemService(context, NotificationManager::class.java) if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { val channel = NotificationChannel(CHANNEL_ID, "动态通知", NotificationManager.IMPORTANCE_DEFAULT) notificationManager?.createNotificationChannel(channel) } notificationManager?.notify(NOTIFICATION_ID, notificationBuilder.build())
常见问题修复
- Cannot resolve symbol 'colorPrimary':确保通过
?android:attr/colorPrimary引用系统主题属性,而非直接写colorPrimary;自定义主题需继承支持动态颜色的系统主题。 - 低版本兼容:Android 12以下无法获取动态颜色,必须提供fallback固定颜色,避免崩溃。
内容的提问来源于stack exchange,提问作者Nishant
相关产品推荐
相关产品推荐

