如何在 Flutter 中从图像的一部分创建小部件?

问题描述 投票:0回答:4

我有一个图像(蓝色矩形)。我想通过路径(红色三角形)剪切图像的一部分,并创建一个较小的小部件(绿色矩形)来显示图像的这一部分,并且其大小等于剪切路径的边界。我怎样才能在 Flutter 中做到这一点?

我尝试使用

ClipPath
CustomClipper<Path>
,但我只能创建具有图像大小的小部件。

flutter widget clip
4个回答
0
投票

由于您没有提供任何代码,我假设您想要基于当前子级的小部件。

如果是,您可以尝试

IntrinsicWidth
IntrinsicHeight
小部件。 https://api.flutter.dev/flutter/widgets/IntrinsicWidth-class.html

IntrinsicWidgth

创建一个小部件,将其子级的大小调整为子级的固有宽度。

这个类很有用,例如,当无限宽度可用时 你想要一个否则会尝试扩展的孩子 无限地将自身调整为更合理的宽度。

使用此小部件,子级将根据内在大小进行渲染。


0
投票

您可以将

CustomPainter
drawAtlas 一起使用 ,表演,显示图像的一部分。我用它来制作像精灵动画这样的动画


0
投票

我找到了这个解决方案:

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;
}

0
投票

这是一个不使用

CustomClipper
的解决方案。

class TileWidget extends StatelessWidget {
  final int left;
  final int top;
  final int width;
  final int height;
  final ui.Image image;

  const TileWidget(this.image, 
    this.left, this.top, this.width, this.height,
      {super.key});

  @override
  Widget build(BuildContext context) {
    return CustomPaint(
        size: Size(width.toDouble(), height.toDouble()),
        painter: _SquarePainter(image, left, top, width, height));
  }
}

class _SquarePainter extends CustomPainter {
  final int left;
  final int top;
  final int width;
  final int height;
  final ui.Image tileset;

  _SquarePainter(this.tileset, this.left, this.top, this.width, this.height);

  @override
  void paint(Canvas canvas, Size size) {
    canvas.drawAtlas(
      tileset,
      [
        RSTransform.fromComponents(
            rotation: 0.0,
            scale: 1.0,
            anchorX: 0.0,
            anchorY: 0.0,
            translateX: 0.0,
            translateY: 0.0)
      ],
      [
        Rect.fromLTWH(
          left.toDouble(),
          top.toDouble(),
          width.toDouble(),
          height.toDouble(),
        )
      ],
      [],
      BlendMode.src,
      null,
      Paint(),
    );
  }

  @override
  bool shouldRepaint(_SquarePainter oldDelegate) => false;

  @override
  bool shouldRebuildSemantics(_SquarePainter oldDelegate) => false;
}
© www.soinside.com 2019 - 2024. All rights reserved.