首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在轻扫颤动时应用滤色图片

在轻扫颤动时应用滤色图片
EN

Stack Overflow用户
提问于 2021-10-05 19:21:34
回答 2查看 477关注 0票数 2

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

我使用多个矩阵来创建一些滤色器,我知道我必须用ColorFiltered包装图像才能应用滤色器:这是没有问题的。

然后当我试着刷这些滤镜时,我不知道如何应用它们。以下是演示的代码:

代码语言:javascript
复制
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,
                ),
              ),
            );
          }),
        ],
      ),
    );
  }
}

在滑动过程中,滤镜是否直接应用于图像并不重要,只要滤镜可见,我就可以检索它并在以后应用它。

感谢您的指导或解决方案

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2021-10-10 14:39:50

这个想法是在页面移动的相反方向上移动图像-所以如果PageView向右移动子窗口(ColorFiltered小部件),你必须将孙子窗口(Image小部件)移动到左边,这样它就保持在原来的位置-虽然在理论上很简单,但在实践中这可能会让人头疼-幸运的是,有CustomSingleChildLayout小部件为我们节省了大量工作:

代码语言:javascript
复制
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,
    ),
  ),);
}

现在使用一些示例过滤器:

代码语言:javascript
复制
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',
];

您可以按如下方式使用它:

代码语言:javascript
复制
child: ColorFilteredPageView(
  image: NetworkImage('https://unsplash.com/photos/3fEzry0pIms/download?force=true&w=640'),
  filters: myFilters,
  filterNames: myFilterNames,
),
票数 2
EN

Stack Overflow用户

发布于 2021-10-06 02:43:38

最简单的方法是使用RenderRepaintBoundary来捕获屏幕小部件:

代码语言:javascript
复制
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,
                ),
              ),
            );
          }),
        ],
      ),
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/69456158

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档