【问题标题】:Apply color filter picture while swipe Flutter在滑动 Flutter 时应用颜色滤镜图片
【发布时间】:2021-11-26 01:40:14
【问题描述】:

我的目标是像这样在背景图像上方水平滑动颜色过滤器:

我正在使用多个矩阵来创建一些颜色过滤器,并且我知道我必须用 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,
                ),
              ),
            );
          }),
        ],
      ),
    );
  }
}

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

感谢任何线索或解决方案

【问题讨论】:

    标签: image flutter dart filter colors


    【解决方案1】:

    这个想法是将图像移动到与页面移动相反的方向 - 所以如果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,
    ),
    

    【讨论】:

      【解决方案2】:

      最简单的方法是使用 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,
                      ),
                    ),
                  );
                }),
              ],
            ),
      

      【讨论】:

        猜你喜欢
        • 2018-01-31
        • 1970-01-01
        • 2015-04-19
        • 1970-01-01
        • 2018-03-25
        • 1970-01-01
        • 2021-09-08
        • 2020-07-06
        • 2015-05-18
        相关资源
        最近更新 更多