flutter - 如何通过触摸旋转颤振小部件
问题描述
我正在开发一个设计应用程序。该应用程序包括将照片添加为贴纸,我想在贴纸的角落里给贴纸四个按钮,其中一个按钮在右上角,如下图所示,它的工作是旋转贴纸,我想要贴纸随触摸位置旋转
我的代码:
import 'dart:io';
import 'dart:math';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/painting.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter/widgets.dart';
import 'dart:async';
import 'package:matrix4_transform/matrix4_transform.dart';
import 'package:quotessec/myWidgets/background.dart';
class stickerOne extends StatefulWidget {
Map style;
StreamController<Map> streamController = StreamController<Map>.broadcast();
dynamic drag;
List<Map> styles;
Function onSubmit;
Function onTap;
Function onValueChange;
Function onDelete;
stickerOne(
{@required Key key,
@required this.style,
@required this.drag,
@required this.styles,
@required this.onSubmit,
@required this.onTap,
@required this.onValueChange,
@required this.onDelete})
: super(key: key);
get getIndex => style['index'];
get gisHidden => style['isHidden'];
get getChild => style['child'];
get getOffset => style['offset'];
get isDeleted => style['isDeleted'];
get sty => style;
get str => streamController;
get delete {
styles.remove(style);
return drag.remove(this);
}
set isHidden(isHidden) {
print('hidden');
style['isHidden'] = isHidden;
streamController.add(style);
}
// set delete(deleted) {
// style['isDeleted'] = true;
// streamController.add(style);
// drag.remove(this);
// }
@override
_stickerOneState createState() => _stickerOneState(
style: style,
);
}
class _stickerOneState extends State<stickerOne> {
Map style;
var stream;
_stickerOneState({@required this.style});
List<dynamic> sizes = [];
@override
void initState() {
stream = widget.streamController.stream;
super.initState();
stream.listen((sty) {
mySetState(sty);
});
WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
setState(() {
imageSizes();
});
});
}
mySetState(Map sty) {
if (this.mounted) {
setState(() {
style = sty;
});
}
}
imageSizes() async {
File image = style['child'];
var decodedImage = await decodeImageFromList(image.readAsBytesSync());
sizes = [decodedImage.height, decodedImage.width];
if (decodedImage.height * .2 >= 100 && decodedImage.height * .2 >= 100) {
style['height'] = double.tryParse(decodedImage.height.toString()) * .2;
style['width'] = double.tryParse(decodedImage.width.toString()) * .2;
} else if (decodedImage.height * .3 >= 100 &&
decodedImage.height * .3 >= 100) {
style['height'] = double.tryParse(decodedImage.height.toString()) * .3;
style['width'] = double.tryParse(decodedImage.width.toString()) * .3;
} else if (decodedImage.height * .4 >= 100 &&
decodedImage.height * .4 >= 100) {
style['height'] = double.tryParse(decodedImage.height.toString()) * .4;
style['width'] = double.tryParse(decodedImage.width.toString()) * .4;
} else {
style['height'] = double.tryParse(decodedImage.height.toString()) * .5;
style['width'] = double.tryParse(decodedImage.width.toString()) * .5;
}
setState(() {});
}
double minHeight;
double minWidth;
bool rotating = true;
_onDragUpdate(BuildContext context, DragUpdateDetails update) {
//print(update.globalPosition.toString());
RenderBox getBox = context.findRenderObject();
var local = getBox.getTransformTo(getBox);
print(local);
//print(local.dx.toString() + "|" + local.dy.toString());
}
double angle = 0.0;
@override
Widget build(BuildContext context) {
return !style['isHidden'] && !style['isDeleted']
? Positioned(
top: style['offset'].dy,
left: style['offset'].dx,
child: GestureDetector(
onTap: () {
if (!style['lock']) {
style['isEditing'] = true;
widget.streamController.add(style);
widget.styles.forEach((
element,
) {
if (element['index'] != style['index'] &&
element['isEditing'] == true) {
setState(() {
widget.styles[widget.styles.indexWhere(
(ele) => element['index'] == ele['index'])]
['isEditing'] = false;
widget.drag.forEach((element2) {
if (element2.runtimeType != background &&
element2.sty['index'] == element['index']) {
widget
.drag[widget.drag.indexWhere((ele2) =>
ele2.runtimeType != background &&
element2.sty['index'] ==
ele2.sty['index'])]
.str
.add(widget.styles[element['index']]);
}
});
});
}
});
widget.onTap(style, widget.streamController);
}
},
onPanUpdate: (details) {
if (!style['lock']) {
setState(() {
style['offset'] = Offset(
style['offset'].dx + details.delta.dx,
style['offset'].dy + details.delta.dy);
print(style['offset']);
});
}
},
child:Transform.rotate(
angle: angle,
child: Column(
children: [
style['isEditing']
? Container(
width:style['width'] + 50,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
mainAxisSize: MainAxisSize.max,
children: [
Transform(
alignment: Alignment.center,
transform: Matrix4Transform()
.rotateDegrees(-45)
.matrix4,
child: GestureDetector(
child: Container(
decoration: BoxDecoration(
color: Theme.of(context)
.primaryColor,
borderRadius:
BorderRadius.circular(25)),
child: Icon(Icons.arrow_upward,
color: Theme.of(context)
.accentColor),
),
onPanUpdate: (details) {
setState(() {
print(details.delta.direction);
if (details.delta.direction > 0) {
if (style['height'] > 0.01 &&
style['width'] > 0.01) {
print('shrinking');
style['height'] =
style['height'] -
(.1 * style['height']);
style['width'] =
style['width'] -
(.1 * style['width']);
print(style['height']);
}
} else {
style['height'] =
style['height'] +
(.1 * style['height']);
style['width'] = style['width'] +
(.1 * style['width']);
}
});
widget.onValueChange(style);
widget.streamController.add(style);
},
),
),
GestureDetector(
child: Container(
decoration: BoxDecoration(
color: Theme.of(context)
.primaryColor,
borderRadius:
BorderRadius.circular(25)),
child: Icon(Icons.rotate_left,color: Theme.of(context)
.accentColor,)
),
onPanUpdate: (details){
//I tried this but it did not work correctly
Offset centerOfGestureDetector = Offset(
style['offset'].dx / 2, style['offset'].dy / 2);
final touchPositionFromCenter =
details.localPosition - centerOfGestureDetector;
print(touchPositionFromCenter.direction * pi / 180);
setState(
() {
angle = touchPositionFromCenter.direction;
},
);
},
),
],
),
)
: Container(width: style['width'] + 50, height: 25),
Container(
height: style['height'],
width: style['width'],
decoration: BoxDecoration(
border: style['isEditing'] ? Border.all() : null,
),
child: style['color'][0] != null &&
style['color'][1] != null
? ShaderMask(
shaderCallback: (rect) {
return LinearGradient(
colors: [
style['color'][0],
style['color'][1]
],
begin: style['beginGradient'],
end: style['endGradient'],
).createShader(rect);
},
blendMode: BlendMode.srcATop,
child: Image.file(style['child'],
height: style['height'],
width: style['width']),
)
: ColorFiltered(
colorFilter: ColorFilter.mode(
style['soledColor'] != null
? style['soledColor']
: Colors.white,
BlendMode.modulate),
child: Image.file(style['child'],
height: style['height'],
width: style['width'])),
),
style['isEditing']
? Container(
width: style['width'] + 50,
child: Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: [
GestureDetector(
child: Container(
decoration: BoxDecoration(
color:
Theme.of(context).primaryColor,
borderRadius:
BorderRadius.circular(25)),
child: Icon(
Icons.check,
color: Theme.of(context).accentColor,
),
),
onTap: () {
style['isEditing'] = false;
widget.streamController.add(style);
widget.onSubmit(null);
},
),
GestureDetector(
child: Container(
decoration: BoxDecoration(
color:
Theme.of(context).primaryColor,
borderRadius:
BorderRadius.circular(25)),
child: Icon(
Icons.control_camera,
color: Theme.of(context).accentColor,
),
),
onPanUpdate: (details) {
setState(() {
style['offset'] = Offset(
style['offset'].dx +
details.delta.dx,
style['offset'].dy +
details.delta.dy);
});
//print(style['offset']);
},
),
],
),
)
: Container(width: style['width'] + 50, height: 25)
],
),
),
))
: Container();
}
}
解决方案
推荐阅读
- spring - 如何使用只有 tokenValue 的 OAuth2RestTemplate?
- python - 根据每个像素的位置有效地应用一个函数
- django - 如何在 django 管理操作的中间页面中从 request.POST 获取所有值
- c++ - template lambda expression in C++
- php - How to fix open_basedir restriction error in shared server?
- maven - 无法通过jenkins创建jar文件
- javascript - 如何制作带有图像背景的画布可以下载
- python-3.x - Reading url arguments to run a python script
- python - 我有一个代码或停止循环,我不知道我该怎么做才能停止
- spring - spring 是否支持从 spring cloud config/http url 加载 bootstrap.yml 文件?