我的目标是在背景中水平滑动图像上方的滤镜,如下所示:

我使用多个矩阵来创建一些滤色器,我知道我必须用ColorFiltered包装图像才能应用滤色器:这是没有问题的。
然后当我试着刷这些滤镜时,我不知道如何应用它们。以下是演示的代码:
class PageFilters extends StatefulWidget {
double ratio;
String file;
PageFilters({required this.ratio,required this.file});
@override
_PageFiltersState createState() => _PageFiltersState();
}
class _PageFiltersState extends State<PageFilters> {
FilterList filters = FilterList();
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.black,
body: Stack(
alignment: Alignment.center,
children: [
Image.file(File(widget.file),fit: BoxFit.cover),
PageView.builder(
physics: const ClampingScrollPhysics(),
itemCount: filters.list.length,
itemBuilder: (context,index) {
return Center(
child: ColorFiltered(
colorFilter: ColorFilter.matrix(filters.list[index].matrix),
child: Container(
color: index == 0 ? Colors.transparent : Colors.white.withOpacity(0.1),
alignment: Alignment.center,
height: Constants.maxWidth*widget.ratio,
),
),
);
}),
],
),
);
}
}在滑动过程中,滤镜是否直接应用于图像并不重要,只要滤镜可见,我就可以检索它并在以后应用它。
感谢您的指导或解决方案
发布于 2021-10-10 14:39:50
这个想法是在页面移动的相反方向上移动图像-所以如果PageView向右移动子窗口(ColorFiltered小部件),你必须将孙子窗口(Image小部件)移动到左边,这样它就保持在原来的位置-虽然在理论上很简单,但在实践中这可能会让人头疼-幸运的是,有CustomSingleChildLayout小部件为我们节省了大量工作:
class ColorFilteredPageView extends StatefulWidget {
final ImageProvider image;
final List<ColorFilter> filters;
final List<String> filterNames;
ColorFilteredPageView({
@required this.image,
@required this.filters,
@required this.filterNames,
}) : assert(filters.length == filterNames.length);
@override
_ColorFilteredPageViewState createState() => _ColorFilteredPageViewState();
}
class _ColorFilteredPageViewState extends State<ColorFilteredPageView> {
PageController controller = PageController();
@override
Widget build(BuildContext context) {
return PageView.builder(
controller: controller,
itemCount: widget.filters.length,
itemBuilder: (ctx, index) {
return Stack(
fit: StackFit.expand,
children: [
ClipRect(
child: ColorFiltered(
colorFilter: widget.filters[index],
child: CustomSingleChildLayout(
delegate: _ColorFilteredPageViewDelegate(index, controller),
child: Image(image: widget.image, fit: BoxFit.cover),
),
),
),
...outlinedName(widget.filterNames[index]),
],
);
},
);
}
}
/*
// NOTE
// AnimatedBuilder + FractionalTranslation can also be used
// instead of CustomSingleChildLayout but it is kind of workaround imho....
ClipRect(
child: ColorFiltered(
colorFilter: widget.filters[index],
child: AnimatedBuilder(
animation: controller,
builder: (context, child) {
return FractionalTranslation(
translation: controller.position.haveDimensions?
Offset(controller.page - index, 0) : Offset.zero,
child: child,
);
},
child: Image(image: widget.image, fit: BoxFit.cover),
),
),
),
*/
class _ColorFilteredPageViewDelegate extends SingleChildLayoutDelegate {
final int index;
final PageController controller;
_ColorFilteredPageViewDelegate(this.index, this.controller) : super(relayout: controller);
Offset getPositionForChild(Size size, Size childSize) {
// print('index: $index, dx: ${controller.offset - index * size.width}');
return Offset(controller.offset - index * size.width, 0);
}
@override
bool shouldRelayout(covariant SingleChildLayoutDelegate oldDelegate) => false;
}
Iterable<Widget> outlinedName(String name) {
final styles = [
TextStyle(
foreground: Paint()
..color = Colors.black
..style = PaintingStyle.stroke
..strokeWidth = 4
..maskFilter = MaskFilter.blur(BlurStyle.solid, 2),
fontWeight: FontWeight.w500,
),
TextStyle(
color: Colors.white,
fontWeight: FontWeight.w500,
),
];
return styles.map((style) => Align(
alignment: Alignment(0, 0.75),
child: Text(name,
textScaleFactor: 2.5,
textAlign: TextAlign.center,
style: style,
),
),);
}现在使用一些示例过滤器:
final myFilters = [
ColorFilter.mode(Colors.transparent, BlendMode.dst),
ColorFilter.mode(Colors.teal, BlendMode.softLight),
ColorFilter.mode(Colors.teal, BlendMode.hardLight),
ColorFilter.mode(Colors.deepPurple, BlendMode.hue),
// sepia
ColorFilter.matrix([
0.393, 0.769, 0.189, 0, 0,
0.349, 0.686, 0.168, 0, 0,
0.272, 0.534, 0.131, 0, 0,
0, 0, 0, 1, 0,
]),
// greyscale
ColorFilter.matrix([
0.2126, 0.7152, 0.0722, 0, 0,
0.2126, 0.7152, 0.0722, 0, 0,
0.2126, 0.7152, 0.0722, 0, 0,
0, 0, 0, 1, 0,
]),
// invert
ColorFilter.matrix([
-1, 0, 0, 0, 255,
0, -1, 0, 0, 255,
0, 0, -1, 0, 255,
0, 0, 0, 1, 0,
]),
ColorFilter.linearToSrgbGamma(),
ColorFilter.srgbToLinearGamma(),
ColorFilter.mode(Colors.transparent, BlendMode.dst),
];
final myFilterNames = [
'original image', 'teal soft light', 'teal hard light', 'deep purple hue', 'matrix sepia', 'matrix greyscale', 'matrix invert', 'linearToSrgbGamma', 'srgbToLinearGamma', 'original image again',
];您可以按如下方式使用它:
child: ColorFilteredPageView(
image: NetworkImage('https://unsplash.com/photos/3fEzry0pIms/download?force=true&w=640'),
filters: myFilters,
filterNames: myFilterNames,
),发布于 2021-10-06 02:43:38
最简单的方法是使用RenderRepaintBoundary来捕获屏幕小部件:
static GlobalKey _screenCapture = new GlobalKey();
Uint8List _takeScreenShot() async {
RenderRepaintBoundary boundary = _screenCapture.currentContext.findRenderObject();
ui.Image image = await boundary.toImage(pixelRatio: 2.0);
ByteData byteData = await image.toByteData(format: ui.ImageByteFormat.png);
Uint8List pngBytes = byteData.buffer.asUint8List();
return pngBytes;
}
body: Stack(
key: _screenCapture,
alignment: Alignment.center,
children: [
Image.file(File(widget.file),fit: BoxFit.cover),
PageView.builder(
physics: const ClampingScrollPhysics(),
itemCount: filters.list.length,
itemBuilder: (context,index) {
return Center(
child: ColorFiltered(
colorFilter: ColorFilter.matrix(filters.list[index].matrix),
child: Container(
color: index == 0 ? Colors.transparent : Colors.white.withOpacity(0.1),
alignment: Alignment.center,
height: Constants.maxWidth*widget.ratio,
),
),
);
}),
],
),https://stackoverflow.com/questions/69456158
复制相似问题