// Copyright 2015 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. import 'dart:math' as math; import 'package:flutter/material.dart'; class ExampleDragTarget extends StatefulWidget { @override ExampleDragTargetState createState() => new ExampleDragTargetState(); } class ExampleDragTargetState extends State<ExampleDragTarget> { Color _color = Colors.grey[500]; void _handleAccept(Color data) { setState(() { _color = data; }); } @override Widget build(BuildContext context) { return new DragTarget<Color>( onAccept: _handleAccept, builder: (BuildContext context, List<Color> data, List<dynamic> rejectedData) { return new Container( height: 100.0, margin: new EdgeInsets.all(10.0), decoration: new BoxDecoration( border: new Border.all( width: 3.0, color: data.isEmpty ? Colors.white : Colors.blue[500] ), backgroundColor: data.isEmpty ? _color : Colors.grey[200] ) ); } ); } } class Dot extends StatefulWidget { Dot({ Key key, this.color, this.size, this.child, this.tappable: false }) : super(key: key); final Color color; final double size; final Widget child; final bool tappable; @override DotState createState() => new DotState(); } class DotState extends State<Dot> { int taps = 0; @override Widget build(BuildContext context) { return new GestureDetector( onTap: config.tappable ? () { setState(() { taps += 1; }); } : null, child: new Container( width: config.size, height: config.size, decoration: new BoxDecoration( backgroundColor: config.color, border: new Border.all(width: taps.toDouble()), shape: BoxShape.circle ), child: config.child ) ); } } class ExampleDragSource extends StatelessWidget { ExampleDragSource({ Key key, this.color, this.heavy: false, this.under: true, this.child }) : super(key: key); final Color color; final bool heavy; final bool under; final Widget child; static const double kDotSize = 50.0; static const double kHeavyMultiplier = 1.5; static const double kFingerSize = 50.0; @override Widget build(BuildContext context) { double size = kDotSize; if (heavy) size *= kHeavyMultiplier; Widget contents = new DefaultTextStyle( style: Theme.of(context).textTheme.body1, textAlign: TextAlign.center, child: new Dot( color: color, size: size, child: new Center(child: child) ) ); Widget feedback = new Opacity( opacity: 0.75, child: contents ); Offset feedbackOffset; DragAnchor anchor; if (!under) { feedback = new Transform( transform: new Matrix4.identity() ..translate(-size / 2.0, -(size / 2.0 + kFingerSize)), child: feedback ); feedbackOffset = const Offset(0.0, -kFingerSize); anchor = DragAnchor.pointer; } else { feedbackOffset = Offset.zero; anchor = DragAnchor.child; } if (heavy) { return new LongPressDraggable<Color>( data: color, child: contents, feedback: feedback, feedbackOffset: feedbackOffset, dragAnchor: anchor ); } else { return new Draggable<Color>( data: color, child: contents, feedback: feedback, feedbackOffset: feedbackOffset, dragAnchor: anchor ); } } } class DashOutlineCirclePainter extends CustomPainter { const DashOutlineCirclePainter(); static const int segments = 17; static const double deltaTheta = math.PI * 2 / segments; // radians static const double segmentArc = deltaTheta / 2.0; // radians static const double startOffset = 1.0; // radians @override void paint(Canvas canvas, Size size) { final double radius = size.shortestSide / 2.0; final Paint paint = new Paint() ..color = const Color(0xFF000000) ..style = PaintingStyle.stroke ..strokeWidth = radius / 10.0; final Path path = new Path(); final Rect box = Point.origin & size; for (double theta = 0.0; theta < math.PI * 2.0; theta += deltaTheta) path.addArc(box, theta + startOffset, segmentArc); canvas.drawPath(path, paint); } @override bool shouldRepaint(DashOutlineCirclePainter oldPainter) => false; } class MovableBall extends StatelessWidget { MovableBall(this.position, this.ballPosition, this.callback); final int position; final int ballPosition; final ValueChanged<int> callback; static final GlobalKey kBallKey = new GlobalKey(); static const double kBallSize = 50.0; @override Widget build(BuildContext context) { Widget ball = new DefaultTextStyle( style: Typography.white.body1, textAlign: TextAlign.center, child: new Dot( key: kBallKey, color: Colors.blue[700], size: kBallSize, tappable: true, child: new Center(child: new Text('BALL')) ) ); Widget dashedBall = new Container( width: kBallSize, height: kBallSize, child: new CustomPaint( painter: const DashOutlineCirclePainter() ) ); if (position == ballPosition) { return new Draggable<bool>( data: true, child: ball, childWhenDragging: dashedBall, feedback: ball, maxSimultaneousDrags: 1 ); } else { return new DragTarget<bool>( onAccept: (bool data) { callback(position); }, builder: (BuildContext context, List<bool> accepted, List<dynamic> rejected) { return dashedBall; } ); } } } class DragAndDropApp extends StatefulWidget { @override DragAndDropAppState createState() => new DragAndDropAppState(); } class DragAndDropAppState extends State<DragAndDropApp> { int position = 1; void moveBall(int newPosition) { setState(() { position = newPosition; }); } @override Widget build(BuildContext context) { return new Scaffold( appBar: new AppBar( title: new Text('Drag and Drop Flutter Demo') ), body: new Column( children: <Widget>[ new Flexible( child: new Row( children: <Widget>[ new ExampleDragSource( color: Colors.yellow[300], under: true, heavy: false, child: new Text('under') ), new ExampleDragSource( color: Colors.green[300], under: false, heavy: true, child: new Text('long-press above') ), new ExampleDragSource( color: Colors.indigo[300], under: false, heavy: false, child: new Text('above') ), ], crossAxisAlignment: CrossAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.spaceAround ) ), new Flexible( child: new Row( children: <Widget>[ new Flexible(child: new ExampleDragTarget()), new Flexible(child: new ExampleDragTarget()), new Flexible(child: new ExampleDragTarget()), new Flexible(child: new ExampleDragTarget()), ] ) ), new Flexible( child: new Row( children: <Widget>[ new MovableBall(1, position, moveBall), new MovableBall(2, position, moveBall), new MovableBall(3, position, moveBall), ], mainAxisAlignment: MainAxisAlignment.spaceAround ) ), ] ) ); } } void main() { runApp(new MaterialApp( title: 'Drag and Drop Flutter Demo', home: new DragAndDropApp() )); }