Flutter - 如何剪辑固定大小的渐变并在可能的情况下对其进行动画处理?
Flutter - How can I clip a fixed size gradient and animate it if possible?
我正在尝试为音频输入创建一个视觉仪表。视觉是基本的:从绿色到黄色再到红色的线性渐变。问题是,我试图根据当前的音频输入值来剪辑渐变。我对 Flutter 比较陌生,我尝试了不同的小部件来实现它,但还没有找到解决方案。
我尝试将装饰后的 Container
包裹在 OverflowBox
中,根据值,父项将是具有适当大小的 SizedBox
。我最后的尝试是这样的:
Widget build(BuildContext context) {
return BlocBuilder(
bloc: _bloc,
builder: (BuildContext context, MicrophoneSpeakingBaseState state) {
if (state is MicrophoneSpeakingActiveState && state.speakingValue > 0) {
return FractionallySizedBox(
alignment: Alignment.topLeft,
widthFactor: state.speakingValue,
child: Stack(
alignment: Alignment.topLeft,
overflow: Overflow.clip,
children: [
Container(
width: size.width,
height: size.height,
constraints: BoxConstraints(minWidth: size.width),
decoration: BoxDecoration(
borderRadius: borderRadius,
gradient: LinearGradient(
begin: Alignment.centerLeft,
end: Alignment.centerRight,
colors: [Colors.green, Colors.green, Colors.yellow, Colors.red],
),
),
),
],
),
);
}
},
);
}
我认为输出会起作用,但实际上我得到了尺寸减小的渐变(根据当前输入值)并且渐变本身按比例缩小,而不是保持完整尺寸。还应用了边框半径,就好像条形图更小一样。
像这样将容器包装在 ClipPath 小部件中:
new ClipPath(
clipper: BoxClipper(clipX: 100.0),
clipBehavior: Clip.hardEdge,
child: Container(
width: 400.0,
height: 100.0,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(100.0),
gradient: LinearGradient(
begin: Alignment.centerLeft,
end: Alignment.centerRight,
colors: [Colors.green, Colors.green, Colors.yellow, Colors.red],
),
),
),
),
ClipPath 小部件需要您定义 CustomClipper 小部件。下面的自定义裁剪器接受一个参数 clipX,它控制裁剪容器的宽度。 clipX的值越大,裁剪后的矩形宽度越小
class BoxClipper extends CustomClipper<Path> {
final double clipX;
BoxClipper({this.clipX});
Path getClip(Size size) {
var path = Path();
path.lineTo(0.0, size.height);
path.lineTo(size.width - clipX, size.height);
path.lineTo(size.width - clipX, 0.0);
path.close();
return path;
}
@override
bool shouldReclip(CustomClipper<Path> oldClipper) => false;
}
感谢@Error4on4,我扩展了他的答案,使其也能够同时剪裁左侧和右侧:
class FractionalRangeClipper extends CustomClipper<Path> {
final double? begin;
final double? end;
FractionalRangeClipper({required this.begin, required this.end});
Path getClip(Size size) {
final path = Path();
final absoluteBegin = size.width * (begin ?? 0);
final absoluteEnd = size.width * (end ?? 1);
path.lineTo(absoluteBegin, 0);
path.lineTo(absoluteBegin, size.height);
path.lineTo(absoluteEnd, size.height);
path.lineTo(absoluteEnd, 0);
path.close();
return path;
}
@override
bool shouldReclip(CustomClipper<Path> oldClipper) => false;
}
用法:
ClipPath(
clipper: FractionalRangeClipper(begin: 0.2, end: 0.7),
clipBehavior: Clip.hardEdge,
child: YourWidget(),
),
我正在尝试为音频输入创建一个视觉仪表。视觉是基本的:从绿色到黄色再到红色的线性渐变。问题是,我试图根据当前的音频输入值来剪辑渐变。我对 Flutter 比较陌生,我尝试了不同的小部件来实现它,但还没有找到解决方案。
我尝试将装饰后的 Container
包裹在 OverflowBox
中,根据值,父项将是具有适当大小的 SizedBox
。我最后的尝试是这样的:
Widget build(BuildContext context) {
return BlocBuilder(
bloc: _bloc,
builder: (BuildContext context, MicrophoneSpeakingBaseState state) {
if (state is MicrophoneSpeakingActiveState && state.speakingValue > 0) {
return FractionallySizedBox(
alignment: Alignment.topLeft,
widthFactor: state.speakingValue,
child: Stack(
alignment: Alignment.topLeft,
overflow: Overflow.clip,
children: [
Container(
width: size.width,
height: size.height,
constraints: BoxConstraints(minWidth: size.width),
decoration: BoxDecoration(
borderRadius: borderRadius,
gradient: LinearGradient(
begin: Alignment.centerLeft,
end: Alignment.centerRight,
colors: [Colors.green, Colors.green, Colors.yellow, Colors.red],
),
),
),
],
),
);
}
},
);
}
我认为输出会起作用,但实际上我得到了尺寸减小的渐变(根据当前输入值)并且渐变本身按比例缩小,而不是保持完整尺寸。还应用了边框半径,就好像条形图更小一样。
像这样将容器包装在 ClipPath 小部件中:
new ClipPath(
clipper: BoxClipper(clipX: 100.0),
clipBehavior: Clip.hardEdge,
child: Container(
width: 400.0,
height: 100.0,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(100.0),
gradient: LinearGradient(
begin: Alignment.centerLeft,
end: Alignment.centerRight,
colors: [Colors.green, Colors.green, Colors.yellow, Colors.red],
),
),
),
),
ClipPath 小部件需要您定义 CustomClipper 小部件。下面的自定义裁剪器接受一个参数 clipX,它控制裁剪容器的宽度。 clipX的值越大,裁剪后的矩形宽度越小
class BoxClipper extends CustomClipper<Path> {
final double clipX;
BoxClipper({this.clipX});
Path getClip(Size size) {
var path = Path();
path.lineTo(0.0, size.height);
path.lineTo(size.width - clipX, size.height);
path.lineTo(size.width - clipX, 0.0);
path.close();
return path;
}
@override
bool shouldReclip(CustomClipper<Path> oldClipper) => false;
}
感谢@Error4on4,我扩展了他的答案,使其也能够同时剪裁左侧和右侧:
class FractionalRangeClipper extends CustomClipper<Path> {
final double? begin;
final double? end;
FractionalRangeClipper({required this.begin, required this.end});
Path getClip(Size size) {
final path = Path();
final absoluteBegin = size.width * (begin ?? 0);
final absoluteEnd = size.width * (end ?? 1);
path.lineTo(absoluteBegin, 0);
path.lineTo(absoluteBegin, size.height);
path.lineTo(absoluteEnd, size.height);
path.lineTo(absoluteEnd, 0);
path.close();
return path;
}
@override
bool shouldReclip(CustomClipper<Path> oldClipper) => false;
}
用法:
ClipPath(
clipper: FractionalRangeClipper(begin: 0.2, end: 0.7),
clipBehavior: Clip.hardEdge,
child: YourWidget(),
),