Flutter颜色选择插件okcolor的使用
Flutter颜色选择插件OkColor的使用
OkColor
OkColor 是一个用于处理感知均匀颜色空间的 Flutter 包,基于 Björn Ottosson 的开创性工作。OkColor 提供了强大的颜色操作、转换和分析工具。
特性
- 支持感知均匀颜色空间:OkLab、OkLCH、OkHSV 和 OkHSL。
- 无缝的颜色转换:可以在 RGB、HSV、HSL 和 Ok* 颜色空间之间转换。
- 高级颜色操作:亮度调整、饱和度调整等。
- 生成和谐的颜色调色板和平滑的渐变。
- 色彩校正功能:包括色彩映射和裁剪功能。
开始使用
在 pubspec.yaml
文件中添加 okcolor
依赖:
dependencies:
okcolor: ^1.0.1
然后运行 flutter pub get
。
使用方法
颜色扩展
OkColor 扩展了 Flutter 的 Color
类,提供了便捷的方法:
import 'package:flutter/material.dart';
import 'package:okcolor/okcolor.dart';
void main() {
Color color = Colors.blue;
// 转换到不同的颜色空间
OkLab oklab = color.toOkLab();
OkLch oklch = color.toOkLch();
OkHsv okhsv = color.toOkHsv();
OkHsl okhsl = color.toOkHsl();
// 颜色操作
Color darkerColor = color.darker(0.2);
Color lighterColor = color.lighter(0.2);
Color saturatedColor = color.saturate(0.2);
Color desaturatedColor = color.desaturate(0.2);
Color rotatedColor = color.rotated(45);
Color complementaryColor = color.complementary();
// 生成颜色谐波
List<Color> splitComplementaryColors = color.splitComplementary();
List<Color> triadicColors = color.triadic();
List<Color> tetradicColors = color.tetradic();
List<Color> analogousColors = color.analogous(count: 3);
List<Color> shades = color.shades(count: 5);
List<Color> tints = color.tints(count: 5);
}
颜色模型
OkColor 提供了四种主要的颜色模型:
- OkLab:感知均匀的亮度、a 和 b 通道。
- OkLch:感知均匀的亮度、色度和色调。
- OkHsv:感知均匀的色调、饱和度和值。
- OkHsl:感知均匀的色调、饱和度和亮度。
每个模型都有其特有的操作方法和转换方法。
转换器
OkColor 包含了各种颜色空间之间的转换器:
import 'package:okcolor/okcolor.dart';
void main() {
// RGB 到 OkLab
OkLab oklab = rgbToOkLab(RGB(1.0, 0.5, 0.2));
// OkLab 到 RGB
RGB rgb = okLabToRgb(OkLab(0.7, 0.2, -0.1));
// OkLab 到 OkLCH
OkLch oklch = labToLch(OkLab(0.7, 0.2, -0.1));
// OkLCH 到 OkLab
OkLab oklab2 = lchToLab(OkLch(0.7, 0.2, 1.5));
// RGB 到 OkHSV
OkHsv okhsv = rgbToOkhsv(RGB(1.0, 0.5, 0.2));
// OkHSV 到 RGB
RGB rgb2 = okhsvToRgb(OkHsv(0.1, 0.8, 0.9));
// 类似的转换器存在其他颜色空间组合
}
对于更多详细示例和高级用法,请参阅 API 文档。
案例演示
以下是一个完整的示例代码,展示了如何使用 OkColor 进行颜色选择和操作:
import 'package:example/color_wheel.dart';
import 'package:flutter/material.dart';
import 'package:flutter_colorpicker/flutter_colorpicker.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:okcolor/models/extensions.dart';
import 'package:okcolor/models/okcolor.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatefulWidget {
const MyApp({super.key});
[@override](/user/override)
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
int index = 0;
[@override](/user/override)
Widget build(BuildContext context) {
return MaterialApp(
title: 'OkColor Demo',
theme: ThemeData(
textTheme: GoogleFonts.interTextTheme().copyWith(),
sliderTheme: const SliderThemeData(
activeTrackColor: Colors.black,
inactiveTrackColor: Colors.black12,
thumbColor: Colors.black,
trackHeight: 5,
),
switchTheme: SwitchThemeData(
thumbColor: WidgetStateProperty.all(Colors.black),
trackColor: WidgetStateProperty.all(Colors.black12),
),
),
home: Scaffold(
bottomNavigationBar: BottomNavigationBar(
items: const [
BottomNavigationBarItem(icon: Icon(Icons.gradient), label: 'Gradient'),
BottomNavigationBarItem(icon: Icon(Icons.color_lens), label: 'Harmonies'),
],
onTap: (value) {
setState(() {
index = value;
});
},
),
body: [
const Gradient(),
const Harmonies(),
][index],
),
);
}
}
class Harmonies extends StatefulWidget {
const Harmonies({super.key});
[@override](/user/override)
State<Harmonies> createState() => _HarmoniesState();
}
class _HarmoniesState extends State<Harmonies> {
Color color = const Color(0xff0000ff);
double darker = 0;
double lighter = 0;
double saturated = 0;
double desaturated = 0;
double rotation = 0;
[@override](/user/override)
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
appBar: AppBar(
title: const Text('Color harmonies'),
),
body: SafeArea(
child: SingleChildScrollView(
padding: const EdgeInsets.all(16),
child: Column(
children: [
AnimatedContainer(
duration: const Duration(milliseconds: 300),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(24),
border: Border.all(color: color.darker(0.2), width: 1),
color: color,
),
child: ClipRRect(
borderRadius: BorderRadius.circular(24),
child: Material(
color: Colors.transparent,
child: InkWell(
onTap: () {
showModalBottomSheet(
context: context,
builder: (context) {
return ColorPicker(
pickerColor: color,
onColorChanged: (color) {
setState(() {
this.color = color;
});
},
);
},
);
},
child: const SizedBox(
height: 120,
width: double.infinity,
),
),
),
),
),
const SizedBox(height: 16),
Text("Lightness", style: GoogleFonts.rubik(fontSize: 18, fontWeight: FontWeight.w500, letterSpacing: -0.25)),
const SizedBox(height: 16),
Row(
children: [
Expanded(
child: Column(
children: [
AspectRatio(
aspectRatio: 1,
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(12),
color: color.darker(darker),
),
width: double.infinity,
),
),
const SizedBox(height: 8),
Text('Darker', style: GoogleFonts.rubik(fontSize: 16, fontWeight: FontWeight.w500, letterSpacing: -0.25)),
const SizedBox(height: 8),
Slider(
value: darker,
onChanged: (value) {
setState(() {
darker = value;
});
},
),
],
),
),
const SizedBox(width: 16),
Expanded(
child: Column(
children: [
AspectRatio(
aspectRatio: 1,
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(12),
color: color.lighter(lighter),
),
width: double.infinity,
),
),
const SizedBox(height: 8),
Text('Lighter', style: GoogleFonts.rubik(fontSize: 16, fontWeight: FontWeight.w500, letterSpacing: -0.25)),
const SizedBox(height: 8),
Slider(
value: lighter,
onChanged: (value) {
setState(() {
lighter = value;
});
},
),
],
),
),
],
),
const SizedBox(height: 16),
Text("Saturation", style: GoogleFonts.rubik(fontSize: 18, fontWeight: FontWeight.w500, letterSpacing: -0.25)),
const SizedBox(height: 16),
Row(
children: [
Expanded(
child: Column(
children: [
AspectRatio(
aspectRatio: 1,
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(12),
color: color.saturate(saturated),
),
width: double.infinity,
),
),
const SizedBox(height: 8),
Text('Saturated', style: GoogleFonts.rubik(fontSize: 16, fontWeight: FontWeight.w500, letterSpacing: -0.25)),
const SizedBox(height: 8),
Slider(
value: saturated,
onChanged: (value) {
setState(() {
saturated = value;
});
},
),
],
),
),
const SizedBox(width: 16),
Expanded(
child: Column(
children: [
AspectRatio(
aspectRatio: 1,
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(12),
color: color.desaturate(desaturated),
),
width: double.infinity,
),
),
const SizedBox(height: 8),
Text('Desaturated', style: GoogleFonts.rubik(fontSize: 16, fontWeight: FontWeight.w500, letterSpacing: -0.25)),
const SizedBox(height: 8),
Slider(
value: desaturated,
onChanged: (value) {
setState(() {
desaturated = value;
});
},
),
],
),
),
],
),
const SizedBox(height: 16),
Text("Hues", style: GoogleFonts.rubik(fontSize: 18, fontWeight: FontWeight.w500, letterSpacing: -0.25)),
const SizedBox(height: 16),
Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Expanded(
child: Column(
children: [
AspectRatio(
aspectRatio: 1,
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(12),
color: color.rotated(rotation * 360),
),
width: double.infinity,
),
),
const SizedBox(height: 8),
Text('Rotated', style: GoogleFonts.rubik(fontSize: 16, fontWeight: FontWeight.w500, letterSpacing: -0.25)),
const SizedBox(height: 8),
Slider(
value: rotation,
onChanged: (value) {
setState(() {
rotation = value;
});
},
),
],
),
),
const SizedBox(width: 16),
Expanded(
child: Column(
children: [
AspectRatio(
aspectRatio: 1,
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(12),
color: color.rotated(rotation * 360).complementary(),
),
width: double.infinity,
),
),
const SizedBox(height: 8),
Text('Complementary', style: GoogleFonts.rubik(fontSize: 16, fontWeight: FontWeight.w500, letterSpacing: -0.25)),
],
),
),
],
),
const SizedBox(height: 16),
Text("Split complementary", style: GoogleFonts.rubik(fontSize: 18, fontWeight: FontWeight.w500, letterSpacing: -0.25)),
const SizedBox(height: 16),
Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: color.rotated(rotation * 360).splitComplementary().map((c) {
return Expanded(
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 8),
child: AspectRatio(
aspectRatio: 1,
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(12),
color: c,
),
width: double.infinity,
),
),
),
);
}).toList(),
),
const SizedBox(height: 16),
Text("Triadic", style: GoogleFonts.rubik(fontSize: 18, fontWeight: FontWeight.w500, letterSpacing: -0.25)),
const SizedBox(height: 16),
Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: color.rotated(rotation * 360).triadic().map((c) {
return Expanded(
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 8),
child: AspectRatio(
aspectRatio: 1,
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(12),
color: c,
),
width: double.infinity,
),
),
),
);
}).toList(),
),
const SizedBox(height: 16),
Text("Tetradic", style: GoogleFonts.rubik(fontSize: 18, fontWeight: FontWeight.w500, letterSpacing: -0.25)),
const SizedBox(height: 16),
Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: color.rotated(rotation * 360).tetradic().map((c) {
return Expanded(
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 8),
child: AspectRatio(
aspectRatio: 1,
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(12),
color: c,
),
width: double.infinity,
),
),
),
);
}).toList(),
),
const SizedBox(height: 16),
Text("Analogous", style: GoogleFonts.rubik(fontSize: 18, fontWeight: FontWeight.w500, letterSpacing: -0.25)),
const SizedBox(height: 16),
Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: color.rotated(rotation * 360).analogous().map((c) {
return Expanded(
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 8),
child: AspectRatio(
aspectRatio: 1,
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(12),
color: c,
),
width: double.infinity,
),
),
),
);
}).toList(),
),
const SizedBox(height: 16),
Text("Shades", style: GoogleFonts.rubik(fontSize: 18, fontWeight: FontWeight.w500, letterSpacing: -0.25)),
const SizedBox(height: 16),
Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: color.rotated(rotation * 360).shades().map((c) {
return Expanded(
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 8),
child: AspectRatio(
aspectRatio: 1,
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(12),
color: c,
),
width: double.infinity,
),
),
),
);
}).toList(),
),
const SizedBox(height: 16),
Text("Tints", style: GoogleFonts.rubik(fontSize: 18, fontWeight: FontWeight.w500, letterSpacing: -0.25)),
const SizedBox(height: 16),
Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: color.rotated(rotation * 360).tints().map((c) {
return Expanded(
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 8),
child: AspectRatio(
aspectRatio: 1,
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(12),
color: c,
),
width: double.infinity,
),
),
),
);
}).toList(),
),
],
),
),
),
);
}
}
class Gradient extends StatefulWidget {
const Gradient({super.key});
[@override](/user/override)
State<Gradient> createState() => _GradientState();
}
class _GradientState extends State<Gradient> {
Color startColor = const Color(0xffffffff);
Color endColor = const Color(0xff0000ff);
int numberOfColors = 20;
bool shortest = true;
Widget _buildControls() {
return Column(
children: [
Row(
children: [
Text(
'Number of colors',
style: GoogleFonts.rubik(fontSize: 18, fontWeight: FontWeight.w500, letterSpacing: -0.25),
),
Expanded(
child: Slider(
value: numberOfColors.toDouble(),
min: 5,
max: 30,
divisions: 25,
label: numberOfColors.toString(),
onChanged: (value) {
setState(() {
numberOfColors = value.toInt();
});
},
activeColor: Colors.black,
inactiveColor: Colors.black12,
),
),
],
),
],
);
}
Widget _buildGradient(String title, List<Color> colors) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
title,
style: GoogleFonts.rubik(fontSize: 18, fontWeight: FontWeight.w500, letterSpacing: -0.25),
),
const SizedBox(height: 8),
AnimatedContainer(
duration: Durations.short4,
width: double.infinity,
height: 64,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(14),
border: Border.all(color: Colors.black12, width: 1),
gradient: LinearGradient(
colors: colors,
),
),
),
],
);
}
Widget _buildColorWheel() {
return Column(
children: [
Text(
'Color Wheel',
style: GoogleFonts.rubik(fontSize: 18, fontWeight: FontWeight.w500, letterSpacing: -0.25),
),
AspectRatio(
aspectRatio: 1,
child: Transform.flip(
flipY: true,
child: HSVColorWheel(
gradientColors: OkColor.gradient(startColor, endColor, numberOfColors: numberOfColors, method: InterpolationMethod.oklch),
),
),
),
],
);
}
[@override](/user/override)
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
body: SafeArea(
child: SingleChildScrollView(
padding: const EdgeInsets.all(16),
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(
'Gradient',
style: GoogleFonts.rubik(fontSize: 24, fontWeight: FontWeight.w500, letterSpacing: -0.25),
),
const SizedBox(height: 20),
Row(
children: [
Expanded(
child: _buildColorPicker(context, startColor, 'Start Color', (color) {
setState(() {
startColor = color;
});
}),
),
const SizedBox(width: 16),
Expanded(
child: _buildColorPicker(context, endColor, 'End Color', (color) {
setState(() {
endColor = color;
});
}),
),
],
),
const SizedBox(height: 8),
_buildColorWheel(),
const SizedBox(height: 8),
_buildControls(),
const SizedBox(height: 8),
_buildGradient('RGB', OkColor.gradient(startColor, endColor, numberOfColors: numberOfColors, method: InterpolationMethod.rgb)),
const SizedBox(height: 8),
_buildGradient('HSV', OkColor.gradient(startColor, endColor, numberOfColors: numberOfColors, method: InterpolationMethod.hsv)),
const SizedBox(height: 8),
_buildGradient('OkLab', OkColor.gradient(startColor, endColor, numberOfColors: numberOfColors, method: InterpolationMethod.oklab)),
const SizedBox(height: 8),
_buildGradient('OkHsv', OkColor.gradient(startColor, endColor, numberOfColors: numberOfColors, method: InterpolationMethod.okhsv)),
const SizedBox(height: 8),
_buildGradient('OkLch', OkColor.gradient(startColor, endColor, numberOfColors: numberOfColors, method: InterpolationMethod.oklch)),
],
),
),
),
);
}
}
Widget _buildColorPicker(BuildContext context, Color color, String label, Function(Color) onColorChanged) {
return Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
AnimatedContainer(
duration: const Duration(milliseconds: 300),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(24),
border: Border.all(color: Colors.black12, width: 1),
color: color,
),
child: ClipRRect(
borderRadius: BorderRadius.circular(24),
child: Material(
color: Colors.transparent,
child: InkWell(
onTap: () {
showModalBottomSheet(
context: context,
builder: (context) {
return ColorPicker(
pickerColor: color,
onColorChanged: onColorChanged,
);
},
);
},
child: const AspectRatio(
aspectRatio: 1,
child: SizedBox(
width: double.infinity,
),
),
),
),
),
),
const SizedBox(height: 8),
Text(
label,
style: GoogleFonts.rubik(fontSize: 16, fontWeight: FontWeight.w500, letterSpacing: -0.25),
),
],
);
}
更多关于Flutter颜色选择插件okcolor的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
更多关于Flutter颜色选择插件okcolor的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
当然,以下是如何在Flutter项目中使用okcolor
插件来实现颜色选择功能的代码示例。okcolor
是一个流行的Flutter插件,用于提供用户友好的颜色选择器。
第一步:添加依赖
首先,在你的pubspec.yaml
文件中添加okcolor
的依赖:
dependencies:
flutter:
sdk: flutter
okcolor: ^x.y.z # 请使用最新版本号替换x.y.z
然后运行flutter pub get
来安装依赖。
第二步:导入插件
在你的Dart文件中导入okcolor
插件:
import 'package:okcolor/okcolor.dart';
第三步:使用颜色选择器
以下是一个完整的示例,展示了如何在Flutter应用中使用okcolor
插件来选择一个颜色并显示所选颜色的十六进制代码:
import 'package:flutter/material.dart';
import 'package:okcolor/okcolor.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Color Picker Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
Color selectedColor = Colors.grey;
void _pickColor() async {
final Color? result = await OkColor.showPicker(
context,
title: 'Choose a color',
initialColor: selectedColor,
allowShades: true,
showAlphaChannel: true,
);
if (result != null) {
setState(() {
selectedColor = result;
});
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Color Picker Demo'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Container(
width: 100,
height: 100,
color: selectedColor,
),
SizedBox(height: 20),
Text(
'Selected Color: #${selectedColor.value.toRadixString(16).toUpperCase().padStart(8, '0')}',
style: TextStyle(fontSize: 18),
),
SizedBox(height: 20),
ElevatedButton(
onPressed: _pickColor,
child: Text('Pick Color'),
),
],
),
),
);
}
}
解释
- 添加依赖:在
pubspec.yaml
文件中添加okcolor
依赖。 - 导入插件:在你的Dart文件中导入
okcolor
。 - 使用颜色选择器:
- 创建一个按钮,点击时调用
_pickColor
方法。 OkColor.showPicker
方法用于显示颜色选择器对话框。- 用户选择颜色后,
result
变量将包含所选颜色。 - 使用
setState
方法更新UI以显示所选颜色及其十六进制代码。
- 创建一个按钮,点击时调用
通过上述步骤,你可以在Flutter应用中集成并使用okcolor
插件来实现颜色选择功能。希望这个示例对你有帮助!