六款桌面小组件,沿用 App 现在的三样东西:跟着封面变的配色、播放页的封面形状、连在一起的切歌按钮组。正在播放是唯一的主角,其余几款做得克制,只负责把人带到对应的功能。下面的原型都能点,顶部预览栏可以切歌、暂停、换配色。
配色来源、配色风格、主题都读 App 的外观设置。默认跟随封面,切歌时所有小组件一起换色;桌面上没有过渡动画,颜色直接换。
播放中的封面用播放页当前的形状,暂停时换成圆角方形看全图。形状在 App 里裁好,再把位图交给桌面。
上一首、播放、下一首连成一组,中间一段最宽、用主色。尺寸小时只留播放和下一首。
切歌、暂停、收藏这些事件触发更新。时间文字交给系统计时控件自己走,进度条只在亮屏播放时 10 秒刷一次。
两屏桌面,按 4 列、每格 84×100dp 画。第一屏是常用组合,第二屏放榜单和歌单。组件上的播放、切歌、收藏按钮可以直接点。
组件的深浅跟 App 的主题设置走:App 是跟随系统时随手机切换,是浅色或深色时固定。可以在预览栏把 App 主题设成深色、手机保持浅色模式看看。
配色来源和 App 外观页是同一个设置(跟随封面、系统壁纸、品牌松绿、自选颜色),组件用和 App 相同的种子色和配色风格。
长按桌面打开小组件选择器后看到的列表。每张卡片写默认尺寸和一句说明,说明就是 android:description 的文案。
Android 15 起选择器可以显示 App 实时生成的预览,所以这里的预览就是组件本身,带着当前歌曲的配色。
七档布局,从 1×1 的封面按钮到 4×3 的歌词舞台。桌面给多大,就选能放下的最大一档,所以拖动尺寸时布局按档切换,不会等比缩放。
当前一句放大,下一句变淡;有翻译时翻译跟在当前句下面。只按行换,不做逐字高亮:桌面组件不能播放动画,逐字刷新也太费电。
底色用主色容器,和正在播放区分开。透明背景时文字固定白色加阴影,浅色壁纸上会不好认,所以默认实色。
没有歌词时显示“纯音乐,请欣赏”或“暂时没有歌词”,点一下照样进播放页。
绑定一个平台的一个模式,比如网易云私人漫游的默认模式。点播放在后台开始漫游,不打开 App;漫游中显示当前歌曲和下一首按钮。
需要登录的模式在未登录时换成“去登录”。添加时默认选第一个已登录平台的第一个模式,之后长按组件可以重新选。
点某一行,从这一首开始播放整张榜单或歌单,不弹出播放页;点标题打开对应页面。列表可以在组件里上下滑。
榜单第一名用榜单页同款拱形封面,排名变化用箭头和“新”标。歌单默认是“我喜欢的歌曲”,正在播放的那一行标成主色。
2×2 是四瓣饼干形底板,中间是听歌识曲,四角是搜索、我喜欢、听歌模式、定时关闭。4×1 变成搜索条,点开可以直接粘贴分享链接。1×1 只留识曲。
识曲要用麦克风,只能在前台录音,所以点了会打开 App、弹出识曲面板并立刻开始听。定时关闭打开播放页的定时面板。
没在播放、从没播放过、封面还没下载完、定时关闭中、未登录、离线。每种都给一个能点的下一步,不出现空白卡片。
颜色角色和 App 相同,深浅跟 App 的主题设置走。主题是跟随系统时,MaterialKolor 按当前种子色生成浅色、深色两套一起交给桌面,由系统按深浅模式选;主题是浅色或深色时只交对应的一套。开了纯黑背景时,深色那套用纯黑方案。
表里的色值随预览栏的歌曲和配色变化。
原型用 OKLCH 近似 Material 色调,App 里是 MaterialKolor SPEC_2025,实际色值会略有不同。
| 用在哪 | 颜色角色 | 浅色 | 深色 |
|---|
外圆角用系统的 system_app_widget_background_radius,内部元素用 system_app_widget_inner_radius(Android 12 起)。更早的系统用 24dp / 12dp 的背景图。
4×2 及以上内边距 16dp,2×2 以下 12–14dp。所有按钮的点击区不小于 48dp,图标 20–24dp。
背景色叠 72% 不透明度。桌面组件不能做背景模糊,所以不提供毛玻璃。
Jetpack Glance 1.2,每款一个 GlanceAppWidget。下面是断点、刷新、点击三张表,以及开工前要先补的四项底层能力。
用 SizeMode.Exact,在 Composable 里按 LocalSize 选档。SizeMode.Responsive 每次更新要为每个尺寸各生成一份 RemoteViews,7 档就要带 7 份封面位图;播放组件刷新频繁,这笔开销不值得。
| 档位 | 最小尺寸 | 常见格数 | 内容 |
|---|
全部由事件推送,updatePeriodMillis 设为 0。PlaybackService 监听播放器事件,合并 300ms 内的连续变化后再调用 updateAll。
| 事件 | 更新哪些组件 | 做法 |
|---|---|---|
| 切歌 | 正在播放、歌词、歌单(高亮行) | 新封面按组件尺寸取图、裁形状,新种子色生成配色后一起推送 |
| 播放 / 暂停 | 正在播放、歌词、听歌模式 | 换播放图标,封面在形状和圆角方形之间切换,进度条在波浪和直线之间切换 |
| 播放进度 | 正在播放 2×3、4×2、4×3 | 时间文字用 Chronometer,系统自己走字。进度条只在亮屏且播放中时每 10 秒推一次,灭屏立即停 |
| 歌词换行 | 歌词、正在播放 4×3 | 和“系统媒体条歌词”共用当前行的计算;只在亮屏时推,两次之间至少隔 1.5 秒 |
| 收藏变化 | 正在播放(心形)、歌单(我喜欢) | 写入 saved_songs 的地方统一触发 |
| 外观设置 | 全部 | 外观页改主题、纯黑背景、配色来源、配色风格、对比度时触发。配色来源是系统壁纸时,换壁纸也要推(App 进程在时监听壁纸颜色变化) |
| 系统切换深浅 | 全部(仅 App 主题为跟随系统时) | Android 12 起由系统按夜间模式选色,不用推;Android 12 以下颜色在生成时就定了,要在 uiMode 变化后重推一次 |
| 榜单内容 | 榜单 | WorkManager 每 12 小时一次、需联网;打开 App 时顺带刷新。Glance 本身已依赖 WorkManager,不新增依赖 |
| 登录状态 | 听歌模式、榜单、歌单 | 账号页登录或退出后触发 |
| 定时关闭 | 正在播放 | 倒计时用 Chronometer 倒数(Android 7 起);Android 6 只显示到分钟,每分钟推一次 |
| 位置 | 动作 | 实现 |
|---|---|---|
| 播放、上一首、下一首 | 后台执行 | 和媒体通知的按钮走同一条路:向 PlaybackService 发媒体按键 Intent。点击组件属于用户交互,允许从后台启动前台服务 |
| 收藏 | 后台执行 | actionRunCallback 写库后刷新组件 |
| 榜单行、歌单行、听歌模式播放 | 后台起播 | actionRunCallback 带上歌单 ID 和序号,交给 Service 侧的起播命令 |
| 封面、标题、歌词 | 打开页面 | actionStartActivity 打开 MainActivity,extra 指定 player 或 lyrics |
| 搜索条、识曲、定时、去登录 | 打开页面 | 同上,extra 为 search、recognize、timer、login |
| 榜单标题、歌单标题 | 打开页面 | 同上,extra 为 chart 或 collection 加 ID |
onPlaybackResumption,进程被杀后点组件的播放键没有东西可放。要保存最后的队列、序号和进度,并实现这个回调;Android 13 起系统媒体控件的“继续播放”也靠它。Media3 1.11 在播放器为空时收到媒体按键是否会走这个回调,要真机确认。CoverStage 在界面里抽,App 没打开时组件拿不到。改成切歌时由播放层抽好,和歌曲一起保存,播放页和组件读同一个值。playCollection 在 MusicViewModel 里,组件点歌单行时 ViewModel 不一定存在。要挪到 Service 也能调用的仓库层。在 App 进程里用 Coil 按组件尺寸取图(coverAt(px),最大 480px),用 CoverShapes 的同一个多边形裁好再传给桌面。系统限制一份 RemoteViews 的位图总量不超过屏幕像素 × 4 × 1.5 字节,480px 的封面约 0.9MB,余量很大。
种子色和 App 取法相同(CoverSeedRepository、wallpaperSeed()、品牌色、自选颜色),用 MaterialKolor 按浏览页配色风格、对比度、纯黑背景生成。主题跟随系统时经 ColorProviders(light, dark) 传两套;主题固定时两个位置传同一套。不用系统动态色,免得组件和 App 的颜色对不上。
Glance 没有包装 Chronometer,用 AndroidRemoteViews 嵌一个 XML 布局,设置开始时间和是否在走。
Android 11 及以下用 previewImage 的 PNG;Android 12 起用 previewLayout;Android 15 起再提供实时生成的预览。
歌单、榜单、听歌模式、歌词有配置页,带默认值,添加时可以跳过;之后长按组件重新配置。配置页用 App 的主题。
每个按钮都写 contentDescription,播放键同时带状态(“暂停,正在播放”)。整块组件不加点击描述,免得读屏把按钮吞掉。
平板桌面的格子更大,用同一组断点,最大可拉到 5×4。Android TV 没有桌面小组件,电视端不做。
MIUI / HyperOS、ColorOS、OriginOS 对标准小组件的圆角、尺寸和刷新频率各有处理,收尾时要逐台真机看。
按依赖关系分组:后三组都建立在第一组的配色、取图和冷启动播放上。先做哪组不在这份方案里定。
onPlaybackResumption;当前形状挪到播放层;MainActivity 打开指定页面2026-10-31 确认,上面各节已经按这些改过。