Any*_*han 18
经过反复试验,我找到了解决方案。源代码和资产文件可在Github 存储库上获取。
\n# Provides server & web apps with the ability to load, manipulate and save images with various image file formats PNG, JPEG, GIF, BMP, WebP, TIFF, TGA, PSD, PVR, and OpenEXR.\nimage: ^2.1.19\n\n# Allows painting & displaying Scalable Vector Graphics 1.1 files\nflutter_svg: ^0.19.3\nRun Code Online (Sandbox Code Playgroud)\n以下是我在研究过程中发现的两种方法。
\n图像颜色切换器小部件
\n# Provides server & web apps with the ability to load, manipulate and save images with various image file formats PNG, JPEG, GIF, BMP, WebP, TIFF, TGA, PSD, PVR, and OpenEXR.\nimage: ^2.1.19\n\n# Allows painting & displaying Scalable Vector Graphics 1.1 files\nflutter_svg: ^0.19.3\nRun Code Online (Sandbox Code Playgroud)\n我创建了一个有状态小部件,它将使用构造函数获取图像路径和所需的颜色。
\n在该initState方法中,我加载图像并imageBytes使用该setState函数将原始字节分配给变量。
接下来,我创建了一个自定义异步函数switchColor,它将Uint8List字节作为参数,检测 RGB 值,将其切换为所需的颜色并返回编码的 png 图像。
在方法内部build,如果imageBytes尚未准备好,我会显示一个CircularProgressIndicatorelse,aFutureBuilder将调用switchColor 并返回容器化图像。
颜色滑块小部件
\nimport \'dart:typed_data\';\nimport \'package:flutter/material.dart\';\nimport \'package:flutter/services.dart\';\nimport \'package:image/image.dart\' as External;\n\nclass ImageColorSwitcher extends StatefulWidget {\n \n /// Holds the Image Path\n final String imagePath;\n\n /// Holds the MaterialColor\n final MaterialColor color;\n\n ImageColorSwitcher({this.imagePath, this.color});\n\n @override\n _ImageColorSwitcherState createState() => _ImageColorSwitcherState();\n}\n\nclass _ImageColorSwitcherState extends State<ImageColorSwitcher> {\n \n /// Holds the Image in Byte Format\n Uint8List imageBytes;\n\n @override\n void initState() {\n rootBundle.load(widget.imagePath).then(\n (data) => setState(() => this.imageBytes = data.buffer.asUint8List()));\n\n super.initState();\n }\n\n /// A function that switches the image color.\n Future<Uint8List> switchColor(Uint8List bytes) async {\n \n // Decode the bytes to [Image] type\n final image = External.decodeImage(bytes);\n\n // Convert the [Image] to RGBA formatted pixels\n final pixels = image.getBytes(format: External.Format.rgba);\n\n // Get the Pixel Length\n final int length = pixels.lengthInBytes;\n\n for (var i = 0; i < length; i += 4) {\n /// PIXELS\n /// =============================\n /// | i | i + 1 | i + 2 | i + 3 |\n /// =============================\n\n // pixels[i] represents Red\n // pixels[i + 1] represents Green\n // pixels[i + 2] represents Blue\n // pixels[i + 3] represents Alpha\n\n // Detect the light blue color & switch it with the desired color\'s RGB value.\n if (pixels[i] == 189 && pixels[i + 1] == 212 && pixels[i + 2] == 222) {\n pixels[i] = widget.color.shade300.red;\n pixels[i + 1] = widget.color.shade300.green;\n pixels[i + 2] = widget.color.shade300.blue;\n }\n \n // Detect the darkish blue shade & switch it with the desired color\'s RGB value.\n else if (pixels[i] == 63 && pixels[i + 1] == 87 && pixels[i + 2] == 101) {\n pixels[i] = widget.color.shade900.red;\n pixels[i + 1] = widget.color.shade900.green;\n pixels[i + 2] = widget.color.shade900.blue;\n }\n }\n return External.encodePng(image);\n }\n\n @override\n Widget build(BuildContext context) {\n return imageBytes == null\n ? Center(child: CircularProgressIndicator())\n : FutureBuilder(\n future: switchColor(imageBytes),\n builder: (_, AsyncSnapshot<Uint8List> snapshot) {\n return snapshot.hasData\n ? Container(\n width: MediaQuery.of(context).size.width * 0.9,\n decoration: BoxDecoration(\n image: DecorationImage(\n image: Image.memory(\n snapshot.data,\n ).image)),\n )\n : CircularProgressIndicator();\n },\n );\n }\n}\nRun Code Online (Sandbox Code Playgroud)\n我声明了一个Map<String, Color> _colorMap保存颜色名称和颜色值的对象。
在该build方法内部,我ListView根据_colorMap.
我colorEntry用 . 将每个包裹在一个圆形容器中BoxShape.circle。
为了点击每种颜色,我将每个容器包装在InkWell小部件中。
在函数内部onTap,我返回了选定的映射条目,即值Color。
光栅代码执行
\nimport \'package:flutter/material.dart\';\n\n/// A Custom Slider that returns a selected color.\n\nclass ColorSlider extends StatelessWidget {\n \n /// Map holding the color name with its value\n final Map<String, Color> _colorMap = {\n \'Red\': Colors.red,\n \'Green\': Colors.green,\n \'Blue\': Colors.blue,\n \'Light Blue\': Colors.lightBlue,\n \'Blue Grey\': Colors.blueGrey,\n \'Brown\': Colors.brown,\n \'Cyan\': Colors.cyan,\n \'Purple\': Colors.purple,\n \'Deep Purple\': Colors.deepPurple,\n \'Light Green\': Colors.lightGreen,\n \'Indigo\': Colors.indigo,\n \'Amber\': Colors.amber,\n \'Yellow\': Colors.yellow,\n \'Lime\': Colors.lime,\n \'Orange\': Colors.orange,\n \'Dark Orange\': Colors.deepOrange,\n \'Teal\': Colors.teal,\n \'Pink\': Colors.pink,\n \'Black\': MaterialColor(\n Colors.black.value,\n {\n 50: Colors.black38,\n 100: Colors.black38,\n 200: Colors.black38,\n 300: Colors.grey.shade800,\n 400: Colors.black38,\n 500: Colors.black38,\n 600: Colors.black38,\n 700: Colors.black38,\n 800: Colors.black38,\n 900: Colors.black,\n },\n ),\n \'White\': MaterialColor(\n Colors.white.value,\n {\n 50: Colors.white,\n 100: Colors.white,\n 200: Colors.white,\n 300: Colors.white,\n 400: Colors.white,\n 500: Colors.white,\n 600: Colors.white,\n 700: Colors.white,\n 800: Colors.white,\n 900: Colors.grey.shade700,\n },\n ),\n \'Grey\': Colors.grey,\n };\n\n /// Triggers when tapped on a color\n final Function(Color) onColorSelected;\n\n ColorSlider({@required this.onColorSelected});\n\n @override\n Widget build(BuildContext context) {\n return ListView(\n scrollDirection: Axis.horizontal,\n children: [\n ..._colorMap.entries.map((MapEntry<String, Color> colorEntry) {\n return InkWell(\n borderRadius: BorderRadius.circular(50.0),\n onTap: () => onColorSelected(colorEntry.value),\n child: Container(\n height: 80,\n width: 80,\n margin: EdgeInsets.all(5.0),\n decoration: BoxDecoration(\n color: colorEntry.value,\n shape: BoxShape.circle,\n boxShadow: [\n BoxShadow(\n color: colorEntry.value.withOpacity(0.8),\n offset: Offset(1.0, 2.0),\n blurRadius: 3.0,\n ),\n ],\n ),\n child: Center(\n child:\n // If the color is Black, change font color to white\n colorEntry.key == \'Black\'\n ? Text(colorEntry.key.toUpperCase(),\n style: TextStyle(\n fontSize: 8.75,\n fontWeight: FontWeight.bold,\n color: Colors.white))\n : Text(colorEntry.key.toUpperCase(),\n style: TextStyle(\n fontSize: 8.75,\n fontWeight: FontWeight.bold)))),\n );\n })\n ],\n );\n }\n}\nRun Code Online (Sandbox Code Playgroud)\n为了将ColorSlider与 集成ImageColorSwitcher,我声明了一个Color变量ColorCode并为其分配了来自回调函数的值ColorSlider\xe2\x80\x99s onColorSelected。
为了避免null值,我将红色设置为默认选择的颜色。
最后,我将这两个自定义小部件包装在一个Column小部件中。
SVG 颜色滑块小部件
\nimport \'package:flutter/material.dart\';\nimport \'package:image_color_switcher/widgets/color_slider.dart\';\nimport \'package:image_color_switcher/widgets/image_color_switcher.dart\';\n\nvoid main() {\n runApp(MyApp());\n\n /// Hide the debug banner on the top right corner\n WidgetsApp.debugAllowBannerOverride = false;\n}\n\nclass MyApp extends StatefulWidget {\n @override\n _MyAppState createState() => _MyAppState();\n}\n\nclass _MyAppState extends State<MyApp> {\n \n // Holds the Color value returned from [ColorSlider]\n Color colorCode;\n\n @override\n Widget build(BuildContext context) {\n return MaterialApp(\n title: \'Image Color Switcher\',\n home: Scaffold(\n body: SafeArea(\n child: Column(children: [\n Expanded(\n child: ImageColorSwitcher(\n imagePath: \'assets/bike.png\',\n color: colorCode ?? Colors.red,\n )),\n Expanded(\n child: ColorSlider(\n onColorSelected: (color) => setState(() => colorCode = color),\n )),\n ]))));\n }\n}\nRun Code Online (Sandbox Code Playgroud)\n我声明了 aMap<String, Color> _colorMap将保存 a String& aColor值。
在地图键内,我Theme.color:shade同样定义了一个编码字符串:\n\xe2\x98\x85 主题:主题的名称。\n\xe2\x98\x85 颜色:颜色的名称或十六进制值。\n\xe2\ x98\x85 阴影:阴影的名称或十六进制值。
在地图值中,我使用了Color.fromARGB constructor.
在该build方法内部,我将_colorMap条目转换为用ListView.
为了显示容器\xe2\x80\x99s的背景颜色,我使用了mapEntry值。
点击该onTap函数后,我返回了选定的mapEntry键(编码字符串)而不是Color 值。
自行车画家小部件
\nimport \'package:flutter/material.dart\';\n\n/// A Custom Slider that returns SVG colors and shades.\nclass SVGColorSlider extends StatelessWidget {\n\n /// Map holding the Theme.color:shade with its value\n final _colorMap = {\n \'Red.indianred:darkred\': Color.fromARGB(255, 255, 0, 0),\n \'Green.#22b14c:#004000\': Colors.green,\n \'Blue.lightskyblue:darkblue\': Color.fromARGB(255, 0, 0, 255),\n \'Navy.#0000CD:#000080\': Color.fromARGB(255, 0, 0, 128),\n \'Magenta.#FF00FF:#8B008B\': Color.fromARGB(255, 255, 0, 255),\n \'Indigo.#9370DB:#4B0082\': Color.fromARGB(255, 75, 0, 130),\n \'Orange.#FFA500:#FF8C00\': Color.fromARGB(255, 255, 165, 0),\n \'Turquoise.#40E0D0:#00CED1\': Color.fromARGB(255, 64, 224, 208),\n \'Purple.#9370DB:#6A0DAD\': Colors.purple,\n \'Bronze.#CD7F32:#524741\': Color.fromARGB(255, 82, 71, 65),\n \'Yellow.#FFFF19:#E0E200\': Color.fromARGB(255, 255, 255, 0),\n \'Burgundy.#9D2735:#800020\': Color.fromARGB(255, 128, 0, 32),\n \'Brown.chocolate:brown\': Color.fromARGB(255, 165, 42, 42),\n \'Beige.beige:#d9b382\': Color.fromARGB(255, 245, 245, 220),\n \'Maroon.#800000:#450000\': Color.fromARGB(255, 128, 0, 0),\n \'Gold.goldenrod:darkgoldenrod\': Color.fromARGB(255, 255, 215, 0),\n \'Grey.grey:darkgrey\': Color.fromARGB(255, 128, 128, 128),\n \'Black.black:#1B1B1B:\': Color.fromARGB(255, 0, 0, 0),\n \'Silver.#8B8B8B:silver\': Color.fromARGB(255, 192, 192, 192),\n // Multiple Options: antiquewhite,floralwhite,ghostwite\n \'White.ghostwhite:black\': Color.fromARGB(255, 255, 255, 255),\n \'Slate.#708090:#284646\': Color.fromARGB(255, 47, 79, 79),\n };\n\n /// Triggers when tapped on a color\n final Function(String) onColorSelected;\n\n SVGColorSlider({@required this.onColorSelected});\n\n @override\n Widget build(BuildContext context) {\n return ListView(\n scrollDirection: Axis.horizontal,\n children: [\n ..._colorMap.entries.map((MapEntry<String, Color> mapEntry) {\n return InkWell(\n borderRadius: BorderRadius.circular(50.0),\n onTap: () => onColorSelected(mapEntry.key),\n child: Container(\n height: 80,\n width: 80,\n margin: EdgeInsets.all(5.0),\n decoration: BoxDecoration(\n color: mapEntry.value,\n shape: BoxShape.circle,\n boxShadow: [\n BoxShadow(\n color: mapEntry.value,\n offset: Offset(1.0, 2.0),\n ),\n ],\n ),\n child: Center(\n child:\n\n /// Change The Font To Black For These Colors\n mapEntry.key.contains(\'White\') ||\n mapEntry.key.contains(\'Beige\') ||\n mapEntry.key.contains(\'Yellow\')\n ? Text(\n mapEntry.key\n .split(\':\')[0]\n .split(\'.\')[0]\n .toUpperCase(),\n style: TextStyle(\n fontSize: 8.75,\n fontWeight: FontWeight.bold,\n ))\n :\n\n /// Else Let The Font Be white\n Text(\n mapEntry.key\n .split(\':\')[0]\n .split(\'.\')[0]\n .toUpperCase(),\n style: TextStyle(\n fontSize: 8.75,\n fontWeight: FontWeight.bold,\n color: Colors.white)))),\n );\n })\n ],\n );\n }\n}\nRun Code Online (Sandbox Code Playgroud)\n我声明了两个String变量color&shade并将它们传递给Bike_Painter\xe2\x80\x99s构造函数。
在该方法内部,我声明了一个用于保存 SVG 代码的build私有变量。_bytes
点击ctrl+H搜索十六进制值并将其替换为变量color& shade。
最后,我将_bytes变量传递给SvgPicture.string构造函数。
SVG 代码执行
\nimport \'package:flutter/material.dart\';\nimport \'package:flutter_svg/svg.dart\';\n\nclass BikePainter extends StatelessWidget {\n final String color, shade;\n\n BikePainter({@required this.color, @required this.shade});\n\n @override\n Widget build(BuildContext context) {\n final _bytes =\n \'\'\'The code is too long, please visit https://gist.githubusercontent.com/Zujaj/2bad1cb88a5b44e95a6a87a89dd23922/raw/68e9597b0b3ab7dfe68a54154c920c335ed1ae18/bike_painter.dart\'\'\';\n\n return SvgPicture.string(_bytes);\n }\n}\nRun Code Online (Sandbox Code Playgroud)\n我将BikePainter&SVGColorSlider小部件集成到文件中main.dart。
下图说明了两种方法的差异。
\n\n1:Flutter 中的 ImageColorSwitcher:第 1 部分光栅图像着色
\n2:Flutter 中的 ImageColorSwitcher:第 2 部分矢量图像着色
\n| 归档时间: |
|
| 查看次数: |
8570 次 |
| 最近记录: |