您最多选择25个主题
主题必须以中文或者字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符
544 行
20 KiB
544 行
20 KiB
using System;
|
|
using Unity.UIWidgets.animation;
|
|
using Unity.UIWidgets.foundation;
|
|
using Unity.UIWidgets.painting;
|
|
using Unity.UIWidgets.rendering;
|
|
using Unity.UIWidgets.ui;
|
|
using Unity.UIWidgets.widgets;
|
|
using UnityEngine;
|
|
using Canvas = Unity.UIWidgets.ui.Canvas;
|
|
using Color = Unity.UIWidgets.ui.Color;
|
|
|
|
namespace Unity.UIWidgets.material {
|
|
class _ProgressIndicatorContants {
|
|
public const float _kLinearProgressIndicatorHeight = 6.0f;
|
|
public const float _kMinCircularProgressIndicatorSize = 36.0f;
|
|
public const int _kIndeterminateLinearDuration = 1800;
|
|
|
|
public static readonly Animatable<float> _kStrokeHeadTween = new CurveTween(
|
|
curve: new Interval(0.0f, 0.5f, curve: Curves.fastOutSlowIn)
|
|
).chain(new CurveTween(
|
|
curve: new SawTooth(5)
|
|
));
|
|
|
|
public static readonly Animatable<float> _kStrokeTailTween = new CurveTween(
|
|
curve: new Interval(0.5f, 1.0f, curve: Curves.fastOutSlowIn)
|
|
).chain(new CurveTween(
|
|
curve: new SawTooth(5)
|
|
));
|
|
|
|
public static readonly Animatable<int> _kStepTween = new StepTween(begin: 0, end: 5);
|
|
|
|
public static readonly Animatable<float> _kRotationTween = new CurveTween(curve: new SawTooth(5));
|
|
}
|
|
|
|
public abstract class ProgressIndicator : StatefulWidget {
|
|
public ProgressIndicator(
|
|
Key key = null,
|
|
float? value = null,
|
|
Color backgroundColor = null,
|
|
Animation<Color> valueColor = null
|
|
) : base(key: key) {
|
|
this.value = value;
|
|
this.backgroundColor = backgroundColor;
|
|
this.valueColor = valueColor;
|
|
}
|
|
|
|
public readonly float? value;
|
|
|
|
public readonly Color backgroundColor;
|
|
|
|
public readonly Animation<Color> valueColor;
|
|
|
|
public Color _getBackgroundColor(BuildContext context) {
|
|
return backgroundColor ?? Theme.of(context).backgroundColor;
|
|
}
|
|
|
|
public Color _getValueColor(BuildContext context) {
|
|
return valueColor?.value ?? Theme.of(context).accentColor;
|
|
}
|
|
|
|
public override void debugFillProperties(DiagnosticPropertiesBuilder properties) {
|
|
base.debugFillProperties(properties);
|
|
properties.add(new PercentProperty("value", value ?? 0.0f, showName: false,
|
|
ifNull: "<indeterminate>"));
|
|
}
|
|
}
|
|
|
|
class _LinearProgressIndicatorPainter : AbstractCustomPainter {
|
|
public _LinearProgressIndicatorPainter(
|
|
Color backgroundColor = null,
|
|
Color valueColor = null,
|
|
float? value = null,
|
|
float? animationValue = null
|
|
) {
|
|
this.backgroundColor = backgroundColor;
|
|
this.valueColor = valueColor;
|
|
this.value = value;
|
|
this.animationValue = animationValue;
|
|
}
|
|
|
|
public readonly Color backgroundColor;
|
|
public readonly Color valueColor;
|
|
public readonly float? value;
|
|
public readonly float? animationValue;
|
|
|
|
static readonly Curve line1Head = new Interval(
|
|
0.0f,
|
|
750.0f / _ProgressIndicatorContants._kIndeterminateLinearDuration,
|
|
curve: new Cubic(0.2f, 0.0f, 0.8f, 1.0f)
|
|
);
|
|
|
|
static readonly Curve line1Tail = new Interval(
|
|
333.0f / _ProgressIndicatorContants._kIndeterminateLinearDuration,
|
|
(333.0f + 750.0f) / _ProgressIndicatorContants._kIndeterminateLinearDuration,
|
|
curve: new Cubic(0.4f, 0.0f, 1.0f, 1.0f)
|
|
);
|
|
|
|
static readonly Curve line2Head = new Interval(
|
|
1000.0f / _ProgressIndicatorContants._kIndeterminateLinearDuration,
|
|
(1000.0f + 567.0f) / _ProgressIndicatorContants._kIndeterminateLinearDuration,
|
|
curve: new Cubic(0.0f, 0.0f, 0.65f, 1.0f)
|
|
);
|
|
|
|
static readonly Curve line2Tail = new Interval(
|
|
1267.0f / _ProgressIndicatorContants._kIndeterminateLinearDuration,
|
|
(1267.0f + 533.0f) / _ProgressIndicatorContants._kIndeterminateLinearDuration,
|
|
curve: new Cubic(0.10f, 0.0f, 0.45f, 1.0f)
|
|
);
|
|
|
|
public override void paint(Canvas canvas, Size size) {
|
|
Paint paint = new Paint();
|
|
paint.color = backgroundColor;
|
|
paint.style = PaintingStyle.fill;
|
|
canvas.drawRect(Offset.zero & size, paint);
|
|
|
|
paint.color = valueColor;
|
|
|
|
void drawBar(float x, float width) {
|
|
if (width <= 0.0f) {
|
|
return;
|
|
}
|
|
|
|
float left = x;
|
|
canvas.drawRect(new Offset(left, 0.0f) & new Size(width, size.height), paint);
|
|
}
|
|
|
|
if (value != null) {
|
|
drawBar(0.0f, value.Value.clamp(0.0f, 1.0f) * size.width);
|
|
}
|
|
else {
|
|
float x1 = size.width * line1Tail.transform(animationValue ?? 0.0f);
|
|
float width1 = size.width * line1Head.transform(animationValue ?? 0.0f) - x1;
|
|
|
|
float x2 = size.width * line2Tail.transform(animationValue ?? 0.0f);
|
|
float width2 = size.width * line2Head.transform(animationValue ?? 0.0f) - x2;
|
|
|
|
drawBar(x1, width1);
|
|
drawBar(x2, width2);
|
|
}
|
|
}
|
|
|
|
public override bool shouldRepaint(CustomPainter oldPainter) {
|
|
D.assert(oldPainter is _LinearProgressIndicatorPainter);
|
|
_LinearProgressIndicatorPainter painter = oldPainter as _LinearProgressIndicatorPainter;
|
|
return painter.backgroundColor != backgroundColor
|
|
|| painter.valueColor != valueColor
|
|
|| painter.value != value
|
|
|| painter.animationValue != animationValue;
|
|
}
|
|
}
|
|
|
|
public class LinearProgressIndicator : ProgressIndicator {
|
|
public LinearProgressIndicator(
|
|
Key key = null,
|
|
float? value = null,
|
|
Color backgroundColor = null,
|
|
Animation<Color> valueColor = null
|
|
) : base(
|
|
key: key,
|
|
value: value,
|
|
backgroundColor: backgroundColor,
|
|
valueColor: valueColor
|
|
) {
|
|
}
|
|
|
|
public override State createState() {
|
|
return new _LinearProgressIndicatorState();
|
|
}
|
|
}
|
|
|
|
class _LinearProgressIndicatorState : SingleTickerProviderStateMixin<LinearProgressIndicator> {
|
|
AnimationController _controller;
|
|
|
|
public _LinearProgressIndicatorState() {
|
|
}
|
|
|
|
public override void initState() {
|
|
base.initState();
|
|
_controller = new AnimationController(
|
|
duration: new TimeSpan(0, 0, 0, 0, _ProgressIndicatorContants._kIndeterminateLinearDuration),
|
|
vsync: this
|
|
);
|
|
if (widget.value == null) {
|
|
_controller.repeat();
|
|
}
|
|
}
|
|
|
|
public override void didUpdateWidget(StatefulWidget oldWidget) {
|
|
base.didUpdateWidget(oldWidget);
|
|
if (widget.value == null && !_controller.isAnimating) {
|
|
_controller.repeat();
|
|
}
|
|
else if (widget.value != null && _controller.isAnimating) {
|
|
_controller.stop();
|
|
}
|
|
}
|
|
|
|
public override void dispose() {
|
|
_controller.dispose();
|
|
base.dispose();
|
|
}
|
|
|
|
Widget _buildIndicator(BuildContext context, float animationValue) {
|
|
return new Container(
|
|
constraints: new BoxConstraints(
|
|
minWidth: float.PositiveInfinity,
|
|
minHeight: _ProgressIndicatorContants._kLinearProgressIndicatorHeight
|
|
),
|
|
child: new CustomPaint(
|
|
painter: new _LinearProgressIndicatorPainter(
|
|
backgroundColor: widget._getBackgroundColor(context),
|
|
valueColor: widget._getValueColor(context),
|
|
value: widget.value,
|
|
animationValue: animationValue
|
|
)
|
|
)
|
|
);
|
|
}
|
|
|
|
public override Widget build(BuildContext context) {
|
|
if (widget.value != null) {
|
|
return _buildIndicator(context, _controller.value);
|
|
}
|
|
|
|
return new AnimatedBuilder(
|
|
animation: _controller.view,
|
|
builder: (BuildContext _context, Widget child) => {
|
|
return _buildIndicator(_context, _controller.value);
|
|
}
|
|
);
|
|
}
|
|
}
|
|
|
|
class _CircularProgressIndicatorPainter : AbstractCustomPainter {
|
|
public _CircularProgressIndicatorPainter(
|
|
Color backgroundColor = null,
|
|
Color valueColor = null,
|
|
float? value = null,
|
|
float? headValue = null,
|
|
float? tailValue = null,
|
|
int? stepValue = null,
|
|
float? rotationValue = null,
|
|
float? strokeWidth = null
|
|
) {
|
|
this.backgroundColor = backgroundColor;
|
|
this.valueColor = valueColor;
|
|
this.value = value;
|
|
this.headValue = headValue;
|
|
this.tailValue = tailValue;
|
|
this.stepValue = stepValue;
|
|
this.rotationValue = rotationValue;
|
|
this.strokeWidth = strokeWidth;
|
|
arcStart = value != null
|
|
? _startAngle
|
|
: _startAngle + tailValue * 3 / 2 * Mathf.PI + rotationValue * Mathf.PI * 1.7f -
|
|
stepValue * 0.8f * Mathf.PI;
|
|
arcSweep = value != null
|
|
? value.Value.clamp(0.0f, 1.0f) * _sweep
|
|
: Mathf.Max(headValue * 3 / 2 * Mathf.PI - tailValue * 3 / 2 * Mathf.PI ?? 0.0f, _epsilon);
|
|
}
|
|
|
|
public readonly Color backgroundColor;
|
|
public readonly Color valueColor;
|
|
public readonly float? value;
|
|
public readonly float? headValue;
|
|
public readonly float? tailValue;
|
|
public readonly int? stepValue;
|
|
public readonly float? rotationValue;
|
|
public readonly float? strokeWidth;
|
|
public readonly float? arcStart;
|
|
public readonly float? arcSweep;
|
|
|
|
const float _twoPi = Mathf.PI * 2.0f;
|
|
const float _epsilon = .001f;
|
|
|
|
const float _sweep = _twoPi - _epsilon;
|
|
const float _startAngle = -Mathf.PI / 2.0f;
|
|
|
|
public override void paint(Canvas canvas, Size size) {
|
|
Paint paint = new Paint();
|
|
paint.color = valueColor;
|
|
paint.strokeWidth = strokeWidth ?? 0.0f;
|
|
paint.style = PaintingStyle.stroke;
|
|
|
|
if (backgroundColor != null) {
|
|
Paint backgroundPaint = new Paint() {
|
|
color = backgroundColor,
|
|
strokeWidth = strokeWidth ?? 0.0f,
|
|
style = PaintingStyle.stroke
|
|
};
|
|
canvas.drawArc(Offset.zero & size, 0, _sweep, false, backgroundPaint);
|
|
}
|
|
|
|
if (value == null)
|
|
{
|
|
paint.strokeCap = StrokeCap.square;
|
|
}
|
|
|
|
canvas.drawArc(Offset.zero & size, arcStart ?? 0.0f, arcSweep ?? 0.0f, false, paint);
|
|
}
|
|
|
|
public override bool shouldRepaint(CustomPainter oldPainter) {
|
|
D.assert(oldPainter is _CircularProgressIndicatorPainter);
|
|
_CircularProgressIndicatorPainter painter = oldPainter as _CircularProgressIndicatorPainter;
|
|
return painter.backgroundColor != backgroundColor
|
|
|| painter.valueColor != valueColor
|
|
|| painter.value != value
|
|
|| painter.headValue != headValue
|
|
|| painter.tailValue != tailValue
|
|
|| painter.stepValue != stepValue
|
|
|| painter.rotationValue != rotationValue
|
|
|| painter.strokeWidth != strokeWidth;
|
|
}
|
|
}
|
|
|
|
public class CircularProgressIndicator : ProgressIndicator {
|
|
public CircularProgressIndicator(
|
|
Key key = null,
|
|
float? value = null,
|
|
Color backgroundColor = null,
|
|
Animation<Color> valueColor = null,
|
|
float strokeWidth = 4.0f
|
|
) : base(
|
|
key: key,
|
|
value: value,
|
|
backgroundColor: backgroundColor,
|
|
valueColor: valueColor
|
|
) {
|
|
this.strokeWidth = strokeWidth;
|
|
}
|
|
|
|
public readonly float? strokeWidth;
|
|
|
|
public override State createState() {
|
|
return new _CircularProgressIndicatorState();
|
|
}
|
|
}
|
|
|
|
|
|
class _CircularProgressIndicatorState : SingleTickerProviderStateMixin<CircularProgressIndicator> {
|
|
protected AnimationController _controller;
|
|
|
|
public _CircularProgressIndicatorState() {
|
|
}
|
|
|
|
public override void initState() {
|
|
base.initState();
|
|
_controller = new AnimationController(
|
|
duration: new TimeSpan(0, 0, 0, 5),
|
|
vsync: this
|
|
);
|
|
if (widget.value == null) {
|
|
_controller.repeat();
|
|
}
|
|
}
|
|
|
|
public override void didUpdateWidget(StatefulWidget oldWidget) {
|
|
base.didUpdateWidget(oldWidget);
|
|
if (widget.value == null && !_controller.isAnimating) {
|
|
_controller.repeat();
|
|
}
|
|
else if (widget.value != null && _controller.isAnimating) {
|
|
_controller.stop();
|
|
}
|
|
}
|
|
|
|
public override void dispose() {
|
|
_controller.dispose();
|
|
base.dispose();
|
|
}
|
|
|
|
Widget _buildIndicator(BuildContext context, float headValue, float tailValue, int stepValue,
|
|
float rotationValue) {
|
|
return new Container(
|
|
constraints: new BoxConstraints(
|
|
minWidth: _ProgressIndicatorContants._kMinCircularProgressIndicatorSize,
|
|
minHeight: _ProgressIndicatorContants._kMinCircularProgressIndicatorSize
|
|
),
|
|
child: new CustomPaint(
|
|
painter: new _CircularProgressIndicatorPainter(
|
|
backgroundColor: widget.backgroundColor,
|
|
valueColor: widget._getValueColor(context),
|
|
value: widget.value,
|
|
headValue: headValue,
|
|
tailValue: tailValue,
|
|
stepValue: stepValue,
|
|
rotationValue: rotationValue,
|
|
strokeWidth: widget.strokeWidth
|
|
)
|
|
)
|
|
);
|
|
}
|
|
|
|
protected Widget _buildAnimation() {
|
|
return new AnimatedBuilder(
|
|
animation: _controller,
|
|
builder: (BuildContext context, Widget child) => {
|
|
return _buildIndicator(
|
|
context,
|
|
_ProgressIndicatorContants._kStrokeHeadTween.evaluate(_controller),
|
|
_ProgressIndicatorContants._kStrokeTailTween.evaluate(_controller),
|
|
_ProgressIndicatorContants._kStepTween.evaluate(_controller),
|
|
_ProgressIndicatorContants._kRotationTween.evaluate(_controller)
|
|
);
|
|
}
|
|
);
|
|
}
|
|
|
|
public override Widget build(BuildContext context) {
|
|
if (widget.value != null) {
|
|
return _buildIndicator(context, 0.0f, 0.0f, 0, 0.0f);
|
|
}
|
|
|
|
return _buildAnimation();
|
|
}
|
|
}
|
|
|
|
class _RefreshProgressIndicatorPainter : _CircularProgressIndicatorPainter {
|
|
public _RefreshProgressIndicatorPainter(
|
|
Color valueColor = null,
|
|
float? value = null,
|
|
float? headValue = null,
|
|
float? tailValue = null,
|
|
int? stepValue = null,
|
|
float? rotationValue = null,
|
|
float? strokeWidth = null,
|
|
float? arrowheadScale = null
|
|
) : base(
|
|
valueColor: valueColor,
|
|
value: value,
|
|
headValue: headValue,
|
|
tailValue: tailValue,
|
|
stepValue: stepValue,
|
|
rotationValue: rotationValue,
|
|
strokeWidth: strokeWidth
|
|
) {
|
|
this.arrowheadScale = arrowheadScale;
|
|
}
|
|
|
|
public readonly float? arrowheadScale;
|
|
|
|
void paintArrowhead(Canvas canvas, Size size) {
|
|
float arcEnd = arcStart + arcSweep ?? 0.0f;
|
|
float ux = Mathf.Cos(arcEnd);
|
|
float uy = Mathf.Sin(arcEnd);
|
|
|
|
D.assert(size.width == size.height);
|
|
float radius = size.width / 2.0f;
|
|
float? arrowheadPointX = radius + ux * radius + -uy * strokeWidth * 2.0f * arrowheadScale;
|
|
float? arrowheadPointY = radius + uy * radius + ux * strokeWidth * 2.0f * arrowheadScale;
|
|
float? arrowheadRadius = strokeWidth * 1.5f * arrowheadScale;
|
|
float? innerRadius = radius - arrowheadRadius;
|
|
float? outerRadius = radius + arrowheadRadius;
|
|
|
|
Path path = new Path();
|
|
path.moveTo(radius + ux * innerRadius ?? 0.0f, radius + uy * innerRadius ?? 0.0f);
|
|
path.lineTo(radius + ux * outerRadius ?? 0.0f, radius + uy * outerRadius ?? 0.0f);
|
|
path.lineTo(arrowheadPointX ?? 0.0f, arrowheadPointY ?? 0.0f);
|
|
path.close();
|
|
Paint paint = new Paint();
|
|
paint.color = valueColor;
|
|
paint.strokeWidth = strokeWidth ?? 0.0f;
|
|
paint.style = PaintingStyle.fill;
|
|
canvas.drawPath(path, paint);
|
|
}
|
|
|
|
public override void paint(Canvas canvas, Size size) {
|
|
base.paint(canvas, size);
|
|
if (arrowheadScale > 0.0) {
|
|
paintArrowhead(canvas, size);
|
|
}
|
|
}
|
|
}
|
|
|
|
public class RefreshProgressIndicator : CircularProgressIndicator {
|
|
public RefreshProgressIndicator(
|
|
Key key = null,
|
|
float? value = null,
|
|
Color backgroundColor = null,
|
|
Animation<Color> valueColor = null,
|
|
float strokeWidth = 2.0f
|
|
) : base(
|
|
key: key,
|
|
value: value,
|
|
backgroundColor: backgroundColor,
|
|
valueColor: valueColor,
|
|
strokeWidth: strokeWidth
|
|
) {
|
|
}
|
|
|
|
public override State createState() {
|
|
return new _RefreshProgressIndicatorState();
|
|
}
|
|
}
|
|
|
|
class _RefreshProgressIndicatorState : _CircularProgressIndicatorState {
|
|
const float _indicatorSize = 40.0f;
|
|
|
|
public _RefreshProgressIndicatorState() {
|
|
}
|
|
|
|
public override Widget build(BuildContext context) {
|
|
if (widget.value != null) {
|
|
_controller.setValue(widget.value / 10.0f ?? 0.0f);
|
|
}
|
|
else if (!_controller.isAnimating) {
|
|
_controller.repeat();
|
|
}
|
|
|
|
return _buildAnimation();
|
|
}
|
|
|
|
Widget _buildIndicator(BuildContext context, float headValue, float tailValue, int stepValue,
|
|
float rotationValue) {
|
|
float arrowheadScale =
|
|
widget.value == null ? 0.0f : (widget.value * 2.0f).Value.clamp(0.0f, 1.0f);
|
|
return new Container(
|
|
width: _indicatorSize,
|
|
height: _indicatorSize,
|
|
margin: EdgeInsets.all(4.0f),
|
|
child: new Material(
|
|
type: MaterialType.circle,
|
|
color: widget.backgroundColor ?? Theme.of(context).canvasColor,
|
|
elevation: 2.0f,
|
|
child: new Padding(
|
|
padding: EdgeInsets.all(12.0f),
|
|
child: new CustomPaint(
|
|
painter: new _RefreshProgressIndicatorPainter(
|
|
valueColor: widget._getValueColor(context),
|
|
value: null,
|
|
headValue: headValue,
|
|
tailValue: tailValue,
|
|
stepValue: stepValue,
|
|
rotationValue: rotationValue,
|
|
strokeWidth: widget.strokeWidth,
|
|
arrowheadScale: arrowheadScale
|
|
)
|
|
)
|
|
)
|
|
)
|
|
);
|
|
}
|
|
}
|
|
}
|