blob: 71a0b73d3af85884bdde0fb088dd4d6aef39d1bc [file] [log] [blame]
// 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;
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: const EdgeInsets.all(10.0),
decoration: new BoxDecoration(
color: data.isEmpty ? _color : Colors.grey.shade200,
border: new Border.all(
width: 3.0,
color: data.isEmpty ? Colors.white : Colors.blue
),
)
);
}
);
}
}
class Dot extends StatefulWidget {
const 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: widget.tappable ? () { setState(() { taps += 1; }); } : null,
child: new Container(
width: widget.size,
height: widget.size,
decoration: new BoxDecoration(
color: widget.color,
border: new Border.all(width: taps.toDouble()),
shape: BoxShape.circle
),
child: widget.child
)
);
}
}
class ExampleDragSource extends StatelessWidget {
const 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;
final 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 = Offset.zero & 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 {
const 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) {
final Widget ball = new DefaultTextStyle(
style: Theme.of(context).primaryTextTheme.body1,
textAlign: TextAlign.center,
child: new Dot(
key: kBallKey,
color: Colors.blue.shade700,
size: kBallSize,
tappable: true,
child: const Center(child: const Text('BALL'))
)
);
final Widget dashedBall = new Container(
width: kBallSize,
height: kBallSize,
child: const 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: const Text('Drag and Drop Flutter Demo')
),
body: new Column(
children: <Widget>[
new Expanded(
child: new Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: <Widget>[
new ExampleDragSource(
color: Colors.yellow.shade300,
under: true,
heavy: false,
child: const Text('under')
),
new ExampleDragSource(
color: Colors.green.shade300,
under: false,
heavy: true,
child: const Text('long-press above')
),
new ExampleDragSource(
color: Colors.indigo.shade300,
under: false,
heavy: false,
child: const Text('above')
),
],
)
),
new Expanded(
child: new Row(
children: <Widget>[
new Expanded(child: new ExampleDragTarget()),
new Expanded(child: new ExampleDragTarget()),
new Expanded(child: new ExampleDragTarget()),
new Expanded(child: new ExampleDragTarget()),
]
)
),
new Expanded(
child: new Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: <Widget>[
new MovableBall(1, position, moveBall),
new MovableBall(2, position, moveBall),
new MovableBall(3, position, moveBall),
],
)
),
]
)
);
}
}
void main() {
runApp(new MaterialApp(
title: 'Drag and Drop Flutter Demo',
home: new DragAndDropApp()
));
}