gpt4 book ai didi

dart - Flutter-像巫师学校App一样的遮蔽效果

转载 作者:IT王子 更新时间:2023-10-29 07:00:16 26 4
gpt4 key购买 nike

这里我想做一个 mask 效果,比如Wizard School app。我在这里使用 RenderProxyBox 但我一次只能做一个蒙版,我想提供多次效果。我在这里使用 blendMode.clear 移除封面图像,然后显示图像。那么,是否有任何其他方法可以实现预期部分中给出的多重掩蔽效果。

import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'dart: math' as math;
class DemoApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Scratch Card',
home: Scaffold(
appBar: AppBar(
title: Text('Scratch Card'),
),
body: Material(
child: Center(
child: SizedBox(
width: 500.0,
height: 500.0,
child: Stack(
children: <Widget>[
ScratchCard(
cover: Stack(
fit: StackFit.expand,
children: <Widget>[
FittedBox(
child: Image.asset(
'assets/bird.jpg',
repeat: ImageRepeat.repeat,
),
),
],
),
reveal: DecoratedBox(
decoration: const BoxDecoration(color: Colors.black),
child: Center(
child:
FittedBox(child: Image.asset('assets/flower.jpg')),
),
),
strokeWidth: 15.0,
finishPercent: 50,
onComplete: () => print('The card is now clear!'),
),
],
),
),
),
),
),
);
}
}

class ScratchCard extends StatefulWidget {
const ScratchCard({
Key key,
this.cover,
this.reveal,
this.strokeWidth = 25.0,
this.finishPercent,
this.onComplete,
}) : super(key: key);

final Widget cover;
final Widget reveal;
final double strokeWidth;
final int finishPercent;
final VoidCallback onComplete;

@override
_ScratchCardState createState() => _ScratchCardState();
}

class _ScratchCardState extends State<ScratchCard> {
_ScratchData _data = _ScratchData();

Offset _lastPoint = null;

Offset _globalToLocal(Offset global) {
return (context.findRenderObject() as RenderBox).globalToLocal(global);
}

double _distanceBetween(Offset point1, Offset point2) {
return math.sqrt(math.pow(point2.dx - point1.dx, 2) +
math.pow(point2.dy - point1.dy, 2));
}

double _angleBetween(Offset point1, Offset point2) {
return math.atan2(point2.dx - point1.dx, point2.dy - point1.dy);
}

void _onPanDown(DragDownDetails details) {
_lastPoint = _globalToLocal(details.globalPosition);
}

void _onPanUpdate(DragUpdateDetails details) {
final currentPoint = _globalToLocal(details.globalPosition);
final distance = _distanceBetween(_lastPoint, currentPoint);
final angle = _angleBetween(_lastPoint, currentPoint);
for (double i = 0.0; i < distance; i++) {
_data.addPoint(Offset(
_lastPoint.dx + (math.sin(angle) * i),
_lastPoint.dy + (math.cos(angle) * i),
));
}
_lastPoint = currentPoint;
}

void _onPanEnd(TapUpDetails details) {
final areaRect = context.size.width * context.size.height;
double touchArea = math.pi * widget.strokeWidth * widget.strokeWidth;
double areaRevealed =
_data._points.fold(0.0, (double prev, Offset point) => touchArea);
print('areaRect $areaRect $areaRevealed');
}

@override
Widget build(BuildContext context) {
return GestureDetector(
behavior: HitTestBehavior.opaque,
onPanDown: _onPanDown,
onPanUpdate: _onPanUpdate,
onTapUp: _onPanEnd,
child: Stack(
fit: StackFit.expand,
children: <Widget>[
widget.reveal,
_ScratchCardLayout(
strokeWidth: widget.strokeWidth,
data: _data,
child: widget.cover,
),
],
),
);
}
}

class _ScratchCardLayout extends SingleChildRenderObjectWidget {
_ScratchCardLayout({
Key key,
this.strokeWidth = 25.0,
@required this.data,
@required this.child,
}) : super(
key: key,
child: child,
);

final Widget child;
final double strokeWidth;
final _ScratchData data;

@override
RenderObject createRenderObject(BuildContext context) {
return _ScratchCardRender(
strokeWidth: strokeWidth,
data: data,
);
}

@override
void updateRenderObject(
BuildContext context, _ScratchCardRender renderObject) {
renderObject
..strokeWidth = strokeWidth
..data = data;
}
}

class _ScratchCardRender extends RenderProxyBox {
_ScratchCardRender({
RenderBox child,
double strokeWidth,
_ScratchData data,
}) : assert(data != null),
_strokeWidth = strokeWidth,
_data = data,
super(child);

double _strokeWidth;
_ScratchData _data;

set strokeWidth(double strokeWidth) {
assert(strokeWidth != null);
if (_strokeWidth == strokeWidth) {
return;
}
_strokeWidth = strokeWidth;
markNeedsPaint();
}

set data(_ScratchData data) {
assert(data != null);
if (_data == data) {
return;
}
if (attached) {
_data.removeListener(markNeedsPaint);
data.addListener(markNeedsPaint);
}
_data = data;
markNeedsPaint();
}

@override
void attach(PipelineOwner owner) {
super.attach(owner);
_data.addListener(markNeedsPaint);
}

@override
void detach() {
_data.removeListener(markNeedsPaint);
super.detach();
}

@override
void paint(PaintingContext context, Offset offset) {
if (child != null) {
context.canvas.saveLayer(offset & size, Paint());
context.paintChild(child, offset);
Paint clear = Paint()..blendMode = BlendMode.clear;
_data._points.forEach((point) =>
context.canvas.drawCircle(offset + point, _strokeWidth, clear));
context.canvas.restore();
}
}

@override
bool get alwaysNeedsCompositing => child != null;
}

class _ScratchData extends ChangeNotifier {
List<Offset> _points = [];

void addPoint(Offset offset) {
_points.add(offset);
notifyListeners();
}
}

输出:- enter image description here

预期:- This first-time image masking is selected如果我改变颜色/图像而不是- enter image description here我想用新的更改颜色/图像并保留以前的。

最佳答案

第 1 步使用此代码将 JPG/PNG 转换为 ui.Image 格式。

ui.Image uiImage;
static Future<void> cacheImage(String asset) async {
if (maskImageMap[asset] == null) {
try {
ByteData data = await rootBundle.load(asset);
ui.Codec codec = await ui.instantiateImageCodec(
data.buffer.asUint8List(),
);
ui.FrameInfo fi = await codec.getNextFrame();
uiImage = fi.image;
} catch (e) {
print(e);
}
}
}

第 2 步:以像素格式划分图像。

final Float64List deviceTransform = new Float64List(16)
..[0] = devicePixelRatio
..[5] = devicePixelRatio
..[10] = 1.0
..[15] = 3.5;

第三步:使用ImageShader赋予mask滤镜效果。

 canvas.saveLayer();
Paint().shader = ImageShader(uiImage,
TileMode.repeated, TileMode.repeated, deviceTransform);

如果这个答案还不够,那么这是我的 git 链接 A Paint Application

关于dart - Flutter-像巫师学校App一样的遮蔽效果,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52242876/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com