Flutter颜色提取插件color_extract的使用

Flutter颜色提取插件color_extract的使用

预览

(视频播放器可能在pub.dev上无法显示,请查看GitHub)

示例

在此示例中,您可以看到如何让您的小部件像变色龙一样改变颜色。

安装

将以下内容添加到您的pubspec.yaml文件中:

dependencies:
  color_extract: ^1.0.1

然后运行flutter pub get

使用

ColorExtractor

ColorExtractor是一个用于从应用的小部件中提取平均颜色的包装器。它可以用作RepaintBoundary的替代品。

ColorExtractor(
  boundaryKey: GlobalKey(),
  child: Container(
    width: 200,
    height: 200,
    color: Colors.red,
  ),
);

ColorAverager

ColorAverager小部件计算特定部分的平均颜色,可以是从ColorExtractorRepaintBoundary获取的颜色。它适用于确定某个区域的主色调,例如背景图像后的颜色。

ColorAverager(
  boundaryKey: GlobalKey(),
  child: SizedBox(
    width: 50,
    height: 50,
  ),
  onChanged: (color) {
    // 处理新的平均颜色。
  },
);

您也可以使用ColorAveragerController来编程计算平均颜色。

final controller = ColorAveragerController();

// ... 渲染小部件 ...

final avgColor = await controller.calculateAvgColor();

示例代码

下面是一个完整的示例代码,展示了如何使用color_extract插件。

import 'dart:math';

import 'package:color_extract/color_extract.dart';
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter/scheduler.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  [@override](/user/override)
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: const MyHomePage(),
    );
  }
}

class PosColor {
  Offset offset;
  Size size;
  Color color;

  PosColor({
    required this.offset,
    required this.size,
    required this.color,
  });
}

List<PosColor> generatePosColors() {
  List<PosColor> posColors = [];
  final random = Random();

  for (int i = 0; i < 20; i++) {
    double width = random.nextDouble() * 200 + 100;
    double height = random.nextDouble() * 200 + 100;
    double x = random.nextDouble() * 300 + 50;
    double y = random.nextDouble() * 800 + 50;

    posColors.add(
      PosColor(
        offset: Offset(x, y),
        size: Size(width, height),
        color: getRandomColor(),
      ),
    );
  }

  for (int i = 0; i < 5; i++) {
    double size = random.nextDouble() * 100 + 50;
    double x = 250 - size / 2;
    double y = 400 - size / 2;

    posColors.add(
      PosColor(
        offset: Offset(x, y),
        size: Size(size, size),
        color: Colors.white,
      ),
    );
  }

  for (int i = 0; i < 5; i++) {
    double size = random.nextDouble() * 100 + 50;
    double x = 250 - size / 2;
    double y = 550 - size / 2;

    posColors.add(
      PosColor(
        offset: Offset(x, y),
        size: Size(size, size),
        color: Colors.black,
      ),
    );
  }
  for (int i = 0; i < 20; i++) {
    double width = random.nextDouble() * 200 + 100;
    double height = random.nextDouble() * 200 + 100;
    double x = random.nextDouble() * 300 + 50;
    double y = random.nextDouble() * 800 + 600;

    posColors.add(
      PosColor(
        offset: Offset(x, y),
        size: Size(width, height),
        color: getRandomColor(),
      ),
    );
  }

  return posColors;
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({super.key});

  [@override](/user/override)
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  final boundaryKey = GlobalKey();
  final _scrollController = ScrollController();
  final _controller = ColorAveragerController();

  final recsInfo = ValueNotifier(generatePosColors());
  final draggableInfo = ValueNotifier(
    PosColor(
        offset: const Offset(30, 30),
        color: Colors.blue,
        size: const Size(50, 50)),
  );

  Future<Color> calcAvgColor([bool reverse = false]) async {
    var color = (await _controller.calculateAvgColor()) ?? Colors.blue;
    if (reverse) color = color.reverse;
    return color;
  }

  bool isReversedColor = false;

  [@override](/user/override)
  void initState() {
    _scrollController.addListener(() {
      if (_scrollController.hasClients) {
        if (_scrollController.position.userScrollDirection != ScrollDirection.idle) {
          SchedulerBinding.instance.addPostFrameCallback((_) {
            _controller.calculateAvgColor();
          });
        }
      }
    });

    super.initState();
  }

  [@override](/user/override)
  Widget build(BuildContext context) {
    return Scaffold(
      body: Stack(
        children: [
          ColorExtractor(
            boundaryKey: boundaryKey,
            child: SingleChildScrollView(
              controller: _scrollController,
              child: SizedBox(
                height: 2000,
                child: Stack(
                    children: recsInfo.value
                        .map((posColor) => Positioned(
                              left: posColor.offset.dx,
                              top: posColor.offset.dy,
                              child: Container(
                                width: posColor.size.width,
                                height: posColor.size.height,
                                color: posColor.color,
                              ),
                            ))
                        .toList()),
              ),
            ),
          ),
          ValueListenableBuilder(
            valueListenable: draggableInfo,
            builder: (_, __, ___) {
              return Positioned(
                left: draggableInfo.value.offset.dx,
                top: draggableInfo.value.offset.dy,
                child: Draggable(
                  feedback: Opacity(
                    opacity: 0.6,
                    child: Container(
                      width: draggableInfo.value.size.width,
                      height: draggableInfo.value.size.height,
                      decoration: BoxDecoration(
                        color: draggableInfo.value.color,
                        borderRadius: BorderRadius.circular(8),
                        border: Border.all(color: Colors.grey.withOpacity(0.4)),
                      ),
                    ),
                  ),
                  onDragEnd: (dragDetails) async {
                    draggableInfo.value = PosColor(
                      color: await calcAvgColor(isReversedColor),
                      offset: Offset(
                        dragDetails.offset.dx,
                        dragDetails.offset.dy - MediaQuery.of(context).padding.top,
                      ),
                      size: draggableInfo.value.size,
                    );
                    WidgetsBinding.instance.addPostFrameCallback((_) async {
                      draggableInfo.value = PosColor(
                        color: await calcAvgColor(isReversedColor),
                        offset: Offset(
                          dragDetails.offset.dx,
                          dragDetails.offset.dy - MediaQuery.of(context).padding.top,
                        ),
                        size: draggableInfo.value.size,
                      );
                    });
                  },
                  child: ColorAverager(
                    boundaryKey: boundaryKey,
                    controller: _controller,
                    fillerColor: Theme.of(context).scaffoldBackgroundColor,
                    child: AnimatedContainer(
                      duration: const Duration(milliseconds: 300),
                      width: draggableInfo.value.size.width,
                      height: draggableInfo.value.size.height,
                      decoration: BoxDecoration(
                        color: draggableInfo.value.color,
                        borderRadius: BorderRadius.circular(8),
                        border: Border.all(color: Colors.grey.withOpacity(0.4)),
                      ),
                    ),
                    onChanged: (value) {
                      // debugPrint('value $value');
                      final color = value ?? Colors.blue;
                      draggableInfo.value = PosColor(
                        color: isReversedColor ? color.reverse : color,
                        offset: draggableInfo.value.offset,
                        size: draggableInfo.value.size,
                      );
                    },
                  ),
                ),
              );
            },
          ),
          Positioned(
              bottom: 0,
              left: 0,
              right: 0,
              child: ColoredBox(
                color: Theme.of(context).scaffoldBackgroundColor.withOpacity(0.8),
                child: CheckboxListTile(
                  controlAffinity: ListTileControlAffinity.trailing,
                  title: const Text('反转颜色'),
                  value: isReversedColor,
                  onChanged: (_) {
                    setState(() {
                      isReversedColor = !isReversedColor;
                      WidgetsBinding.instance.addPostFrameCallback((_) async {
                        draggableInfo.value = PosColor(
                          color: await calcAvgColor(isReversedColor),
                          offset: draggableInfo.value.offset,
                          size: draggableInfo.value.size,
                        );
                      });
                    });
                  },
                ),
              ))
        ],
      ),
    );
  }
}

