在Flutter中输入DragTarget时如何更新Draggable子级?

我有许多Draggables和DragTargets。在Draggable上,我指定了 childfeedback

,但是我也希望它更改当Draggable进入DragTarget时的外观。我看不到任何方法可以做到这一点。

每当我拖动Draggable时,我都会将其颜色更改为红色,但是,一旦它进入DragTarget,我想将Draggable颜色更新为绿色。

我知道DragTarget.OnWillAccept,只要Draggable进入DragTarget就会调用此方法,但是我只有 data

。我尝试用新颜色更新数据,然后调用setState,但这似乎不起作用。

关于如何获得这种行为的任何建议?

我想要类似以下回调Draggable.onEnteringDragTarget和的内容Draggable.onLeavingDragTarget

回答:

我能想到的唯一方法是使用streambuilder和将承载可拖动对象是否在拖动目标上的信息的流。此代码提供了基本的解决方案。

class _MyHomePageState extends State<MyHomePage> {

BehaviorSubject<bool> willAcceptStream;

@override

void initState() {

willAcceptStream = new BehaviorSubject<bool>();

willAcceptStream.add(false);

super.initState();

}

@override

Widget build(BuildContext context) {

return Scaffold(

appBar: AppBar(

title: Text(widget.title),

),

body: Column(

children: <Widget>[

Container(

height: 400,

width: double.infinity,

child: Container(

width: 100,

height: 100,

child: Center(

child: Draggable(

feedback: StreamBuilder(

initialData: false,

stream: willAcceptStream,

builder: (context, snapshot) {

return Container(

height: 100,

width: 100,

color: snapshot.data ? Colors.green : Colors.red,

);

},

),

childWhenDragging: Container(),

child: Container(

height: 100,

width: 100,

color: this.willAcceptStream.value ?? false

? Colors.green

: Colors.blue,

),

onDraggableCanceled: (v, f) => setState(

() {

this.willAcceptStream.add(false);

},

),

),

),

),

),

DragTarget(

builder: (context, list, list2) {

return Container(

height: 50,

width: double.infinity,

color: Colors.blueGrey,

child: Center(child: Text('TARGET ZONE'),),

);

},

onWillAccept: (item) {

debugPrint('will accept');

this.willAcceptStream.add(true);

return true;

},

onLeave: (item) {

debugPrint('left the target');

this.willAcceptStream.add(false);

},

),

],

),

);

}

}

编辑:第一个示例不会同时处理多个拖动,这更干净一些。

import 'package:rxdart/rxdart.dart';

import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {

// This widget is the root of your application.

@override

Widget build(BuildContext context) {

return MaterialApp(

title: 'Draggable Test',

theme: ThemeData(

primarySwatch: Colors.blue,

),

home: MyHomePage(),

);

}

}

class MyHomePage extends StatefulWidget {

MyHomePage({Key key}) : super(key: key);

@override

_MyHomePageState createState() => _MyHomePageState();

}

class _MyHomePageState extends State<MyHomePage> {

MyDraggableController<String> draggableController;

@override

void initState() {

this.draggableController = new MyDraggableController<String>();

super.initState();

}

@override

Widget build(BuildContext context) {

return Scaffold(

appBar: AppBar(

title: Text('Draggable Test'),

),

body: Column(

children: <Widget>[

Container(

height: 400,

width: double.infinity,

child: Container(

width: 100,

height: 100,

child: Center(

child: Stack(

children: <Widget>[

Positioned(

left: 30,

top: 30,

child: MyDraggable<String>(draggableController, 'Test1'),

),

Positioned(

left: 230,

top: 230,

child: MyDraggable<String>(draggableController, 'Test2'),

)

],

),

),

),

),

DragTarget<String>(

builder: (context, list, list2) {

return Container(

height: 50,

width: double.infinity,

color: Colors.blueGrey,

child: Center(

child: Text('TARGET ZONE'),

),

);

},

onWillAccept: (item) {

debugPrint('draggable is on the target');

this.draggableController.onTarget(true, item);

return true;

},

onLeave: (item) {

debugPrint('draggable has left the target');

this.draggableController.onTarget(false, item);

},

),

],

),

);

}

}

class MyDraggable<T> extends StatefulWidget {

final MyDraggableController<T> controller;

final T data;

MyDraggable(this.controller, this.data);

@override

_MyDraggableState createState() =>

_MyDraggableState<T>(this.controller, this.data);

}

class _MyDraggableState<T> extends State<MyDraggable> {

BehaviorSubject<DraggableInfo<T>> willAcceptStream;

MyDraggableController<T> controller;

T data;

_MyDraggableState(this.controller, this.data);

@override

void initState() {

willAcceptStream = this.controller._isOnTarget;

willAcceptStream.add(new DraggableInfo<T>(false, this.data));

super.initState();

}

@override

Widget build(BuildContext context) {

return Draggable<T>(

data: this.data,

feedback: StreamBuilder<DraggableInfo<T>>(

initialData: DraggableInfo<T>(false, this.data),

stream: willAcceptStream,

builder: (context, snapshot) {

return Container(

height: 100,

width: 100,

color: snapshot.data.isOnTarget && snapshot.data.data == this.data ? Colors.green : Colors.red,

);

},

),

childWhenDragging: Container(),

child: Container(

height: 100,

width: 100,

color: (this.willAcceptStream.value.isOnTarget ?? this.willAcceptStream.value.data == this.data)

? Colors.green

: Colors.blue,

),

onDraggableCanceled: (v, f) => setState(

() {

this.willAcceptStream.add(DraggableInfo(false, null));

},

),

);

}

}

