Flutter自定义图像拼贴

Flutter custom image collage

我希望能够构建 拼贴画 为此,我尝试使用 CustomPaint 绘制形状,然后用 image.这是我试过的:

  Container(
    height: 300,
    width: 300,
    decoration: BoxDecoration(
      borderRadius: BorderRadius.circular(10.0),
      border: Border.all(color: Colors.white, width: 5),
    ),
    child: CustomPaint(
      painter: DrawTriangleShape(color: Colors.blue),
      child: Image.asset('assets/images/exampleImage.jpg'),
    ),
  ),

还有我的 DrawTriangleShape:

class DrawTriangleShape extends CustomPainter {
  Paint painter;

  DrawTriangleShape({color: Colors}) {
    painter = Paint()
      ..color = color
      ..style = PaintingStyle.fill;
  }

  @override
  void paint(Canvas canvas, Size size) {
    var path = Path();

    path.moveTo(size.width / 1, 0);
    path.lineTo(0, size.height);
    path.lineTo(size.height, size.width);
    path.close();

    canvas.drawPath(path, painter);
  }

  @override
  bool shouldRepaint(CustomPainter oldDelegate) {
    return false;
  }
}

结果:

如您所见,这并不是真正想要的结果,因为图像没有填充形状。我没有找到任何东西。有可能吗?如果没有,用自定义形状构建拼贴画的最佳方法是什么?

如果您需要更多信息,请告诉我!

使用 ClipPath 小部件代替 CustomPaint

使用与您相同的路径 CustomPaint:

完整源代码

import 'package:flutter/material.dart';

void main() {
  runApp(
    MaterialApp(
      debugShowCheckedModeBanner: false,
      title: 'Flutter Demo',
      home: HomePage(),
    ),
  );
}

class HomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: ClipPath(
          clipper: CustomClipperImage(),
          child: Image.asset('images/abstract.jpg'),
        ),
      ),
    );
  }
}

class CustomClipperImage extends CustomClipper<Path> {
  @override
  getClip(Size size) {
    return Path()
      ..moveTo(size.width / 1, 0)
      ..lineTo(0, size.height)
      ..lineTo(size.height, size.width)
      ..close();
  }

  @override
  bool shouldReclip(CustomClipper oldClipper) {
    return false;
  }
}

带有白色边框和缩放图像的附加示例。

完整源代码

import 'package:flutter/material.dart';

void main() {
  runApp(
    MaterialApp(
      debugShowCheckedModeBanner: false,
      title: 'Flutter Demo',
      home: HomePage(),
    ),
  );
}

class HomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final width = MediaQuery.of(context).size.width * .8;
    final height = width * .7;
    return Scaffold(
      body: Container(
        color: Colors.black54,
        child: Center(
          child: Stack(
            children: [
              CustomPaint(
                painter: MyPainter(),
                child: Container(width: width, height: height),
              ),
              ClipPath(
                clipper: CustomClipperImage(),
                child: Transform.scale(
                  scale: 3,
                  child: Image.asset('images/abstract.jpg',
                      width: width, height: height),
                ),
              ),
            ],
          ),
        ),
      ),
    );
  }
}

class CustomClipperImage extends CustomClipper<Path> {
  @override
  getClip(Size size) {
    return Path()
      ..moveTo(size.width, 0)
      ..lineTo(0, size.height)
      ..lineTo(size.height, size.height)
      ..close();
  }

  @override
  bool shouldReclip(CustomClipper oldClipper) {
    return false;
  }
}

class MyPainter extends CustomPainter {
  @override
  void paint(Canvas canvas, Size size) {
    final path = Path()
      ..moveTo(size.width, 0)
      ..lineTo(0, size.height)
      ..lineTo(size.height, size.height)
      ..close();
    final paint = Paint()
      ..color = Colors.white
      ..strokeWidth = 8.0
      ..style = PaintingStyle.stroke;
    canvas.drawPath(path, paint);
  }

  @override
  bool shouldRepaint(covariant CustomPainter oldDelegate) => false;
}

在图像上缩放和平移的解决方案

使用GestureDetector检测scalelocalFocalPoint的变化。然后使用 Matrix4Transform 我们的 Image.asset:

完整源代码:

import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';

void main() {
  runApp(
    MaterialApp(
      debugShowCheckedModeBanner: false,
      title: 'Flutter Demo',
      home: HomePage(),
    ),
  );
}

class HomePage extends HookWidget {
  @override
  Widget build(BuildContext context) {
    final _width = MediaQuery.of(context).size.width * .8;
    final _height = _width * .6;
    final _zoom = useState<double>(1.0);
    final _previousZoom = useState<double>(1.0);
    final _offset = useState<Offset>(Offset.zero);
    final _previousOffset = useState<Offset>(Offset.zero);
    final _startingFocalPoint = useState<Offset>(Offset.zero);
    return Scaffold(
      body: Container(
        color: Colors.black54,
        child: Center(
          child: GestureDetector(
            onScaleStart: (details) {
              _startingFocalPoint.value = details.localFocalPoint;
              _previousOffset.value = _offset.value;
              _previousZoom.value = _zoom.value;
            },
            onScaleUpdate: (details) {
              _zoom.value = _previousZoom.value * details.scale;
              final Offset normalizedOffset =
                  (_startingFocalPoint.value - _previousOffset.value) /
                      _previousZoom.value;
              _offset.value =
                  details.localFocalPoint - normalizedOffset * _zoom.value;
            },
            child: Stack(
              children: [
                CustomPaint(
                  painter: MyPainter(),
                  child: Container(width: _width, height: _height),
                ),
                ClipPath(
                  clipper: CustomClipperImage(),
                  child: Transform(
                    transform: Matrix4.identity()
                      ..translate(_offset.value.dx, _offset.value.dy)
                      ..scale(_zoom.value),
                    // ..rotateZ(_rotation.value),
                    child: Image.asset('images/milkyway.jpg',
                        width: _width, height: _height),
                  ),
                ),
              ],
            ),
          ),
        ),
      ),
    );
  }
}

class CustomClipperImage extends CustomClipper<Path> {
  @override
  getClip(Size size) {
    return Path()
      ..moveTo(size.width, 0)
      ..lineTo(0, size.height)
      ..lineTo(size.height, size.height)
      ..close();
  }

  @override
  bool shouldReclip(CustomClipper oldClipper) {
    return false;
  }
}

class MyPainter extends CustomPainter {
  @override
  void paint(Canvas canvas, Size size) {
    final path = Path()
      ..moveTo(size.width, 0)
      ..lineTo(0, size.height)
      ..lineTo(size.height, size.height)
      ..close();
    final paint = Paint()
      ..color = Colors.white
      ..strokeWidth = 8.0
      ..style = PaintingStyle.stroke;
    canvas.drawPath(path, paint);
  }

  @override
  bool shouldRepaint(covariant CustomPainter oldDelegate) => false;
}