1.缘起
在查看 ColorScheme 源码时,发现了一个有意思的静态方法 fromImageProvider
: 如下所示,其中传入一个 ImageProvider 对象,顾名思义是通过一个图片来获取主色,然后生成 ColorScheme 主题色对象 :

在上一篇中:《 Flutter 百题斩#14 | 说说你对 ColorScheme 的了解》 中做过一个 ColorScheme 色系的展示效果。本文就基于这个案例,实现一个从图片中取出主题色的功能,并通过左侧面板展示色彩效果。如下所示:

2. 图片资源切换
右侧图片列表选择器,可以独立封装一个 ImageSelector
,其中传入 images
图片列表、激活索引。并通过 onIndexChange
回调通知外界选择图片变化的时机:
dart
import 'package:flutter/material.dart';
class ImageSelector extends StatelessWidget {
final List<ImageProvider> images;
final int? activeIndex;
final Color indicatorColor;
final ValueChanged<int> onIndexChange;
const ImageSelector({
super.key,
required this.images,
required this.onIndexChange,
required this.activeIndex,
required this.indicatorColor,
});
@override
Widget build(BuildContext context) {
return ListView.builder(
itemBuilder: _buildItem,
itemExtent: 86,
itemCount: images.length,
);
}
Widget? _buildItem(BuildContext context, int index) {
bool active = activeIndex == index;
Color color = active ? indicatorColor : Colors.transparent;
ImageProvider image = images[index];
return GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: () => onIndexChange(index),
child: ImageDisplayItem(image: image, activeColor: color),
);
}
}
其中单个图片的展示,可以封装一个 ImageDisplayItem
组件,条目分为激活和非激活状态:
- 激活的条目如左图:两侧有图片对应的主色色块,以及圆角边框。
- 非激活的图片不展示边框
激活 | 非激活 |
---|---|
![]() |
![]() |
dart
class ImageDisplayItem extends StatelessWidget {
final ImageProvider image;
final Color activeColor;
const ImageDisplayItem({
super.key,
required this.image,
required this.activeColor,
});
@override
Widget build(BuildContext context) {
BorderRadius radius = BorderRadius.circular(6);
Border border = Border.all(color: activeColor, width: 2);
return Row(
spacing: 4,
children: [
buildIndicator(color: activeColor),
Container(
height: 80,
padding: EdgeInsets.all(1),
decoration: BoxDecoration(borderRadius: radius, border: border),
child: ClipRRect(
borderRadius: radius,
child: Image(image: image, height: 80),
),
),
buildIndicator(color: activeColor),
],
);
}
Widget buildIndicator({Color? color}){
return Container(
height: 80,
width: 6,
decoration: BoxDecoration(
color: color,
borderRadius: BorderRadius.circular(2),
));
}
}
3. 使用图片切换器
当 ImageSelector
组件封装完毕,就可以将其放在界面中,比如这里放在界面右侧。测试案例中,使用 AssetImage
将图片资源放在 assets
中:

dart
List<ImageProvider> get assetsImage => [
'assets/images/2.jpg',
'assets/images/1.jpg',
'assets/images/3.webp',
'assets/images/3.jpg',
'assets/images/4.webp',
'assets/images/5.png',
].map((e) => AssetImage(e)).toList();
int? _activeIndex;
Widget buildImageSelector(){
return Container(
width: 108,
padding: EdgeInsets.only(right: 8, top: 8),
child: ImageSelector(
images: assetsImage,
indicatorColor: scheme.primary,
onIndexChange: _onImageChange,
activeIndex: _activeIndex,
));
}
在点击图片时回调 _onImageChange
函数,在其中可以通过 ColorScheme.fromImageProvider
根据激活的图片提供器,创建 ColorScheme 对象。然后将这个 scheme
对象设置到主题上,就可以影响配色全局效果:

ini
void _onImageChange(int index) async {
setState(() {
_activeIndex = index;
});
ImageProvider image = assetsImage[index];
ColorScheme scheme = await ColorScheme.fromImageProvider(provider: image);
_activeColor = scheme.primary;
_scheme = scheme;
setState(() {});
}
4. 小结
在 Flutter 的 UI 设计中,ColorScheme
是构建一致且现代化配色体系的重要工具。而通过 ColorScheme.fromImageProvider
,我们可以从一张图片中自动提取主色,生成整套主题配色方案。这种方式不仅大大提升了配色效率,也让界面风格更具灵活性与视觉美感。
本文围绕这一特性,构建了一个完整的图片主题色提取案例。通过封装 ImageSelector
和 ImageDisplayItem
两个组件,我们实现了一个支持左右联动、动态切换图片与配色的主题演示界面。每次点击图片,即可自动提取对应主色,并即时刷新界面主题色彩,呈现出与图片风格相匹配的 UI 效果。
这种"图片驱动主题"的方式,特别适合用于美化工具、主题换肤、个性化主页等场景。未来,也可以进一步结合用户上传图片、自定义调色板等功能,打造更智能、更富创意的配色系统。
更多文章和视频知识资讯,大家可以关注我的公众号、掘金和 B 站 。