Dart 在卡中任意定位小部件(基于相对于父级的x-y坐标)
我想在卡片上放置一个点,可以在卡片内部任意移动 到目前为止,这是我的解决方案Dart 在卡中任意定位小部件(基于相对于父级的x-y坐标),dart,flutter,Dart,Flutter,我想在卡片上放置一个点,可以在卡片内部任意移动 到目前为止,这是我的解决方案 class RoomCard extends StatefulWidget { final Room room; RoomCard({ @required this.room, }) : assert(room != null); @override _RoomCardState createState() => _RoomCardState(); } class _RoomCa
class RoomCard extends StatefulWidget {
final Room room;
RoomCard({
@required this.room,
}) : assert(room != null);
@override
_RoomCardState createState() => _RoomCardState();
}
class _RoomCardState extends State<RoomCard> {
double x = 0.0;
double y = 0.0;
@override
Widget build(BuildContext context) {
return SizedBox(
height: 400.0,
width: 400.0,
child: GestureDetector(
onPanUpdate: (p) {
setState(() {
x += p.delta.dx;
y += p.delta.dy;
});
},
child: Card(
child: Stack(
children: <Widget>[
Marker(
x: x,
y: y,
),
],
),
),
),
);
}
}
class Marker extends StatelessWidget {
final double x;
final double y;
Marker({this.x: 0.0, this.y: 0.0});
@override
Widget build(BuildContext context) {
print("x: $x, y: $y");
return Padding(
padding: EdgeInsets.only(left: x, top: y),
child: CircleAvatar(),
);
}
}
class RoomCard扩展StatefulWidget{
最后一个房间;
房卡({
@需要这个房间,
}):assert(房间!=null);
@凌驾
_RoomCardState createState();
}
类RoomCardState扩展了状态{
双x=0.0;
双y=0.0;
@凌驾
小部件构建(构建上下文){
返回大小框(
高度:400.0,
宽度:400.0,
儿童:手势检测器(
onPanUpdate:(p){
设置状态(){
x+=p.delta.dx;
y+=p.delta.dy;
});
},
孩子:卡片(
子:堆栈(
儿童:[
标记(
x:x,
y:y,
),
],
),
),
),
);
}
}
类标记扩展了无状态小部件{
最后的双x;
最后双y;
标记({this.x:0.0,this.y:0.0});
@凌驾
小部件构建(构建上下文){
打印(“x:$x,y:$y”);
返回填充(
填充:仅限边设置(左:x,上:y),
child:CircleAvatar(),
);
}
}
除了使用Padding小部件之外,我找不到任何其他方法基于x,y位置将标记放置在卡中。如果有其他更好的方法,请告诉我
其次,这是第一次(第一次移动它)。之后移动时出现问题。我在这里有没有遗漏什么逻辑
我想进一步扩展这一点,在卡片上有多个这样的点,可以易怒地放置和移动
如果您能推荐任何第三方软件包,我很高兴。您想要的可能是或 使用CustomSingleChildLayout看起来像这样:
class RoomCard extends StatefulWidget {
@override
_RoomCardState createState() => _RoomCardState();
}
class _RoomCardState extends State<RoomCard> {
Offset position = Offset.zero;
@override
Widget build(BuildContext context) {
return SizedBox(
height: 400.0,
width: 400.0,
child: GestureDetector(
onPanUpdate: (p) {
setState(() => position += p.delta);
},
child: CustomSingleChildLayout(
delegate: MarkerLayoutDelegate(position),
child: Marker(),
),
),
);
}
}
class CallableNotifier extends ChangeNotifier {
void notify() {
this.notifyListeners();
}
}
class MarkerLayoutDelegate extends SingleChildLayoutDelegate with ChangeNotifier {
Offset position;
MarkerLayoutDelegate(this.position);
@override
BoxConstraints getConstraintsForChild(BoxConstraints constraints) {
return constraints.loosen();
}
@override
Offset getPositionForChild(Size size, Size childSize) {
return Offset(min(position.dx, size.width - childSize.width), min(position.dy, size.height - childSize.height));
}
@override
bool shouldRelayout(MarkerLayoutDelegate oldDelegate) {
return position != oldDelegate.position;
}
}
class Marker extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Container(
width: 30,
height: 30,
child: CircleAvatar(),
);
}
}
class RoomCard扩展StatefulWidget{
@凌驾
_RoomCardState createState();
}
类RoomCardState扩展了状态{
偏移位置=偏移0.0;
@凌驾
小部件构建(构建上下文){
返回大小框(
高度:400.0,
宽度:400.0,
儿童:手势检测器(
onPanUpdate:(p){
设置状态(()=>位置+=p.delta);
},
子:CustomSingleChildLayout(
代表:MarkerLayout代表(职位),
子项:标记(),
),
),
);
}
}
类CallableNotifier扩展了ChangeNotifier{
作废通知(){
this.notifyListeners();
}
}
类MarkerLayoutDelegate使用ChangeNotifier扩展SingleChildLayoutDelegate{
偏置位置;
MarkerLayoutDelegate(该职位);
@凌驾
BoxConstraints getConstraintsForChild(BoxConstraints约束){
返回约束;
}
@凌驾
偏移量getPositionForChild(大小,大小childSize){
返回偏移量(最小值(position.dx,size.width-childSize.width),最小值(position.dy,size.height-childSize.height);
}
@凌驾
bool shouldrellayout(MarkerLayoutDelegate-oldDelegate){
返回位置!=oldDelegate.position;
}
}
类标记扩展了无状态小部件{
@凌驾
小部件构建(构建上下文){
返回容器(
宽度:30,
身高:30,
child:CircleAvatar(),
);
}
}
或者,您可以使用监听器以这样一种方式执行此操作,即主小部件不需要在每次点的位置更改时重新生成:
class RoomCard extends StatefulWidget {
@override
_RoomCardState createState() => _RoomCardState();
}
class _RoomCardState extends State<RoomCard> {
double x = 0.0;
double y = 0.0;
MarkerLayoutDelegate delegate = MarkerLayoutDelegate(relayout: CallableNotifier());
@override
Widget build(BuildContext context) {
return SizedBox(
height: 400.0,
width: 400.0,
child: GestureDetector(
onPanUpdate: (p) {
delegate.position += p.delta;
},
child: CustomSingleChildLayout(
delegate: delegate,
child: Marker(),
),
),
);
}
}
class CallableNotifier extends ChangeNotifier {
void notify() {
this.notifyListeners();
}
}
class MarkerLayoutDelegate extends SingleChildLayoutDelegate with ChangeNotifier {
Offset _position;
CallableNotifier _notifier;
MarkerLayoutDelegate({CallableNotifier relayout, Offset initialPosition = Offset.zero})
: _position = initialPosition,
_notifier = relayout,
super(relayout: relayout);
set position(Offset position) {
_position = position;
_notifier.notifyListeners();
}
Offset get position => _position;
@override
BoxConstraints getConstraintsForChild(BoxConstraints constraints) {
return constraints.loosen();
}
@override
Offset getPositionForChild(Size size, Size childSize) {
return Offset(min(_position.dx, size.width - childSize.width), min(_position.dy, size.height - childSize.height));
}
@override
bool shouldRelayout(MarkerLayoutDelegate oldDelegate) {
return _position != oldDelegate._position;
}
}
class Marker extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Container(
width: 30,
height: 30,
child: CircleAvatar(),
);
}
}
class RoomCard扩展StatefulWidget{
@凌驾
_RoomCardState createState();
}
类RoomCardState扩展了状态{
双x=0.0;
双y=0.0;
MarkerLayoutDelegate=MarkerLayoutDelegate(relayout:CallableNotifier());
@凌驾
小部件构建(构建上下文){
返回大小框(
高度:400.0,
宽度:400.0,
儿童:手势检测器(
onPanUpdate:(p){
delegate.position+=p.delta;
},
子:CustomSingleChildLayout(
代表:代表,
子项:标记(),
),
),
);
}
}
类CallableNotifier扩展了ChangeNotifier{
作废通知(){
this.notifyListeners();
}
}
类MarkerLayoutDelegate使用ChangeNotifier扩展SingleChildLayoutDelegate{
偏移位置;
CallableNotifier\u通知程序;
MarkerLayoutDelegate({CallableNotifier relayout,Offset initialPosition=Offset.zero})
:_位置=初始位置,
_通知程序=重新启动,
超级(重新播放:重新播放);
设置位置(偏移位置){
_位置=位置;
_notifyListeners();
}
偏移量获取位置=>\u位置;
@凌驾
BoxConstraints getConstraintsForChild(BoxConstraints约束){
返回约束;
}
@凌驾
偏移量getPositionForChild(大小,大小childSize){
返回偏移量(最小值(_position.dx,size.width-childSize.width),最小值(_position.dy,size.height-childSize.height));
}
@凌驾
bool shouldrellayout(MarkerLayoutDelegate-oldDelegate){
返回_位置!=oldDelegate._位置;
}
}
类标记扩展了无状态小部件{
@凌驾
小部件构建(构建上下文){
返回容器(
宽度:30,
身高:30,
child:CircleAvatar(),
);
}
}
您可以像下面这样使用Transform
class Marker extends StatelessWidget {
final double x;
final double y;
Marker({this.x: 0.0, this.y: 0.0});
@override
Widget build(BuildContext context) {
print("x: $x, y: $y");
return Transform(
transform: Matrix4.translationValues(x, y, 0.0), child: CircleAvatar());
}
}
您需要检查x、y约束以将变换绑定到特定区域
编辑:
这是一个完整的工作代码,用于说明如何约束卡底部边缘的标记
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
void main() {
runApp(new MaterialApp(
home: new Scaffold(
body: RoomCard(room: Room()),
),
));
}
class Room {}
class RoomCard extends StatefulWidget {
final Room room;
RoomCard({
@required this.room,
}) : assert(room != null);
@override
_RoomCardState createState() => _RoomCardState();
}
class _RoomCardState extends State<RoomCard> {
double x = 0.0;
double y = 0.0;
@override
Widget build(BuildContext context) {
//This hight should be known or calculated for the Widget need to be moved
const double markerHight = 50.0;
double ymax = context.findRenderObject()?.paintBounds?.bottom ?? markerHight ;
return SizedBox(
height: 300.0,
width: 400.0,
child: GestureDetector(
onPanUpdate: (p) {
setState(() {
x += p.delta.dx;
y = (y+p.delta.dy) >ymax - markerHight ? ymax -markerHight : y+p.delta.dy;
});
},
child: Card(
child: Stack(
children: <Widget>[
Marker(
x: x,
y: y,
),
],
),
),
),
);
}
}
class Marker extends StatelessWidget {
final double x;
final double y;
Marker({this.x: 0.0, this.y: 0.0});
@override
Widget build(BuildContext context) {
print("x: $x, y: $y");
return Transform(
transform: Matrix4.translationValues(x, y, 0.0),
child: CircleAvatar());
}
}
导入“包装:颤振/材料.省道”;
导入“package:flatter/rendering.dart”;
void main(){
runApp(新材料)PP(
家:新脚手架(
正文:RoomCard(房间:room()),
),
));
}
教室{}
类RoomCard扩展StatefulWidget{
最后一个房间;
房卡({
@需要这个房间,
}):assert(房间!=null);
@凌驾
_RoomCardState createState();
}
类_roomcardstateexte