Commit babe380f authored by Hans Muller's avatar Hans Muller

Adds CicularProgressIndicator and LinearProgressIndicator

Setting a ProgressIndicator's value to null (the default) makes it an "indeterminate progress" or activity indicator.

The indeterminate animations for both kinds of progress bars are essentially the same and wrong vis the Material Design spec, http://www.google.com/design/spec/components/progress-activity.html. I'll improve conformity with the visual design in a future CL.
parent 130119df
// 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:sky' as sky;
import 'package:sky/animation/animation_performance.dart';
import 'package:sky/animation/animated_value.dart';
import 'package:sky/animation/curves.dart';
import 'package:sky/theme/colors.dart';
import 'package:sky/widgets/basic.dart';
import 'package:sky/widgets/icon.dart';
import 'package:sky/widgets/progress_indicator.dart';
import 'package:sky/widgets/scaffold.dart';
import 'package:sky/widgets/theme.dart';
import 'package:sky/widgets/tool_bar.dart';
import 'package:sky/widgets/framework.dart';
import 'package:sky/widgets/task_description.dart';
import 'package:sky/widgets/transitions.dart';
class ProgressIndicatorApp extends App {
AnimationPerformance valueAnimation;
Direction valueAnimationDirection = Direction.forward;
void initState() {
super.initState();
valueAnimation = new AnimationPerformance()
..duration = const Duration(milliseconds: 1500)
..variable = new AnimatedValue<double>(
0.0,
end: 1.0,
curve: ease,
reverseCurve: ease,
interval: new Interval(0.0, 0.9)
);
}
void handleTap(sky.GestureEvent event) {
if (valueAnimation.isAnimating)
valueAnimation.stop();
else
valueAnimation.resume();
}
void reverseValueAnimationDirection() {
setState(() {
valueAnimationDirection = (valueAnimationDirection == Direction.forward)
? Direction.reverse
: Direction.forward;
});
}
Widget buildIndicators() {
List<Widget> indicators = <Widget>[
new SizedBox(
width: 200.0,
child: new LinearProgressIndicator()
),
new LinearProgressIndicator(),
new LinearProgressIndicator(),
new LinearProgressIndicator(value: valueAnimation.variable.value),
new CircularProgressIndicator(),
new SizedBox(
width: 20.0,
height: 20.0,
child: new CircularProgressIndicator(value: valueAnimation.variable.value)
),
new SizedBox(
width: 50.0,
height: 30.0,
child: new CircularProgressIndicator(value: valueAnimation.variable.value)
)
];
return new Flex(
indicators
.map((c) => new Container(child: c, margin: const EdgeDims.symmetric(vertical: 20.0)))
.toList(),
direction: FlexDirection.vertical,
justifyContent: FlexJustifyContent.center
);
}
Widget build() {
Widget body = new Listener(
onGestureTap: (e) { handleTap(e); },
child: new Container(
padding: const EdgeDims.symmetric(vertical: 12.0, horizontal: 8.0),
decoration: new BoxDecoration(backgroundColor: Theme.of(this).cardColor),
child: new BuilderTransition(
variables: [valueAnimation.variable],
direction: valueAnimationDirection,
performance: valueAnimation,
onDismissed: reverseValueAnimationDirection,
onCompleted: reverseValueAnimationDirection,
builder: buildIndicators
)
)
);
return new IconTheme(
data: const IconThemeData(color: IconThemeColor.white),
child: new Theme(
data: new ThemeData(
brightness: ThemeBrightness.light,
primarySwatch: Blue,
accentColor: RedAccent[200]
),
child: new TaskDescription(
label: 'Cards',
child: new Scaffold(
toolbar: new ToolBar(center: new Text('Progress Indicators')),
body: body
)
)
)
);
}
}
void main() {
runApp(new ProgressIndicatorApp());
}
// 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 'dart:sky' as sky;
import 'package:sky/animation/animation_performance.dart';
import 'package:sky/animation/animated_value.dart';
import 'package:sky/animation/curves.dart';
import 'package:sky/theme/colors.dart';
import 'package:sky/widgets/basic.dart';
import 'package:sky/widgets/icon.dart';
import 'package:sky/widgets/scaffold.dart';
import 'package:sky/widgets/theme.dart';
import 'package:sky/widgets/tool_bar.dart';
import 'package:sky/widgets/framework.dart';
import 'package:sky/widgets/task_description.dart';
import 'package:sky/widgets/transitions.dart';
const double _kLinearProgressIndicatorHeight = 6.0;
const double _kMinCircularProgressIndicatorSize = 15.0;
const double _kCircularProgressIndicatorStrokeWidth = 3.0;
abstract class ProgressIndicator extends StatefulComponent {
ProgressIndicator({
Key key,
this.value,
this.bufferValue
}) : super(key: key);
double value; // Null for non-determinate progress indicator.
double bufferValue; // TODO(hansmuller) implement the support for this.
AnimationPerformance _animation;
double get _animationValue => _animation.variable.value;
Color get _backgroundColor => Theme.of(this).primarySwatch[200];
Color get _valueColor => Theme.of(this).primaryColor;
void initState() {
_animation = new AnimationPerformance()
..duration = const Duration(milliseconds: 1500)
..variable = new AnimatedValue<double>(0.0, end: 1.0, curve: ease);
}
void syncFields(ProgressIndicator source) {
value = source.value;
bufferValue = source.bufferValue;
}
void _restartAnimation() {
_animation.progress = 0.0;
_animation.play();
}
Widget build() {
if (value != null)
return _buildIndicator();
return new BuilderTransition(
variables: [_animation.variable],
direction: Direction.forward,
performance: _animation,
onCompleted: _restartAnimation,
builder: _buildIndicator
);
}
Widget _buildIndicator();
}
class LinearProgressIndicator extends ProgressIndicator {
LinearProgressIndicator({
Key key,
double value,
double bufferValue
}) : super(key: key, value: value, bufferValue: bufferValue);
void _paint(sky.Canvas canvas, Size size) {
Paint paint = new Paint()
..color = _backgroundColor
..setStyle(sky.PaintingStyle.fill);
canvas.drawRect(Point.origin & size, paint);
paint.color = _valueColor;
if (value != null) {
double width = value.clamp(0.0, 1.0) * size.width;
canvas.drawRect(Point.origin & new Size(width, size.height), paint);
} else {
double startX = size.width * (1.5 * _animationValue - 0.5);
double endX = startX + 0.5 * size.width;
double x = startX.clamp(0.0, size.width);
double width = endX.clamp(0.0, size.width) - x;
canvas.drawRect(new Point(x, 0.0) & new Size(width, size.height), paint);
}
}
Widget _buildIndicator() {
return new Container(
child: new CustomPaint(callback: _paint),
constraints: new BoxConstraints.tightFor(
width: double.INFINITY,
height: _kLinearProgressIndicatorHeight
)
);
}
}
class CircularProgressIndicator extends ProgressIndicator {
static const _kTwoPI = math.PI * 2.0;
static const _kEpsilon = .0000001;
// Canavs.drawArc(r, 0, 2*PI) doesn't draw anything, so just get close.
static const _kSweep = _kTwoPI - _kEpsilon;
static const _kStartAngle = -math.PI / 2.0;
CircularProgressIndicator({
Key key,
double value,
double bufferValue
}) : super(key: key, value: value, bufferValue: bufferValue);
void _paint(sky.Canvas canvas, Size size) {
Paint paint = new Paint()
..color = _valueColor
..strokeWidth = _kCircularProgressIndicatorStrokeWidth
..setStyle(sky.PaintingStyle.stroke);
if (value != null) {
double angle = value.clamp(0.0, 1.0) * _kSweep;
sky.Path path = new sky.Path()
..arcTo(Point.origin & size, _kStartAngle, angle, false);
canvas.drawPath(path, paint);
} else {
double startAngle = _kTwoPI * (1.75 * _animationValue - 0.75);
double endAngle = startAngle + _kTwoPI * 0.75;
double arcAngle = startAngle.clamp(0.0, _kTwoPI);
double arcSweep = endAngle.clamp(0.0, _kTwoPI) - arcAngle;
sky.Path path = new sky.Path()
..arcTo(Point.origin & size, _kStartAngle + arcAngle, arcSweep, false);
canvas.drawPath(path, paint);
}
}
Widget _buildIndicator() {
return new Container(
child: new CustomPaint(callback: _paint),
constraints: new BoxConstraints(
minWidth: _kMinCircularProgressIndicatorSize,
minHeight: _kMinCircularProgressIndicatorSize
)
);
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment