flutter开发实战-实现css线性渐变转换flutter渐变LinearGradient功能
在之前项目开发中,遇到更换样式,由于从服务器端获取的样式均为css属性值,需要将其转换成flutter类对应的属性值。这里只处理线性渐变linear-gradient
比如渐变
“linear-gradient(to right, rgba(246, 12, 112, .6) 30%, rgba(46, 112, 112, .8) 30%, rgba(46, 12, 145, .8) 30%)”
需要将其转换成LinearGradient属性值。
下面先看效果图
一、css渐变
linear-gradient() 函数用于创建一个表示两种或多种颜色线性渐变的图片。
创建一个线性渐变,需要指定两种颜色,还可以实现不同方向(指定为一个角度)的渐变效果,如果不指定方向,默认从上到下渐变。
/* 从上到下,蓝色渐变到红色 */
linear-gradient(blue, red);
/* 渐变轴为45度,从蓝色渐变到红色 */
linear-gradient(45deg, blue, red);
/* 从右下到左上、从蓝色渐变到红色 */
linear-gradient(to left top, blue, red);
/* 从下到上,从蓝色开始渐变、到高度40%位置是绿色渐变开始、最后以红色结束 */
linear-gradient(0deg, blue, green 40%, red);
background-image: linear-gradient(direction, color-stop1, color-stop2, …);
direction:用角度值指定渐变的方向(或角度)。
color-stop1, color-stop2,…:用于指定渐变的起止颜色。
请参考查看
https://blog.csdn.net/gloryFlow/article/details/131713101
二、将css的属性值转换成flutter类LinearGradient
LinearGradient一个用于创建线性渐变颜色装饰
下面实现以下将css渐变转换成flutter中的LinearGradient类属性值的过程。
看下css,如linear-gradient(180deg, #f34cf6 20%, #ea3e7f, #ea3e7f 100%)
效果如下
- 首先,第一个direction是180deg,或者to left,这里暂时只处理这两种格式。
- 第二,之后是颜色颜色值和stop
我们需要将其转换成flutter的线性渐变对应的类。我们定义类如下
// 渐变方向
enum SkinGradientTo {
top, // 向上
bottom, // 向下
left, // 向左
right, // 向右
}
// 渐变类
class SkinGradient {
double? degree; // 角度
SkinGradientTo? gradientTo; // 方向
List<Color>? colors; // 颜色
List<double>? stops;
}
我们进行以下步骤。
2.1 处理css线性渐变的direction
现将css线性渐变字符串valueString,去除多余空格,最后原先有空格的每个值之间值保留一个空格。
代码如下
// 方式就是遍历两个空格,将其替换成一个空格
// 处理字符串中多个空格
// red___50%转red_50%,_代表空格,处理多个连续空格
static String dealMultContinuousBlank(String originString) {
String twoBlank = " ";
bool hasTwoContinuousBlank = originString.contains(twoBlank);
while(hasTwoContinuousBlank) {
originString = originString.replaceAll(twoBlank, " ");
hasTwoContinuousBlank = originString.contains(twoBlank);
loggerDebug("originString:${originString}");
}
return originString;
}
转换后的valueString结果格式为:linear-gradient(180deg, #f34cf6 20%, #ea3e7f, #ea3e7f 100%)
2.2 统一颜色处理,将css中的rgb、rgba全部转换成#FFFFFFFF或者#FFFFFF格式
由于需要根据逗号“,”进行拆分字符串,生成数组:[“180deg”," #f34cf6 20%“,” #ea3e7f"," #ea3e7f 100%"]
这里需要转换一下颜色格式,将css中的rgb、rgba全部转换成#FFFFFFFF或者#FFFFFF格式。
代码如下
// 处理rgba字符串转成Color
static Color? rgbaToColor(String rgbaString) {
String start = "rgba";
if (rgbaString.startsWith(start)) {
// rgba(152, 69, 255, 0.75)
String subColorStr = rgbaString.substring(start.length);
String noBlank = subColorStr.replaceAll(RegExp(r"\s*"), "");
String noLeftBrackets = noBlank.replaceAll("(", "");
String gDgColor = noLeftBrackets.replaceAll(")", "");
List<String> colors = gDgColor.split(",");
if (colors != null && colors.length == 4) {
String redStr = colors[0];
String greenStr = colors[1];
String blueStr = colors[2];
String alphaStr = colors[3];
int? red = int.parse(redStr);
int? green = int.parse(greenStr);
int? blue = int.parse(blueStr);
double? alpha = double.parse(alphaStr);
Color color = Color.fromRGBO(red, green, blue, alpha);
return color;
}
}
String rgbStart = "rgb";
if (rgbaString.startsWith(rgbStart)) {
// rgba(152, 69, 255)
String subColorStr = rgbaString.substring(rgbStart.length);
String noBlank = subColorStr.replaceAll(RegExp(r"\s*"), "");
String noLeftBrackets = noBlank.replaceAll("(", "");
String gDgColor = noLeftBrackets.replaceAll(")", "");
List<String> colors = gDgColor.split(",");
if (colors != null && colors.length == 3) {
String redStr = colors[0];
String greenStr = colors[1];
String blueStr = colors[2];
int? red = int.parse(redStr);
int? green = int.parse(greenStr);
int? blue = int.parse(blueStr);
double alpha = 1.0;
Color color = Color.fromRGBO(red, green, blue, alpha);
return color;
}
}
return null;
}
/// 颜色检测只保存 #RRGGBB格式 FF透明度
/// [color] 格式可能是材料风/十六进制/string字符串
/// 返回[String] #rrggbb 字符串
static String? color2HEX(Color color) {
// 0xFFFFFFFF
//将十进制转换成为16进制 返回字符串但是没有0x开头
String temp = color.value.toRadixString(16);
if (temp.isNotEmpty) {
loggerDebug("color2HEX temp:${temp}");
if (temp.length == 8) {
String hexColor = "#" + temp.substring(2, 8);
return hexColor.toLowerCase();
} else {
String hexColor = "#" + temp;
return hexColor.toLowerCase();
}
}
return null;
}
通过代码转换后生成数组
生成数组:[“180deg”," #f34cf6 20%“,” #ea3e7f"," #ea3e7f 100%"]
2.3 获得SkinGradientTo或者degree
生成的数组中第一个为direction,需要将其转换成SkinGradientTo或者degree,这里暂时只处理四个方向的
to
top, // 向上
bottom, // 向下
left, // 向左
right, // 向右
四个方向。如果第一个元素包括deg时候,表示为角度
代码如下
String first = colors.first.trim().toLowerCase();
List<double> gStops = [];
if (first.contains("deg")) {
// 角度
String aFirst = first.replaceAll(RegExp(r"\s*"), "");
String dgs = aFirst.replaceAll("deg", "");
double? dgDouble = double.parse(dgs);
if (dgDouble != null) {
// 为整型值
gradient.degree = dgDouble;
}
} else if (first.startsWith("to")) {
// 方向
String aFirst = first.replaceAll(RegExp(r"\s*"), "");
String toStart = "to";
String toStr = aFirst.substring(toStart.length);
SkinGradientTo? gradientTo;
if ("left" == toStr) {
gradientTo = SkinGradientTo.left;
} else if ("right" == toStr) {
gradientTo = SkinGradientTo.right;
} else if ("top" == toStr) {
gradientTo = SkinGradientTo.top;
} else if ("bottom" == toStr) {
gradientTo = SkinGradientTo.bottom;
}
gradient.gradientTo = gradientTo;
}
如果第一个元素不包括"to"也不包括"deg",则表示direction为缺省值,采取默认即可。
2.4 颜色colors与stops,
由于flutter中的线性渐变类,如果存在stops,则stops与colors的length必须一直,所以需要进行转换。
// 处理渐变的Color, 处理这种字符#280069 50%
static Map<String, dynamic> handleGradientColor(String colorString) {
List<String> contentList = colorString.split(" ");
Map<String, dynamic> mapData = {};
String? colorHex;
if (contentList.isNotEmpty) {
for (String str in contentList) {
if (str.isNotEmpty) {
if (str.startsWith("#")) {
colorHex = str;
break;
} else if (str.contains("transparent")) {
colorHex = str;
break;
} else {
Color? aColor = kColorNameMap[str];
if (aColor != null) {
colorHex = str;
}
}
}
}
}
if (colorHex != null) {
// 颜色的占比
String colorRatio = findFirstRatio(colorString);
if (colorRatio.isNotEmpty) {
// 百分比,如50%
String ratioStr = colorRatio.replaceAll("%", "");
double ratio = double.parse(ratioStr) / 100.0;
mapData["ratio"] = ratio;
Color? color;
Color? aColor = kColorNameMap[colorHex];
if (aColor != null) {
color = aColor;
} else {
color = hexColorString(colorHex);
}
mapData["color"] = color;
} else {
Color? color;
Color? aColor = kColorNameMap[colorHex];
if (aColor != null) {
color = aColor;
} else {
color = hexColorString(colorHex);
}
// 没有设置颜色值Stop的百分比,则默认为-1
double ratio = -1;
mapData["color"] = color;
mapData["ratio"] = ratio;
}
}
loggerDebug("mapData:${mapData}");
return mapData;
}
// 颜色名称对应的color类,如red对应Colors.red
Map<String, Color> kColorNameMap = {
'transparent':Colors.transparent,
'black':Colors.black,
'white':Colors.white,
'gray':Colors.grey,
'red':Colors.red,
'green':Colors.green,
'blue':Colors.blue,
'cyan':Colors.cyan,
'brown':Colors.brown,
'lightblue':Colors.lightBlue,
'lightgreen':Colors.lightGreen,
'purple':Colors.purple,
'yellow':Colors.yellow,
'aqua':ColorUtil.hexColorString("00FFFF"),
'fuchsia':ColorUtil.hexColorString("FF00FF"),
'maroon':ColorUtil.hexColorString("800000"),
'olive':ColorUtil.hexColorString("808000"),
'navy':ColorUtil.hexColorString("000080"),
'silver':ColorUtil.hexColorString("C0C0C0"),
'teal':ColorUtil.hexColorString("C0C0C0"),
};
处理后,每个颜色的每一条均为{‘color’:“#FF808000”,‘stop’:“-1”},或者stop有值{‘color’:“#FF808000”,‘stop’:“0.3”}
2.5 处理stops,将color的stop填充完整
由于出现缺省的color stop,缺省是默认值为-1,需要将其改成正确的值。
stops中如果第一条缺省时候,则设置为0;最后一条缺省,则设置为1,
目的是将#f34cf6 0%,#ff0100,#ff0200,#ea3e7f 50%,#0000ff,#000fff, #ea3e7f 100%
代码如下
// 处理gStops值,将gStops中为-1的值转换成正确的值,-1只是占位值
static List<double> dealGradientStops(List<double> stops) {
// 如果stops值超过两个的时候
int startIdx = -1;
int endIdx = -1;
int allNum = stops.length;
if (stops.length >= 2) {
int firstIdx = 0;
int lastIdx = allNum - 1;
double first = stops[firstIdx];
double last = stops[lastIdx];
if (first == -1) {
stops.replaceRange(0, 1, [0.0]);
}
if (last == -1) {
stops.replaceRange(lastIdx, allNum, [1.0]);
}
print("before stops:${stops}, num:${stops.length}");
bool isHasDefaultValue = checkGradientStopsHasDefault(stops);
while(isHasDefaultValue) {
// 进入循环重新设置值
startIdx = -1;
endIdx = -1;
// 判断出startIdx
for(int index = 0; index < allNum; index++) {
double value = stops[index];
int nextIdx = index+1;
if(nextIdx < allNum) {
double nextValue = stops[nextIdx];
if (value != -1.0 && nextValue == -1.0) {
startIdx = index;
break;
}
}
}
// 判断出endIdx
for(int index = 0; index < allNum; index++) {
double value = stops[index];
if (value != -1.0 && index > startIdx) {
endIdx = index;
break;
}
}
print("step stops:${stops}, num:${stops.length}");
if(endIdx >= startIdx) {
print("startIdx:${startIdx}, endIdx:${endIdx}");
int betweenNum = endIdx - startIdx;
double startValue = stops[startIdx];
double endValue = stops[endIdx];
double aTValue = endValue - startValue;
double perValue = aTValue/(betweenNum);
List<double> replacements = [];
double beginValue = startValue;
for(int i = startIdx+1; i < endIdx; i++) {
double value = beginValue + perValue;
replacements.add(value);
beginValue = value;
}
stops.replaceRange(startIdx+1, endIdx, replacements);
}
isHasDefaultValue = checkGradientStopsHasDefault(stops);
}
} else if (stops.length == 1) {
double first = stops[0];
if (first == -1) {
stops.replaceRange(0, 1, [0.0]);
}
}
return stops;
}
2.5 得到所需数据类SkinGradient属性值
这时候得到完所需要的数据degree、gradientTo、colors、stops
将其转换为LinearGradient
LoggerManager().debug(
“decorationGradient gradient colors:
g
r
a
d
i
e
n
t
.
c
o
l
o
r
s
,
s
t
o
p
s
:
{gradient.colors}, stops:
gradient.colors,stops:{gradient.stops}, gradientTo:${gradient.gradientTo}”);
Alignment begin = Alignment.centerLeft;
Alignment end = Alignment.centerRight;
GradientRotation? transform;
if (gradient.gradientTo != null) {
if (SkinGradientTo.top == gradient.gradientTo) {
// 向上
begin = Alignment.bottomCenter;
end = Alignment.topCenter;
} else if (SkinGradientTo.bottom == gradient.gradientTo) {
// 向下
begin = Alignment.topCenter;
end = Alignment.bottomCenter;
} else if (SkinGradientTo.left == gradient.gradientTo) {
// 向左
begin = Alignment.centerRight;
end = Alignment.centerLeft;
} else if (SkinGradientTo.right == gradient.gradientTo) {
// 向右
begin = Alignment.centerLeft;
end = Alignment.centerRight;
}
} else {
// 角度
// 计算角度
if (gradient.degree != null && gradient.degree != 0) {
double p = 180.0;
double radians = (math.pi / p) * gradient.degree!;
transform = GradientRotation(radians);
// 和css角度,方向保持一致
begin = Alignment.bottomCenter;
end = Alignment.topCenter;
}
}
LinearGradient linearGradient;
if (gradient.colors != null &&
gradient.stops != null &&
gradient.colors!.length == gradient.stops!.length) {
linearGradient = LinearGradient(
colors: gradient.colors!,
stops: gradient.stops!,
begin: begin,
end: end,
transform: transform,
);
} else {
linearGradient = LinearGradient(
colors: gradient.colors ?? [],
begin: begin,
end: end,
transform: transform,
);
}
至此转换完成了,先看下效果图
完整代码如下
import 'dart:ui';
import 'package:flutter/material.dart';
import 'color_util.dart';
import 'dart:math' as math;
// 颜色名称对应的color类,如red对应Colors.red
Map<String, Color> kColorNameMap = {
'transparent':Colors.transparent,
'black':Colors.black,
'white':Colors.white,
'gray':Colors.grey,
'red':Colors.red,
'green':Colors.green,
'blue':Colors.blue,
'cyan':Colors.cyan,
'brown':Colors.brown,
'lightblue':Colors.lightBlue,
'lightgreen':Colors.lightGreen,
'purple':Colors.purple,
'yellow':Colors.yellow,
'aqua':ColorUtil.hexColorString("00FFFF"),
'fuchsia':ColorUtil.hexColorString("FF00FF"),
'maroon':ColorUtil.hexColorString("800000"),
'olive':ColorUtil.hexColorString("808000"),
'navy':ColorUtil.hexColorString("000080"),
'silver':ColorUtil.hexColorString("C0C0C0"),
'teal':ColorUtil.hexColorString("C0C0C0"),
};
// 渐变样式
enum SkinGradientStyle {
line, // 线性渐变
}
// 渐变方向
enum SkinGradientTo {
top, // 向上
bottom, // 向下
left, // 向左
right, // 向右
}
// 渐变
class SkinGradient {
SkinGradientStyle? style; // 样式
double? degree; // 角度
SkinGradientTo? gradientTo; // 方向
List<Color>? colors; // 颜色
List<double>? stops;
}
// 描边
class SkinDecorationStroke {
double? width;
Color? color;
}
// 主题皮肤配置
class SkinThemeConfig {
/// 转换css到具体的element类
static SkinGradient? transformThemeGradient(
{ required String value}) {
try {
if (value != null && value.isNotEmpty) {
value = dealMultContinuousBlank(value);
value = value.trimLeft().trimRight().toLowerCase();
// 渐变
SkinGradient? gradient = transformGradient(value);
if (gradient != null) {
return gradient;
}
return null;
}
} catch (e) {
return null;
}
}
/// 转换css到具体的element类
static LinearGradient? transformLineGradient(
{SkinGradient? gradient}) {
try {
if (gradient != null) {
Alignment begin = Alignment.centerLeft;
Alignment end = Alignment.centerRight;
GradientRotation? transform;
if (gradient.gradientTo != null) {
if (SkinGradientTo.top == gradient.gradientTo) {
// 向上
begin = Alignment.bottomCenter;
end = Alignment.topCenter;
} else if (SkinGradientTo.bottom == gradient.gradientTo) {
// 向下
begin = Alignment.topCenter;
end = Alignment.bottomCenter;
} else if (SkinGradientTo.left == gradient.gradientTo) {
// 向左
begin = Alignment.centerRight;
end = Alignment.centerLeft;
} else if (SkinGradientTo.right == gradient.gradientTo) {
// 向右
begin = Alignment.centerLeft;
end = Alignment.centerRight;
}
} else {
// 角度
// 计算角度
if (gradient.degree != null && gradient.degree != 0) {
double p = 180.0;
double radians = (math.pi / p) * gradient.degree!;
transform = GradientRotation(radians);
// 和css角度,方向保持一致
begin = Alignment.bottomCenter;
end = Alignment.topCenter;
}
}
LinearGradient linearGradient;
if (gradient.colors != null &&
gradient.stops != null &&
gradient.colors!.length == gradient.stops!.length) {
linearGradient = LinearGradient(
colors: gradient.colors!,
stops: gradient.stops!,
begin: begin,
end: end,
transform: transform,
);
} else {
linearGradient = LinearGradient(
colors: gradient.colors ?? [],
begin: begin,
end: end,
transform: transform,
);
}
return linearGradient;
}
} catch (e) {
return null;
}
}
// 处理渐变,转换成渐变的类
static SkinGradient? transformGradient(String valueString) {
// value: linear-gradient(180deg, #ff34c6, #fea3e7)
try {
String value = valueString.toLowerCase();
SkinGradient gradient = SkinGradient();
gradient.style = SkinGradientStyle.line;
String start = "linear-gradient";
String subGradientValue =
value.substring(start.length); // (180deg, #ff34c6, #fea3e7)
// [rgba(119, 77, 255, .8), rgba(119, 177, 255, .8)]
List<String> rgbaList = findRegRgbaColorList(subGradientValue);
if (rgbaList.isNotEmpty) {
// 将rgba(255, 77, 255, .8)转换成#ff34c6格式
for (String rgbaString in rgbaList) {
Color? rgbaColor = rgbaToColor(rgbaString);
if (rgbaColor != null) {
String? colorHex = ColorUtil.color2HEX(rgbaColor);
subGradientValue =
subGradientValue.replaceAll(rgbaString, colorHex ?? "");
}
}
} else {
List<String> rgbList = findRegRgbColorList(value);
if (rgbList.isNotEmpty) {
// 将rgb(255, 77, 255)转换成#ff34c6格式
for (String rgbString in rgbList) {
Color? rgbColor = rgbaToColor(rgbString);
if (rgbColor != null) {
String? colorHex = ColorUtil.color2HEX(rgbColor);
subGradientValue =
subGradientValue.replaceAll(rgbString, colorHex ?? "");
}
}
}
}
String noLeftBrackets =
subGradientValue.replaceAll("(", ""); //180deg,#ff34c6,#fea3e7)
String gDgColor =
noLeftBrackets.replaceAll(")", ""); //180deg,#ff34c6,#fea3e7
List<String> colors = gDgColor.split(",");
print("gDgColor:${gDgColor} colors:${colors}");
if (colors.isNotEmpty) {
List<Color> gColors = [];
String first = colors.first.trimLeft().trimRight().toLowerCase();
List<double> gStops = [];
if (first.contains("deg")) {
// 角度
String aFirst = first.replaceAll(RegExp(r"\s*"), "");
String dgs = aFirst.replaceAll("deg", "");
double? dgDouble = double.parse(dgs);
if (dgDouble != null) {
// 为整型值
gradient.degree = dgDouble;
}
} else if (first.startsWith("to")) {
// 方向
String aFirst = first.replaceAll(RegExp(r"\s*"), "");
String toStart = "to";
String toStr = aFirst.substring(toStart.length);
SkinGradientTo? gradientTo;
if ("left" == toStr) {
gradientTo = SkinGradientTo.left;
} else if ("right" == toStr) {
gradientTo = SkinGradientTo.right;
} else if ("top" == toStr) {
gradientTo = SkinGradientTo.top;
} else if ("bottom" == toStr) {
gradientTo = SkinGradientTo.bottom;
}
gradient.gradientTo = gradientTo;
} else {
Map<String, dynamic> mapData = handleGradientColor(first);
double? ratio = mapData["ratio"];
Color? color = mapData["color"];
if (color != null) {
gColors.add(color);
}
if (ratio != null) {
gStops.add(ratio);
}
}
// 遍历之后的
for (int index = 1; index < colors.length; index++) {
String colorString = colors[index].trimLeft().trimRight().toLowerCase();
Map<String, dynamic> mapData = handleGradientColor(colorString);
double? ratio = mapData["ratio"];
Color? color = mapData["color"];
if (color != null) {
gColors.add(color);
}
if (ratio != null) {
gStops.add(ratio);
}
}
gradient.colors = gColors;
// 处理后的新的stop数组
List<double> gGdStops = dealGradientStops(gStops);
gradient.stops = gGdStops;
print("to:${gradient.gradientTo},degree:${gradient.degree},colors:${gradient.colors} gStops:${gradient.stops}");
return gradient;
}
} catch (e) {
return null;
}
return null;
}
// 处理渐变的Color, 处理这种字符#280069 50px
static Map<String, dynamic> handleGradientColor(String colorString) {
List<String> contentList = colorString.split(" ");
Map<String, dynamic> mapData = {};
String? colorHex;
if (contentList.isNotEmpty) {
for (String str in contentList) {
if (str.isNotEmpty) {
if (str.startsWith("#")) {
colorHex = str;
break;
} else if (str.contains("transparent")) {
colorHex = str;
break;
} else {
Color? aColor = kColorNameMap[str];
if (aColor != null) {
colorHex = str;
}
}
}
}
}
if (colorHex != null) {
// 颜色的占比
String colorRatio = findFirstRatio(colorString);
if (colorRatio.isNotEmpty) {
// 百分比,如50%
String ratioStr = colorRatio.replaceAll("%", "");
double ratio = double.parse(ratioStr) / 100.0;
mapData["ratio"] = ratio;
Color? color;
Color? aColor = kColorNameMap[colorHex];
if (aColor != null) {
color = aColor;
} else {
color = hexColorString(colorHex);
}
mapData["color"] = color;
} else {
Color? color;
Color? aColor = kColorNameMap[colorHex];
if (aColor != null) {
color = aColor;
} else {
color = hexColorString(colorHex);
}
// 没有设置颜色值Stop的百分比,则默认为-1
double ratio = -1;
mapData["color"] = color;
mapData["ratio"] = ratio;
}
}
print("mapData:${mapData}");
return mapData;
}
// 处理rgba字符串转成Color
static Color? rgbaToColor(String rgbaString) {
String start = "rgba";
if (rgbaString.startsWith(start)) {
// rgba(152, 69, 255, 0.75)
String subColorStr = rgbaString.substring(start.length);
String noBlank = subColorStr.replaceAll(RegExp(r"\s*"), "");
String noLeftBrackets = noBlank.replaceAll("(", "");
String gDgColor = noLeftBrackets.replaceAll(")", "");
List<String> colors = gDgColor.split(",");
if (colors != null && colors.length == 4) {
String redStr = colors[0];
String greenStr = colors[1];
String blueStr = colors[2];
String alphaStr = colors[3];
int? red = int.parse(redStr);
int? green = int.parse(greenStr);
int? blue = int.parse(blueStr);
double? alpha = double.parse(alphaStr);
Color color = Color.fromRGBO(red, green, blue, alpha);
return color;
}
}
String rgbStart = "rgb";
if (rgbaString.startsWith(rgbStart)) {
// rgba(152, 69, 255)
String subColorStr = rgbaString.substring(rgbStart.length);
String noBlank = subColorStr.replaceAll(RegExp(r"\s*"), "");
String noLeftBrackets = noBlank.replaceAll("(", "");
String gDgColor = noLeftBrackets.replaceAll(")", "");
List<String> colors = gDgColor.split(",");
if (colors != null && colors.length == 3) {
String redStr = colors[0];
String greenStr = colors[1];
String blueStr = colors[2];
int? red = int.parse(redStr);
int? green = int.parse(greenStr);
int? blue = int.parse(blueStr);
double alpha = 1.0;
Color color = Color.fromRGBO(red, green, blue, alpha);
return color;
}
}
return null;
}
// 找到字符串中的第一个百分比百分比
// 'abc rgba(119, 77, 255, .8) 88% , rgba(119, 177, 255, .8) 21%'
// => [88%, 21%]
static String findFirstRatio(String str) {
RegExp exp = RegExp(r'[\d.]+%');
RegExpMatch? match = exp.firstMatch(str);
return match?.group(0) ?? '';
}
// 处理字符串中多个空格
// red___50%转red_50%,_代表空格,处理多个连续空格
static String dealMultContinuousBlank(String originString) {
String twoBlank = " ";
bool hasTwoContinuousBlank = originString.contains(twoBlank);
while(hasTwoContinuousBlank) {
originString = originString.replaceAll(twoBlank, " ");
hasTwoContinuousBlank = originString.contains(twoBlank);
print("originString:${originString}");
}
return originString;
}
// 处理gStops值,将gStops中为-1的值转换成正确的值,-1只是占位值
static List<double> dealGradientStops(List<double> stops) {
// 如果stops值超过两个的时候
int startIdx = -1;
int endIdx = -1;
int allNum = stops.length;
if (stops.length >= 2) {
int firstIdx = 0;
int lastIdx = allNum - 1;
double first = stops[firstIdx];
double last = stops[lastIdx];
if (first == -1) {
stops.replaceRange(0, 1, [0.0]);
}
if (last == -1) {
stops.replaceRange(lastIdx, allNum, [1.0]);
}
print("before stops:${stops}, num:${stops.length}");
bool isHasDefaultValue = checkGradientStopsHasDefault(stops);
while(isHasDefaultValue) {
// 进入循环重新设置值
startIdx = -1;
endIdx = -1;
// 判断出startIdx
for(int index = 0; index < allNum; index++) {
double value = stops[index];
int nextIdx = index+1;
if(nextIdx < allNum) {
double nextValue = stops[nextIdx];
if (value != -1.0 && nextValue == -1.0) {
startIdx = index;
break;
}
}
}
// 判断出endIdx
for(int index = 0; index < allNum; index++) {
double value = stops[index];
if (value != -1.0 && index > startIdx) {
endIdx = index;
break;
}
}
print("step stops:${stops}, num:${stops.length}");
if(endIdx >= startIdx) {
print("startIdx:${startIdx}, endIdx:${endIdx}");
int betweenNum = endIdx - startIdx;
double startValue = stops[startIdx];
double endValue = stops[endIdx];
double aTValue = endValue - startValue;
double perValue = aTValue/(betweenNum);
List<double> replacements = [];
double beginValue = startValue;
for(int i = startIdx+1; i < endIdx; i++) {
double value = beginValue + perValue;
replacements.add(value);
beginValue = value;
}
stops.replaceRange(startIdx+1, endIdx, replacements);
}
isHasDefaultValue = checkGradientStopsHasDefault(stops);
}
} else if (stops.length == 1) {
double first = stops[0];
if (first == -1) {
stops.replaceRange(0, 1, [0.0]);
}
}
return stops;
}
// 判断数组中是否有占位的-1值
static bool checkGradientStopsHasDefault(List<double> list) {
for (int index = 0; index < list.length; index++) {
double value = list[index];
if (value == -1) {
return true;
}
}
return false;
}
}
三、小结
flutter开发实战-实现css线性渐变转换flutter渐变LinearGradient功能
在之前项目开发中,遇到更换样式,由于从服务器端获取的样式均为css属性值,需要将其转换成flutter类对应的属性值。
学习记录,每天不停进步。