blob: 17dd489b897b8c1da113a728b173f268c1fbe167 [file] [log] [blame]
// Copyright 2017 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:async';
import 'dart:math' as math;
import 'package:flutter/material.dart';
const double _kBorderWidth = 4.0;
const double _kBorderRadius = 8.0;
const double _kClipRadius = 12.0;
const int _kBlueStartingIndex = 0;
const int _kYellowStartingIndex = 3;
/// The mondrian spinner. A series of overlapping rectangular elements that
/// rotate. The parent of this [MondrianSpinner] must have non-infinite bounds.
/// The [MondrianSpinner] will center itself in its parent and have a diameter
/// equal to the minimum dimension.
class MondrianSpinner extends StatefulWidget {
@override
_MondrianSpinnerState createState() => new _MondrianSpinnerState();
}
class _MondrianSpinnerState extends State<MondrianSpinner> {
Timer _timer;
int _index = 0;
List<Rect> _positions;
@override
void initState() {
super.initState();
_timer = new Timer.periodic(
const Duration(milliseconds: 500),
(_) => setState(() {
_index = (_index + 1) % _positions.length;
}),
);
}
@override
void dispose() {
_timer?.cancel();
_timer = null;
super.dispose();
}
@override
Widget build(BuildContext context) => new LayoutBuilder(
builder: (BuildContext context, BoxConstraints constraints) {
double diameter = math.min(
constraints.maxWidth,
constraints.maxHeight,
);
_positions = <Rect>[
new Rect.fromLTWH(
0.0,
0.0,
diameter / 2.0 + _kBorderWidth / 2.0,
diameter,
),
new Rect.fromLTWH(
0.0,
diameter / 2.0 - _kBorderWidth / 2.0,
diameter / 2.0 + _kBorderWidth / 2.0,
diameter / 2.0 + _kBorderWidth / 2.0,
),
new Rect.fromLTWH(
0.0,
diameter / 2.0 - _kBorderWidth / 2.0,
diameter,
diameter / 2.0 + _kBorderWidth / 2.0,
),
new Rect.fromLTWH(
diameter / 2.0 - _kBorderWidth / 2.0,
diameter / 2.0 - _kBorderWidth / 2.0,
diameter / 2.0 + _kBorderWidth / 2.0,
diameter / 2.0 + _kBorderWidth / 2.0,
),
new Rect.fromLTWH(
diameter / 2.0 - _kBorderWidth / 2.0,
0.0,
diameter / 2.0 + _kBorderWidth / 2.0,
diameter,
),
new Rect.fromLTWH(
diameter / 2.0 - _kBorderWidth / 2.0,
0.0,
diameter / 2.0 + _kBorderWidth / 2.0,
diameter / 2.0 + _kBorderWidth / 2.0,
),
new Rect.fromLTWH(
0.0,
0.0,
diameter,
diameter / 2.0 + _kBorderWidth / 2.0,
),
new Rect.fromLTWH(
0.0,
0.0,
diameter / 2.0 + _kBorderWidth / 2.0,
diameter / 2.0 + _kBorderWidth / 2.0,
),
];
return new Center(
child: new Container(
width: diameter,
height: diameter,
decoration: new BoxDecoration(
color: Colors.black,
borderRadius: new BorderRadius.circular(_kBorderRadius),
),
foregroundDecoration: new BoxDecoration(
border: new Border.all(
color: Colors.black,
width: _kBorderWidth,
),
borderRadius: new BorderRadius.circular(_kBorderRadius),
),
child: new ClipRRect(
borderRadius: new BorderRadius.circular(_kClipRadius),
child: new Stack(
fit: StackFit.passthrough,
children: <Widget>[
new Container(
margin: const EdgeInsets.all(_kBorderWidth),
color: Colors.red[700],
),
new AnimatedPositioned(
left: _yellowPosition.left,
top: _yellowPosition.top,
width: _yellowPosition.width,
height: _yellowPosition.height,
curve: Curves.fastOutSlowIn,
duration: const Duration(milliseconds: 250),
child: new Container(
color: Colors.yellow[700],
foregroundDecoration: new BoxDecoration(
border: new Border.all(
color: Colors.black,
width: _kBorderWidth,
),
),
),
),
new AnimatedPositioned(
left: _bluePosition.left,
top: _bluePosition.top,
width: _bluePosition.width,
height: _bluePosition.height,
curve: Curves.fastOutSlowIn,
duration: const Duration(milliseconds: 250),
child: new Container(
color: Colors.blue[700],
foregroundDecoration: new BoxDecoration(
border: new Border.all(
color: Colors.black,
width: _kBorderWidth,
),
),
),
)
],
),
),
),
);
},
);
Rect get _bluePosition =>
_positions[(_index + _kBlueStartingIndex) % _positions.length];
Rect get _yellowPosition =>
_positions[(_index + _kYellowStartingIndex) % _positions.length];
}