You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在不全局主题化的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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.16 13:00:59