我是Flutter的新手,我正在尝试编写一个库,允许用户平移/缩放他们的个人资料图片。
为了使它具有视觉效果,我想用“倒置”的ClipOval堆叠它们的图像,以显示边界。
到目前为止,这是我获得的结果:
这显示了边界,但这不是用户友好的,我想“反转”ClipOval,使剪辑的中心“清晰”,外部变灰(类似于蒙版)。
有没有办法实现这个目标?
这是我到目前为止的代码(其中一部分来自flutter_zoomable_image):
import 'dart:ui' as ui;
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
class ImagePanner extends StatefulWidget {
ImagePanner(this.image, {Key key}) : super(key: key);
/// The image to be panned
final ImageProvider image;
@override
_ImagePannerState createState() => new _ImagePannerState();
}
class _ImagePannerState extends State<ImagePanner> {
ImageStream _imageStream;
ui.Image _image;
double _zoom = 1.0;
Offset _offset = Offset.zero;
double _scale = 16.0;
@override
void didChangeDependencies() {
_resolveImage();
super.didChangeDependencies();
}
@override
void reassemble() {
_resolveImage();
super.reassemble();
}
@override
Widget build(BuildContext context) {
if (_image == null) {
return new Container();
}
return new Container(
width: double.INFINITY,
color: Colors.amber,
child: new Padding(
padding: new EdgeInsets.all(50.0),
child: new Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
new AspectRatio(
aspectRatio: 1.0,
child: new Stack(
children: [
_child(),
new Opacity(
opacity: 0.5,
child: new ClipOval(
child: new Container(
color: Colors.black,
),
),
),
],
),
),
],
)),
);
}
Widget _child() {
Widget bloated = new CustomPaint(
child: new Container(),
painter: new _ImagePainter(
image: _image,
offset: _offset,
zoom: _zoom / _scale,
),
);
bloated = new Stack(
children: [
new Container(
),
bloated
],
);
return new Transform(
transform: new Matrix4.diagonal3Values(_scale, _scale, _scale),
child: bloated);
}
void _resolveImage() {
_imageStream = widget.image.resolve(createLocalImageConfiguration(context));
_imageStream.addListener(_handleImageLoaded);
}
void _handleImageLoaded(ImageInfo info, bool synchronousCall) {
print("image loaded: $info $synchronousCall");
setState(() {
_image = info.image;
});
}
}
class _ImagePainter extends CustomPainter {
const _ImagePainter({this.image, this.offset, this.zoom});
final ui.Image image;
final Offset offset;
final double zoom;
@override
void paint(Canvas canvas, Size size) {
paintImage(canvas: canvas, rect: offset & (size * zoom), image: image);
}
@override
bool shouldRepaint(_ImagePainter old) {
return old.image != image || old.offset != offset || old.zoom != zoom;
}
}
我想获得的结果是以下内容,以便用户可以直接看到边界,并且能够在椭圆形中心,平移,缩放其轮廓图像。
(我是通过Photoshop制作的,因为我不知道如何用Flutter实现这一点)
非常感谢您的帮助。
还有其他几种方法可以做到这一点 - 您可以使用具有圆形和矩形的路径在CustomCanvas中绘制叠加层,因为您真正需要的是一个带有孔的矩形半透明矩形。但是你也可以使用CustomClipper
,它可以在将来提供更大的灵活性而无需手动绘制内容。
void main() {
int i = 0;
runApp(new MaterialApp(
home: new SafeArea(
child: new Stack(
children: <Widget>[
new GestureDetector(
onTap: () {
print("Tapped! ${i++}");
},
child: new Container(
color: Colors.white,
child: new Center(
child: new Container(
width: 400.0,
height: 300.0,
color: Colors.red.shade100,
),
),
),
),
new IgnorePointer(
child: new ClipPath(
clipper: new InvertedCircleClipper(),
child: new Container(
color: new Color.fromRGBO(0, 0, 0, 0.5),
),
),
)
],
),
),
));
}
class InvertedCircleClipper extends CustomClipper<Path> {
@override
Path getClip(Size size) {
return new Path()
..addOval(new Rect.fromCircle(
center: new Offset(size.width / 2, size.height / 2),
radius: size.width * 0.45))
..addRect(new Rect.fromLTWH(0.0, 0.0, size.width, size.height))
..fillType = PathFillType.evenOdd;
}
@override
bool shouldReclip(CustomClipper<Path> oldClipper) => false;
}
需要IgnorePointer
,否则事件不会通过半透明部分传播(假设您需要触摸事件)。
这是如何工作的,clipPath使用的Path
是一个中间的圆圈(你需要手动调整大小),矩形占据整个大小。 fillType = PathFillType.evenOdd
很重要,因为它告诉路径填充应该在圆和矩形之间。
如果你想使用customPainter,路径将是相同的,你只需要绘制它。