Flutter 知识集锦 | 如何得到图片主色

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,我们可以从一张图片中自动提取主色,生成整套主题配色方案。这种方式不仅大大提升了配色效率,也让界面风格更具灵活性与视觉美感。

本文围绕这一特性,构建了一个完整的图片主题色提取案例。通过封装 ImageSelectorImageDisplayItem 两个组件,我们实现了一个支持左右联动、动态切换图片与配色的主题演示界面。每次点击图片,即可自动提取对应主色,并即时刷新界面主题色彩,呈现出与图片风格相匹配的 UI 效果。

这种"图片驱动主题"的方式,特别适合用于美化工具、主题换肤、个性化主页等场景。未来,也可以进一步结合用户上传图片、自定义调色板等功能,打造更智能、更富创意的配色系统。


更多文章和视频知识资讯,大家可以关注我的公众号、掘金和 B 站 。

相关推荐
_无_妄_1 分钟前
Android 使用 WebView 直接加载 PDF 文件,通过 JS 实现
android
VomPom5 分钟前
手写一个精简版Koin:深入理解依赖注入核心原理
android
君赏12 分钟前
Petrel(雨燕)Flutter 热更新如何在我们项目应用
flutter
IT乐手16 分钟前
Java 编写查看调用栈信息
android
Digitally2 小时前
如何轻松永久删除 Android 手机上的短信
android·智能手机
JulyYu2 小时前
Flutter混合栈适配安卓ActivityResult
android·flutter
Warren982 小时前
Appium学习笔记
android·windows·spring boot·笔记·后端·学习·appium
Kapaseker3 小时前
Compose 文本适配天花板?BasicText 自动调大小实战
android·kotlin
海的天空16616 小时前
Flutter旧版本升级-> Android 配置、iOS配置
android·flutter·ios
小蜜蜂嗡嗡6 小时前
【flutter对屏幕底部有手势区域(如:一条横杠)导致出现重叠遮挡】
前端·javascript·flutter