更多关于Flutter颜色提取插件color_extract的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter颜色提取插件color_extract的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,以下是如何在Flutter项目中使用color_extract插件来提取图像颜色的示例代码。这个插件可以帮助你从图像中提取主要颜色。

1. 添加依赖

首先,你需要在pubspec.yaml文件中添加color_extract依赖:

dependencies:
  flutter:
    sdk: flutter
  color_extract: ^0.1.4  # 请检查最新版本号

然后运行以下命令来安装依赖:

flutter pub get

2. 导入插件

在你的Dart文件中(例如main.dart),导入color_extract插件:

import 'package:color_extract/color_extract.dart';

3. 提取颜色

以下是一个完整的示例,展示如何从图像中提取颜色:

import 'package:flutter/material.dart';
import 'package:color_extract/color_extract.dart';
import 'dart:ui' as ui;
import 'dart:typed_data';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('Color Extract Example'),
        ),
        body: ColorExtractExample(),
      ),
    );
  }
}

class ColorExtractExample extends StatefulWidget {
  @override
  _ColorExtractExampleState createState() => _ColorExtractExampleState();
}

class _ColorExtractExampleState extends State<ColorExtractExample> {
  List<ui.Color> colors = [];

  @override
  void initState() {
    super.initState();
    _extractColors();
  }

  Future<void> _extractColors() async {
    // 加载图像数据(这里使用了一个本地图像路径,你可以使用网络图像)
    final ByteData byteData = await rootBundle.load('assets/sample_image.jpg');
    Uint8List list = byteData.buffer.asUint8List();

    // 创建图像对象
    final ui.Image image = await decodeImageFromList(list);

    // 使用ColorExtract提取颜色
    final List<ui.Color> extractedColors = await ColorExtract.extractColors(image, 5); // 提取5个主要颜色

    // 更新状态
    setState(() {
      colors = extractedColors;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Padding(
      padding: const EdgeInsets.all(16.0),
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          Text('Extracted Colors:', style: TextStyle(fontSize: 20)),
          SizedBox(height: 16),
          ...colors.map((color) => ColorSwatchWidget(color: color)),
        ],
      ),
    );
  }
}

class ColorSwatchWidget extends StatelessWidget {
  final ui.Color color;

  ColorSwatchWidget({required this.color});

  @override
  Widget build(BuildContext context) {
    return Container(
      decoration: BoxDecoration(
        color: color,
        borderRadius: BorderRadius.circular(8),
      ),
      width: 50,
      height: 50,
      margin: EdgeInsets.symmetric(vertical: 8),
    );
  }
}

4. 添加图像资源

确保在pubspec.yaml文件中添加了图像资源:

flutter:
  assets:
    - assets/sample_image.jpg

并将图像文件sample_image.jpg放在assets文件夹中。

5. 运行应用

现在,你可以运行你的Flutter应用,并看到从图像中提取的主要颜色显示在屏幕上。

注意事项

  1. 确保color_extract插件的版本是最新的,以避免兼容性问题。
  2. 提取颜色的数量(在上述示例中为5)可以根据需要进行调整。
  3. 你可以根据需要自定义ColorSwatchWidget以更好地显示颜色。

这样,你就成功地使用color_extract插件在Flutter项目中提取图像颜色了。

回到顶部