class DraggableInfo<T> {

bool isOnTarget;

T data;

DraggableInfo(this.isOnTarget, this.data);

}

class MyDraggableController<T> {

BehaviorSubject<DraggableInfo<T>> _isOnTarget;

MyDraggableController() {

this._isOnTarget = new BehaviorSubject<DraggableInfo<T>>();

}

void onTarget(bool onTarget, T data) {

_isOnTarget.add(new DraggableInfo(onTarget, data));

}

}

编辑2:不使用流和streambuilder的解决方案。重要的是反馈小部件是有状态的。

import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {

// This widget is the root of your application.

@override

Widget build(BuildContext context) {

return MaterialApp(

title: 'Draggable Test',

theme: ThemeData(

primarySwatch: Colors.blue,

),

home: MyHomePage(),

);

}

}

class MyHomePage extends StatefulWidget {

MyHomePage({Key key}) : super(key: key);

@override

_MyHomePageState createState() => _MyHomePageState();

}

class _MyHomePageState extends State<MyHomePage> {

MyDraggableController<String> draggableController;

@override

void initState() {

this.draggableController = new MyDraggableController<String>();

super.initState();

}

@override

Widget build(BuildContext context) {

return Scaffold(

appBar: AppBar(

title: Text('Draggable Test'),

),

body: Column(

children: <Widget>[

Container(

height: 400,

width: double.infinity,

child: Container(

width: 100,

height: 100,

child: Center(

child: Stack(

children: <Widget>[

Positioned(

left: 30,

top: 30,

child: MyDraggable<String>(

draggableController,

'Test1',

),

),

Positioned(

left: 230,

top: 230,

child: MyDraggable<String>(

draggableController,

'Test2',

),

),

],

),

),

),

),

DragTarget<String>(

builder: (context, list, list2) {

return Container(

height: 100,

width: double.infinity,

color: Colors.blueGrey,

child: Center(

child: Text('TARGET ZONE'),

),

);

},

onWillAccept: (item) {

debugPrint('draggable is on the target $item');

this.draggableController.onTarget(true, item);

return true;

},

onLeave: (item) {

debugPrint('draggable has left the target $item');

this.draggableController.onTarget(false, item);

},

),

],

),

);

}

}

class MyDraggable<T> extends StatefulWidget {

final MyDraggableController<T> controller;

final T data;

MyDraggable(this.controller, this.data, {Key key}) : super(key: key);

@override

_MyDraggableState createState() =>

_MyDraggableState<T>(this.controller, this.data);

}

class _MyDraggableState<T> extends State<MyDraggable> {

MyDraggableController<T> controller;

T data;

bool isOnTarget;

_MyDraggableState(this.controller, this.data);

FeedbackController feedbackController;

@override

void initState() {

feedbackController = new FeedbackController();

this.controller.subscribeToOnTargetCallback(onTargetCallbackHandler);

super.initState();

}

void onTargetCallbackHandler(bool t, T data) {

this.isOnTarget = t && data == this.data;

this.feedbackController.updateFeedback(this.isOnTarget);

}

@override

void dispose() {

this.controller.unSubscribeFromOnTargetCallback(onTargetCallbackHandler);

super.dispose();

}

@override

Widget build(BuildContext context) {

return Draggable<T>(

data: this.data,

feedback: FeedbackWidget(feedbackController),

childWhenDragging: Container(

height: 100,

width: 100,

color: Colors.blue[50],

),

child: Container(

height: 100,

width: 100,

color: (this.isOnTarget ?? false) ? Colors.green : Colors.blue,

),

onDraggableCanceled: (v, f) => setState(

() {

this.isOnTarget = false;

this.feedbackController.updateFeedback(this.isOnTarget);

},

),

);

}

}

class FeedbackController {

Function(bool) feedbackNeedsUpdateCallback;

void updateFeedback(bool isOnTarget) {

if (feedbackNeedsUpdateCallback != null) {

feedbackNeedsUpdateCallback(isOnTarget);

}

}

}

class FeedbackWidget extends StatefulWidget {

final FeedbackController controller;

FeedbackWidget(this.controller);

@override

_FeedbackWidgetState createState() => _FeedbackWidgetState();

}

class _FeedbackWidgetState extends State<FeedbackWidget> {

bool isOnTarget;

@override

void initState() {

this.isOnTarget = false;

this.widget.controller.feedbackNeedsUpdateCallback = feedbackNeedsUpdateCallbackHandler;

super.initState();

}

void feedbackNeedsUpdateCallbackHandler(bool t) {

setState(() {

this.isOnTarget = t;

});

}

@override

Widget build(BuildContext context) {

return Container(

height: 100,

width: 100,

color: this.isOnTarget ?? false ? Colors.green : Colors.red,

);

}

@override

void dispose() {

this.widget.controller.feedbackNeedsUpdateCallback = null;

super.dispose();

}

}

class DraggableInfo<T> {

bool isOnTarget;

T data;

DraggableInfo(this.isOnTarget, this.data);

}

class MyDraggableController<T> {

List<Function(bool, T)> _targetUpdateCallbacks = new List<Function(bool, T)>();

MyDraggableController();

void onTarget(bool onTarget, T data) {

if (_targetUpdateCallbacks != null) {

_targetUpdateCallbacks.forEach((f) => f(onTarget, data));

}

}

void subscribeToOnTargetCallback(Function(bool, T) f) {

_targetUpdateCallbacks.add(f);

}

void unSubscribeFromOnTargetCallback(Function(bool, T) f) {

_targetUpdateCallbacks.remove(f);

}

}

以上是 在Flutter中输入DragTarget时如何更新Draggable子级? 的全部内容, 来源链接: utcz.com/qa/397295.html

回到顶部