skip to Main Content

I have an image (blue rect). I want to cut a part of the image by path (red triangle) and create a smaller widget (green rect) that shows this part of the image and has size which equals bounds of cutting path. How can I do it in Flutter?

Example

I tried to use ClipPath and CustomClipper<Path>, but I was able to create only widget which has size of the image.

3

Answers


  1. Chosen as BEST ANSWER

    I found this solution:

    import 'dart:typed_data';
    import 'dart:ui' as ui;
    
    import 'package:flutter/material.dart';
    
    class MyWidget extends StatelessWidget {
      final ui.Image _uiImage;
      final Path _clipPath;
    
      const MyWidget({
        Key? key,
        required ui.Image uiImage,
        required Path clipPath,
      })  : _uiImage = uiImage,
            _clipPath = clipPath,
            super(key: key);
    
      @override
      Widget build(BuildContext context) {
        final bounds = _clipPath.getBounds();
        
        final translateM = Float64List.fromList([
          1, 0, 0, 0,
          0, 1, 0, 0,
          0, 0, 1, 0,
          -bounds.left, -bounds.top, 0, 1
        ]);
        
        final localClipPath = _clipPath.transform(translateM);
        
        return ClipPath(
          clipper: _MyClipper(localClipPath),
          child: CustomPaint(
            painter: _MyPainter(_uiImage, bounds),
            child: SizedBox(
              width: bounds.width,
              height: bounds.height,
            ),
          ),
        );
      }
    }
    
    class _MyClipper extends CustomClipper<Path> {
      final Path _clipPath;
    
      _MyClipper(this._clipPath);
    
      @override
      Path getClip(Size size) => _clipPath;
    
      @override
      bool shouldReclip(covariant CustomClipper<Path> oldClipper) => true;
    }
    
    class _MyPainter extends CustomPainter {
      final ui.Image _uiImage;
      final Rect _bounds;
    
      final _paint = Paint();
    
      _MyPainter(this._uiImage, this._bounds);
    
      @override
      void paint(Canvas canvas, Size size) {
        canvas.drawAtlas(
          _uiImage,
          [
            RSTransform.fromComponents(
              rotation: 0.0,
              scale: 1.0,
              // Center of the sprite relative to its rect
              anchorX: _bounds.width / 2,
              anchorY: _bounds.height / 2,
              // Location at which to draw the center of the sprite
              translateX: _bounds.width / 2,
              translateY: _bounds.height / 2,
            )
          ],
          [_bounds],
          null,
          null,
          null,
          _paint,
        );
      }
    
      @override
      bool shouldRepaint(_MyPainter oldDelegate) => false;
    }
    

  2. since you are not provide any code, I assume you want to have widget based on current child.

    if yes, you may try IntrinsicWidth and IntrinsicHeight widget.
    https://api.flutter.dev/flutter/widgets/IntrinsicWidth-class.html

    IntrinsicWidgth:

    Creates a widget that sizes its child to the child’s intrinsic width.

    This class is useful, for example, when unlimited width is available
    and you would like a child that would otherwise attempt to expand
    infinitely to instead size itself to a more reasonable width.

    With this widget, the child will rendered with based on intrinsic size.

    Login or Signup to reply.
  3. you can use CustomPainter with drawAtlas
    , performant, show part of the image. I use this to make animation like sprites Animation

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search