Flutter颜色拾取插件simple_eye_dropper的使用
Flutter颜色拾取插件simple_eye_dropper的使用
Simple Eye Dropper
是一个依赖于标准库的简单颜色拾取小部件。
使用方法
使用asset图片
构建 EyeDropper
小部件的方法如下:
final byteData = await rootBundle.load('asset/example.png');
(snip)
EyeDropper.of(
// 编码后的Uint8List。
bytes: byteData.buffer.asUint8List(),
// 显示的大小。
size: const Size(200, 400),
// 当选择颜色时调用的回调。
onSelected: (color) => print('Selected color is $color'),
);
bytes
参数是一个通过image_picker
等方式获得的图像字节的 Uint8List。如果bytes
参数为 null,则会显示一个空白区域。onSelected
指定一个当颜色被选择时调用的回调。
指针
选择指针实现
默认情况下,使用带有放大功能的指针:
EyeDropper.of(
bytes: bytes,
size: const Size(200, 400),
// 默认情况。
pointerBuilder: MagnifierPointer.new,
onSelected: (color) => print('Selected color is $color'),
);
也可以指定一个简单的指针(不带放大功能):
EyeDropper.of(
bytes: bytes,
size: const Size(200, 400),
// 简单的小正方形指针,不带放大功能。
pointerBuilder: (_, __) => SimplePointer(),
onSelected: (color) => print('Selected color is $color'),
);
还可以使用圆形放大镜指针:
EyeDropper.of(
bytes: bytes,
size: const Size(200, 400),
pointerBuilder: CircularMagnifierPointer.new,
onSelected: (color) => print('Selected color is $color'),
);
这些指针都有多个参数,可以进行一些自定义设置:
EyeDropper.of(
bytes: bytes,
size: const Size(200, 400),
// 自定义指针,带有放大功能。
pointerBuilder: (uiImage, ratio) => MagnifierPointer(
uiImage,
ratio,
magnification: 2.5,
outerRectSize: 101,
outerStrokeWidth: 3,
innerRectSize: 9,
innerStrokeWidth: 3,
),
onSelected: (color) => print('Selected color is $color'),
);
实现指针
你也可以通过继承 Pointer
类来创建自己的指针。参考 CircleMagnifierPointer
类的代码来实现 Pointer
。
图像相关
支持的图像格式和错误处理
支持的图像格式类似于 dart:ui
中的 instantiateImageCodec
函数。至少支持以下图像格式:JPEG、PNG、GIF、Animated GIF、WebP、Animated WebP、BMP 和 WBMP。
当传递一个不受支持的图像格式的 Uint8List 给 bytes
时,将调用 errorBuilder
。errorBuilder
的使用方式与 Image.errorBuilder
相同。默认情况下,会显示一个灰色的错误图标。如果传递 null
给 bytes
,则会显示一个空白区域。
使用 image_picker
例如,你可以使用 image_picker
来选择图片:
final picker = ImagePicker();
final image = await picker.pickImage(source: ImageSource.gallery);
if(image == null) {
return;
}
final bytes = await image.readAsBytes();
(snip)
EyeDropper.of(
bytes: bytes,
size: const Size(200, 400),
onSelected: (color) => print('Selected color is $color'),
);
在实际应用中,你可能会使用 FutureBuilder
来支持异步操作。具体示例请参见 example/lib/main.dart。
使用网络图片
例如,如果你使用 http
包,可以这样做:
import 'package:http/http.dart' as http;
(snip)
final response = await http.get(Uri.parse('https://example.org/sample.jpg'));
(snip)
EyeDropper.of(
bytes: response.bodyBytes,
size: const Size(200, 400),
onSelected: (color) => print('Selected color is $color'),
);
只需将响应体直接传递给 bytes
。
使用Dart Image Library
如果你想传递一个经过 image
(Dart Image Library)处理过的图像到 EyeDropper
,可以按如下方式传递一个重新编码的 Uint8List:
import 'package:image/image.dart' as img;
(snip)
final imgImage = img.decodeImage(bytes);
final grayImage = img.grayscale(imgImage!);
grayBytes = img.encodeJpg(grayImage);
(snip)
EyeDropper.of(
bytes: grayBytes,
size: const Size(200, 400),
onSelected: (color) => print('Selected color is $color'),
);
使用 Riverpod
当 EyeDropper
与 Riverpod
的 ConsumerWidget
或 ConsumerStatefulWidget
一起使用时,由于指针会被完全重绘,可能会导致指针无法正确显示。
// 不好的例子。
import 'package:flutter_riverpod/flutter_riverpod.dart';
final colorProvider = StateProvider<Color>((ref) => Colors.white);
(snip)
class MyHomePage extends ConsumerWidget {
(snip)
// 显示颜色代码。
Text(ref.watch(colorProvider).toString()),
(snip)
}
在这种情况下,不要直接使用 ConsumerWidget
或 ConsumerStatefulWidget
的 ref
,而是使用 Consumer
来指定重绘范围。
// 好的例子。
import 'package:flutter_riverpod/flutter_riverpod.dart';
final colorProvider = StateProvider<Color>((ref) => Colors.white);
class MyHomePage extends ConsumerWidget {
(snip)
// 显示颜色代码。
Consumer(
builder: (_, ref, __) {
return Text(ref.watch(colorProvider).toString());
},
),
(snip)
}
完整示例
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:image_picker/image_picker.dart';
import 'package:simple_eye_dropper/simple_eye_dropper.dart';
/// 示例:Simple Eye Dropper 小部件。
///
/// 在iOS上使用时,需要在info.plist中添加以下设置:
/// <key>NSPhotoLibraryUsageDescription</key>
/// <string>此应用需要访问照片库。</string>
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
/// 图像显示区域占整个屏幕的比例。
static const imageAreaWidthRatio = 0.95;
static const imageAreaHeightRatio = 0.65;
[@override](/user/override)
Widget build(BuildContext context) {
return MaterialApp(
title: 'Eye Dropper',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: Builder(
builder: (context) {
// 图像的尺寸。
final screenSize = MediaQuery.of(context).size;
final imageAreaSize = Size(
screenSize.width * imageAreaWidthRatio,
screenSize.height * imageAreaHeightRatio,
);
return MyHomePage(title: 'Eye Dropper', imageAreaSize: imageAreaSize);
},
),
);
}
}
class MyHomePage extends StatelessWidget {
MyHomePage({super.key, required this.title, required this.imageAreaSize});
final String title;
final Size imageAreaSize;
final ValueNotifier<Uint8List?> _bytes = ValueNotifier(null);
final ValueNotifier<Color> _color = ValueNotifier(Colors.white);
[@override](/user/override)
Widget build(BuildContext context) {
// 如果发生错误,显示 SnackBar。
Object? vError;
WidgetsBinding.instance.addPostFrameCallback((_) {
if (vError != null) {
final snackBar = SnackBar(
behavior: SnackBarBehavior.floating,
content: Text('$vError'),
);
ScaffoldMessenger.of(context).showSnackBar(snackBar);
}
});
return Scaffold(
appBar: AppBar(
title: Text(title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
// 提取的颜色部分。
ValueListenableBuilder(
valueListenable: _color,
builder: (_, color, __) {
return Column(
children: [
// 选中颜色的样本。
CustomPaint(
size: const Size(50, 50),
painter: PickedPainter(color),
),
// 选中颜色的十六进制三元组。
Text(color.hexTriplet()),
],
);
},
),
// 从图像中提取颜色的部分。
ValueListenableBuilder(
valueListenable: _bytes,
builder: (_, bytes, __) {
// Eye dropper 实例化。
return EyeDropper.of(
bytes: bytes, // 原始图像字节。
size: imageAreaSize,
errorBuilder: (_, error, stackTrace) {
// print('$stackTrace');
vError = error;
return const Icon(
Icons.error,
color: Colors.black54,
);
},
// 颜色选择时的回调。
onSelected: (color) => _color.value = color,
);
},
),
ImagePickerButton(
onSelected: (bytes) => _bytes.value = bytes,
),
],
),
),
);
}
}
/// 用于从相册中选择图像的按钮。
class ImagePickerButton extends StatelessWidget {
const ImagePickerButton({super.key, required this.onSelected});
/// 图像选择时的回调。
final ValueChanged<Uint8List> onSelected;
[@override](/user/override)
Widget build(BuildContext context) {
return ElevatedButton(
onPressed: selectImage,
child: const Text('Select Image'),
);
}
Future<void> selectImage() async {
final picker = ImagePicker();
final image = await picker.pickImage(source: ImageSource.gallery);
if (image == null) {
return;
}
final bytes = await image.readAsBytes();
onSelected(bytes);
}
}
/// 显示指定颜色。
[@immutable](/user/immutable)
class PickedPainter extends CustomPainter {
const PickedPainter(this.color);
static const double rectSize = 50;
final Color color;
[@override](/user/override)
void paint(Canvas canvas, Size size) {
final paint = Paint();
const rect = Rect.fromLTWH(0, 0, rectSize, rectSize);
paint
..color = color
..style = PaintingStyle.fill;
canvas.drawRect(rect, paint);
}
[@override](/user/override)
bool shouldRepaint(covariant CustomPainter oldDelegate) {
return true;
}
}
/// 显示十六进制三元组,如#FFFFFF。
extension HexTriplet on Color {
String hexTriplet() {
return '#${value.toRadixString(16).padLeft(8, '0').substring(2, 8).toUpperCase()}';
}
}
更多关于Flutter颜色拾取插件simple_eye_dropper的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html
更多关于Flutter颜色拾取插件simple_eye_dropper的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
simple_eye_dropper
是一个用于 Flutter 的简单颜色拾取插件。它允许用户从屏幕上选择颜色,并将其返回给应用程序。以下是如何在 Flutter 项目中使用 simple_eye_dropper
插件的步骤。
1. 添加依赖
首先,在 pubspec.yaml
文件中添加 simple_eye_dropper
依赖:
dependencies:
flutter:
sdk: flutter
simple_eye_dropper: ^1.0.0 # 请使用最新版本
然后运行 flutter pub get
来获取依赖。
2. 导入包
在需要使用颜色拾取功能的 Dart 文件中导入 simple_eye_dropper
包:
import 'package:simple_eye_dropper/simple_eye_dropper.dart';
3. 使用颜色拾取器
你可以通过调用 SimpleEyeDropper.pickColor()
方法来启动颜色拾取器。该方法将返回一个 Future<Color?>
,表示用户选择的颜色。
以下是一个简单的示例,展示如何在按钮点击时启动颜色拾取器,并将选择的颜色应用到某个 Widget 的背景色上:
import 'package:flutter/material.dart';
import 'package:simple_eye_dropper/simple_eye_dropper.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
[@override](/user/override)
Widget build(BuildContext context) {
return MaterialApp(
home: ColorPickerDemo(),
);
}
}
class ColorPickerDemo extends StatefulWidget {
[@override](/user/override)
_ColorPickerDemoState createState() => _ColorPickerDemoState();
}
class _ColorPickerDemoState extends State<ColorPickerDemo> {
Color? _selectedColor;
Future<void> _pickColor() async {
final Color? color = await SimpleEyeDropper.pickColor();
if (color != null) {
setState(() {
_selectedColor = color;
});
}
}
[@override](/user/override)
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Color Picker Demo'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Container(
width: 100,
height: 100,
color: _selectedColor ?? Colors.grey,
),
SizedBox(height: 20),
ElevatedButton(
onPressed: _pickColor,
child: Text('Pick Color'),
),
],
),
),
);
}
}