My main goal is, to create a flexible widget with features.
1 and 2, I've managed to make. but the 3rd point, when the widget finishes rotating and resizing the widget, the position will change and be erratic.
i really need you guys help. thanks
this is my code.
import 'package:flutter/material.dart';
void main() {
return runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
debugShowCheckedModeBanner: false,
home: const TestingDesign2(),
);
}
}
class Item{
Size size;
Offset offset;
double rotation;
var parentKey;
Item({required this.parentKey, required this.size, required this.offset, required this.rotation });
}
class TestingDesign2 extends StatefulWidget {
const TestingDesign2({super.key});
@override
State<TestingDesign2> createState() => _TestingDesign2State();
}
class _TestingDesign2State extends State<TestingDesign2> {
Item item = new Item(
parentKey: new GlobalKey(),
offset: Offset(10,10),
size: Size(150,150),
rotation: 0
);
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("Testing design 2")),
body: Container(
color: Colors.blueAccent.withOpacity(0.5),
child: Stack(
alignment: Alignment.center,
children: [ItemTesting(key: item.parentKey, item:item)],
),
));
}
}
class ItemTesting extends StatefulWidget {
Item item;
ItemTesting({super.key, required this.item});
@override
State<ItemTesting> createState() => _ItemTestingState();
}
class _ItemTestingState extends State<ItemTesting> {
double offsetAngle = 0;
bool isRotate = false;
@override
Widget build(BuildContext context) {
return _Item();
}
Widget _Item() {
return Positioned(
left: widget.item.offset.dx,
top: widget.item.offset.dy,
child: Transform.rotate(
angle: widget.item.rotation,
child: SizedBox(
height: widget.item.size.height,
width: widget.item.size.width,
child: Stack(
children: [
GestureDetector(
onPanStart: onPanStart,
onPanUpdate: onPanUpdate,
behavior: HitTestBehavior.translucent,
onPanEnd: (details) {
isRotate = false;
},
onPanCancel: () {
isRotate = false;
},
child: Container(
color: Colors.red,
height: widget.item.size.height,
width: widget.item.size.width,
),
),
IgnorePointer(
child: Align(
alignment: Alignment.topRight,
child: ClipOval(
child: Container(
height: 25,
width: 25,
color: Colors.blue,
child: Icon(Icons.rotate_right_outlined))),
),
),
Align(
alignment: Alignment.centerRight,
child: GestureDetector(
onPanUpdate: resizeRight,
child: Container(
height: 25,
width: 25,
color: Colors.yellow,
child: Icon(Icons.arrow_forward)))),
Align(
alignment: Alignment.bottomCenter,
child: GestureDetector(
onPanUpdate: resizeBottom,
child: Container(
height: 25,
width: 25,
color: Colors.yellow,
child: Icon(Icons.arrow_downward))))
],
),
),
),
);
}
var touchPosition = Offset.zero;
onPanStart(DragStartDetails details) {
Offset centerOfGestureDetector = Offset(widget.item.size.width / 2, widget.item.size.height / 2);
final touchPositionFromCenter =
details.localPosition - centerOfGestureDetector;
offsetAngle = touchPositionFromCenter.direction - widget.item.rotation;
final RenderBox referenceBox =
widget.item.parentKey.currentContext.findRenderObject();
var x = referenceBox.globalToLocal(details.globalPosition);
touchPosition = Offset(x.dx, x.dy + 55);
// top right
if (details.localPosition.dx > (widget.item.size.width - 25) &&
details.localPosition.dy <= 25) {
isRotate = true;
}
}
onPanUpdate(DragUpdateDetails details) {
if (isRotate) {
Offset centerOfGestureDetector = Offset(widget.item.size.width / 2, widget.item.size.height / 2);
final touchPositionFromCenter =
details.localPosition - centerOfGestureDetector;
widget.item.rotation = touchPositionFromCenter.direction - offsetAngle;
} else {
var positionG = widget.item.offset + details.globalPosition;
var positiong2 = positionG - touchPosition;
widget.item.offset = (positiong2 - widget.item.offset);
}
setState(() {});
}
//------------------------------------------------ resize widget
void resizeRight(DragUpdateDetails details) {
setState(() {
widget.item.size = Size(widget.item.size.width + details.delta.dx, widget.item.size.height);
});
}
void resizeBottom(DragUpdateDetails details) {
setState(() {
widget.item.size = Size(widget.item.size.width, widget.item.size.height + details.delta.dy);
});
}
}
You can compensate for the rotation by offsetting the position proportional to the cos
and sin
of the angle.
First, to use cos
and sin
functions, import the 'dart:math' library at the beginning:
import 'dart:math';
Then in your resizeRight
function:
void resizeRight(DragUpdateDetails details) {
setState(() {
widget.item.size = Size(widget.item.size.width + details.delta.dx, widget.item.size.height);
var angle = widget.item.rotation;
var rotationalOffset = Offset(cos(angle) - 1, sin(angle)) * details.delta.dx / 2;
widget.item.offset += rotationalOffset;
});
}
Likewise, in your resizeBottom
function:
void resizeBottom(DragUpdateDetails details) {
setState(() {
widget.item.size = Size(widget.item.size.width, widget.item.size.height + details.delta.dy);
var angle = widget.item.rotation;
var rotationalOffset = Offset(-sin(angle), cos(angle) - 1) * details.delta.dy / 2;
widget.item.offset += rotationalOffset;
});
}