Flutter 裁剪图片/显示图片部分内容

1,517 阅读1分钟

前置数据:

String labelObject = {
  "leftTop": {
    "x": 30,
    "y": 50,
  },
  "rightBottom": {
    "x": 200,
    "y": 200,
  }
}
String imageObject = {
  "imagePath": "someUrl.jpg""width": 1024,
  "height": 768,
}

目标:

图片大小为1024*768, 希望仅能显示labelObject范围内的图片内容。

解决方案

1. 使用Stack布局,最简单

double labelWidth = labelObject.rightBottom.x - labelObject.leftTop.x;
double labelHeight = labelObject.rightBottom.y - labelObject.leftTop.y;

SizedBox(
  height: 150,
  width: double.infinity,
  child: FittedBox(
    fit: BoxFit.contain,
    child: SizedBox(
      width: labelWidth,
      height: labelHeight,
      child: Stack(
        children: [
          Positioned(
            top: -labelObject.leftTop.y,
            left: -labelObject.leftTop.x,
            child: Image.file(
              File(imageObject.imagePath),
            ),
          ),
        ],
      ),
    ),
  ),
),

2. 使用Align, alignment参数比较难理解

double labelWidth = labelObject.rightBottom.x - labelObject.leftTop.x;
double labelHeight = labelObject.rightBottom.y - labelObject.leftTop.y;
double labelCenterX = (labelObject.rightBottom.x + labelObject.leftTop.x) / 2;
double labelCenterY = (labelObject.rightBottom.y + labelObject.leftTop.y) / 2;


double offsetX = labelCenterX - imageObject.width / 2;
double offsetY = labelCenterY - imageObject.height / 2;
double offsetRangeX = (imageObject.width - labelWidth) / 2;
double offsetRangeY = (imageObject.height - labelHeight) / 2;

double xAlign = offsetRangeX == 0 ? 0 : offsetX / offsetRangeX;
double yAlign = offsetRangeY == 0 ? 0 : offsetY / offsetRangeY;

SizedBox(
  height: 300,
  width: double.infinity,
  child: FittedBox(
    fit: BoxFit.contain,
    child: Container(
      color: Colors.red,
      child: ClipRect(
        child: Align(
          widthFactor: labelWidth / imageObject.width,
          heightFactor: labelHeight / imageObject.height,
          alignment: Alignment(xAlign, yAlign),
          child: Image.file(File(imageObject.imagePath)),
        ),
      ),
    ),
  ),
),

3. 同样使用Align,但使用transform可以避免Aligin参数很不好计算的问题

double labelCenterX = (labelObject.rightBottom.x + labelObject.leftTop.x) / 2;
double labelCenterY = (labelObject.rightBottom.y + labelObject.leftTop.y) / 2;

SizedBox(
  height: 150,
  width: double.infinity,
  child: FittedBox(
    fit: BoxFit.contain,
    child: Container(
      color: Colors.red,
      child: ClipRect(
        child: Align(
          widthFactor: labelWidth / imageObject.width,
          heightFactor: labelHeight / imageObject.height,
          alignment: Alignment.center,
          child: Transform.translate(
            offset: Offset(
              -labelCenterX + imageObject.width / 2,
              -labelCenterY + imageObject.height / 2,
            ),
            child: Image.file(File(imageObject.imagePath)),
          ),
        ),
      ),
    ),
  ),
),