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 站 。

相关推荐
MaoJiu18 分钟前
Flutter与原生端的通信
flutter·ios
刺客xs2 小时前
MYSQL数据库----DCL语句
android·数据库·mysql
iReaShare2 小时前
如何将数据从一部手机传输到另一部手机?
android
慢行的骑兵2 小时前
Android音视频探索之旅 | C++层使用OpenGL ES实现视频渲染
android·音视频·ndk
iReaShare3 小时前
将CSV联系人导入安卓手机的3种简单方法
android
whysqwhw4 小时前
Okttp之unixdomainsockets模块分析
android
非凡ghost4 小时前
Android System WebView:Android生态的核心组件
android
潇凝子潇5 小时前
MySQL 的 `EXPLAIN` 输出中,`filtered` 属性使用
android·数据库·mysql
fengye2071615 小时前
板凳-------Mysql cookbook学习 (十一--------9)
android·学习·mysql