浏览代码

Implement animated icons.

/main
Yuncong Zhang 6 年前
当前提交
29fa7700
共有 23 个文件被更改,包括 4032 次插入294 次删除
  1. 23
      Runtime/rendering/stack.cs
  2. 334
      Runtime/widgets/banner.cs
  3. 11
      Runtime/widgets/transitions.cs
  4. 257
      Samples/UIWidgetsGallery/gallery/home.cs
  5. 8
      Runtime/material/animated_icons.meta
  6. 11
      Runtime/widgets/animated_switcher.cs.meta
  7. 365
      Samples/UIWidgetsGallery/gallery/backdrop.cs
  8. 3
      Samples/UIWidgetsGallery/gallery/backdrop.cs.meta
  9. 213
      Runtime/material/animated_icons/animated_icons.cs
  10. 11
      Runtime/material/animated_icons/animated_icons.cs.meta
  11. 56
      Runtime/material/animated_icons/animated_icons_data.cs
  12. 3
      Runtime/material/animated_icons/animated_icons_data.cs.meta
  13. 8
      Runtime/material/animated_icons/data.meta
  14. 1001
      Runtime/material/animated_icons/data/add_event.g.cs
  15. 11
      Runtime/material/animated_icons/data/add_event.g.cs.meta
  16. 1001
      Runtime/material/animated_icons/data/arrow_menu.g.cs
  17. 3
      Runtime/material/animated_icons/data/arrow_menu.g.cs.meta
  18. 1001
      Runtime/material/animated_icons/data/close_menu.g.cs
  19. 3
      Runtime/material/animated_icons/data/close_menu.g.cs.meta
  20. 3
      Runtime/widgets/auto_switcher.cs.meta
  21. 0
      /Runtime/widgets/animated_switcher.cs

23
Runtime/rendering/stack.cs


container.height - this.bottom);
}
public static RelativeRect lerp(RelativeRect a, RelativeRect b, float t) {
D.assert(t != null);
if (a == null && b == null) {
return null;
}
if (a == null) {
return fromLTRB(b.left * t, b.top * t, b.right * t, b.bottom * t);
}
if (b == null) {
float k = 1.0f - t;
return fromLTRB(b.left * k, b.top * k, b.right * k, b.bottom * k);
}
return fromLTRB(
MathUtils.lerpFloat(a.left, b.left, t),
MathUtils.lerpFloat(a.top, b.top, t),
MathUtils.lerpFloat(a.right, b.right, t),
MathUtils.lerpFloat(a.bottom, b.bottom, t)
);
}
public bool Equals(RelativeRect other) {
if (ReferenceEquals(null, other)) {
return false;

334
Runtime/widgets/banner.cs


using Unity.UIWidgets.foundation;
using Unity.UIWidgets.painting;
using Unity.UIWidgets.ui;
using Unity.UIWidgets.widgets;
using UnityEngine;
using Canvas = Unity.UIWidgets.ui.Canvas;
using Color = Unity.UIWidgets.ui.Color;

public static readonly Rect _kRect = Rect.fromLTWH(-_kOffset, _kOffset - _kHeight, _kOffset * 2.0f, _kHeight);
public static readonly Color _kColor = new Color(0xA0B71C1C);
color: new Color(0xFFFFFFFF),
fontSize: _kHeight * 0.85f,
fontWeight: FontWeight.w700,
height: 1.0f
color: new Color(0xFFFFFFFF),
fontSize: _kHeight * 0.85f,
fontWeight: FontWeight.w700,
height: 1.0f
topStart,
topStart,
topEnd,
topEnd,
bottomStart,
bottomStart,
bottomEnd,
bottomEnd,
public BannerPainter(
string message,
BannerLocation? location,
Color color = null,
TextStyle textStyle = null
) {D.assert(message != null);
D.assert(location != null);
D.assert(textStyle != null);
this.color = color ?? BannerConstants._kColor;
this.message = message;
this.location = location;
this.textStyle = textStyle ?? BannerConstants._kTextStyle;
}
public BannerPainter(
string message,
BannerLocation? location,
Color color = null,
TextStyle textStyle = null
) {
D.assert(message != null);
D.assert(location != null);
D.assert(textStyle != null);
this.color = color ?? BannerConstants._kColor;
this.message = message;
this.location = location;
this.textStyle = textStyle ?? BannerConstants._kTextStyle;
}
public readonly string message;
public readonly string message;
public readonly BannerLocation? location;
public readonly BannerLocation? location;
public readonly Color color;
public readonly Color color;
public readonly TextStyle textStyle;
public readonly TextStyle textStyle;
readonly BoxShadow _shadow = new BoxShadow(
color: new Color(0x7F000000),
blurRadius: 6.0f
);
readonly BoxShadow _shadow = new BoxShadow(
color: new Color(0x7F000000),
blurRadius: 6.0f
);
bool _prepared = false;
TextPainter _textPainter;
Paint _paintShadow;
Paint _paintBanner;
bool _prepared = false;
TextPainter _textPainter;
Paint _paintShadow;
Paint _paintBanner;
void _prepare() {
this._paintShadow = this._shadow.toPaint();
this._paintBanner = new Paint();
this._paintBanner.color = this.color;
this._textPainter = new TextPainter(
text: new TextSpan(style: this.textStyle, text: this.message),
textAlign: TextAlign.center
void _prepare() {
this._paintShadow = this._shadow.toPaint();
this._paintBanner = new Paint();
this._paintBanner.color = this.color;
this._textPainter = new TextPainter(
text: new TextSpan(style: this.textStyle, text: this.message),
textAlign: TextAlign.center
this._prepared = true;
}
this._prepared = true;
}
public override void paint(Canvas canvas, Size size) {
if (!this._prepared) this._prepare();
canvas.translate(this._translationX(size.width), this._translationY(size.height));
canvas.rotate(this._rotation);
canvas.drawRect(BannerConstants._kRect, this._paintShadow);
canvas.drawRect(BannerConstants._kRect, this._paintBanner);
const float width = BannerConstants._kOffset * 2.0f;
this._textPainter.layout(minWidth: width, maxWidth: width);
this._textPainter.paint(canvas, BannerConstants._kRect.topLeft + new Offset(0.0f, (BannerConstants._kRect.height - this._textPainter.height) / 2.0f));
}
public override void paint(Canvas canvas, Size size) {
if (!this._prepared) {
this._prepare();
}
public override bool shouldRepaint(CustomPainter _oldDelegate) {
BannerPainter oldDelegate = _oldDelegate as BannerPainter;
return this.message != oldDelegate.message
|| this.location != oldDelegate.location
|| this.color != oldDelegate.color
|| this.textStyle != oldDelegate.textStyle;
}
canvas.translate(this._translationX(size.width), this._translationY(size.height));
canvas.rotate(this._rotation);
canvas.drawRect(BannerConstants._kRect, this._paintShadow);
canvas.drawRect(BannerConstants._kRect, this._paintBanner);
const float width = BannerConstants._kOffset * 2.0f;
this._textPainter.layout(minWidth: width, maxWidth: width);
this._textPainter.paint(canvas,
BannerConstants._kRect.topLeft + new Offset(0.0f,
(BannerConstants._kRect.height - this._textPainter.height) / 2.0f));
}
public override bool shouldRepaint(CustomPainter _oldDelegate) {
BannerPainter oldDelegate = _oldDelegate as BannerPainter;
return this.message != oldDelegate.message
|| this.location != oldDelegate.location
|| this.color != oldDelegate.color
|| this.textStyle != oldDelegate.textStyle;
}
public override bool? hitTest(Offset position) => false;
public override bool? hitTest(Offset position) {
return false;
}
float _translationX(float width) {
float _translationX(float width) {
case BannerLocation.bottomEnd:
return width - BannerConstants._kBottomOffset;
case BannerLocation.topEnd:
return width;
case BannerLocation.bottomStart:
return BannerConstants._kBottomOffset;
case BannerLocation.topStart:
return 0.0f;
default:
throw new Exception("Unknown location: " + this.location);
case BannerLocation.bottomEnd:
return width - BannerConstants._kBottomOffset;
case BannerLocation.topEnd:
return width;
case BannerLocation.bottomStart:
return BannerConstants._kBottomOffset;
case BannerLocation.topStart:
return 0.0f;
default:
throw new Exception("Unknown location: " + this.location);
}
}
float _translationY(float height) {
D.assert(this.location != null);
switch (this.location) {
case BannerLocation.bottomStart:
case BannerLocation.bottomEnd:
return height - BannerConstants._kBottomOffset;
case BannerLocation.topStart:
case BannerLocation.topEnd:
return 0.0f;
default:
throw new Exception("Unknown location: " + this.location);
float _translationY(float height) {
D.assert(this.location != null);
switch (this.location) {
case BannerLocation.bottomStart:
case BannerLocation.bottomEnd:
return height - BannerConstants._kBottomOffset;
case BannerLocation.topStart:
case BannerLocation.topEnd:
return 0.0f;
default:
throw new Exception("Unknown location: " + this.location);
}
}
float _rotation {
get {
switch (this.location) {
case BannerLocation.bottomStart:
case BannerLocation.topEnd:
return Mathf.PI / 4.0f;
case BannerLocation.bottomEnd:
case BannerLocation.topStart:
return -Mathf.PI / 4.0f;
default:
throw new Exception("Unknown location: " + this.location);
}
}
}
float _rotation {
get {
switch (this.location) {
case BannerLocation.bottomStart:
case BannerLocation.topEnd:
return Mathf.PI / 4.0f;
case BannerLocation.bottomEnd:
case BannerLocation.topStart:
return -Mathf.PI / 4.0f;
default:
throw new Exception("Unknown location: " + this.location);
}
}
}
public Banner(
Key key = null,
Widget child = null,
string message = null,
BannerLocation? location = null,
Color color = null,
TextStyle textStyle = null
) : base(key: key) {
D.assert(message != null);
D.assert(color != null);
D.assert(textStyle != null);
this.child = child;
this.message = message;
this.location = location;
this.color = color ?? BannerConstants._kColor;
this.textStyle = textStyle ?? BannerConstants._kTextStyle;
}
public Banner(
Key key = null,
Widget child = null,
string message = null,
BannerLocation? location = null,
Color color = null,
TextStyle textStyle = null
) : base(key: key) {
D.assert(message != null);
D.assert(color != null);
D.assert(textStyle != null);
this.child = child;
this.message = message;
this.location = location;
this.color = color ?? BannerConstants._kColor;
this.textStyle = textStyle ?? BannerConstants._kTextStyle;
}
public readonly Widget child;
public readonly Widget child;
public readonly String message;
public readonly string message;
public readonly BannerLocation? location;
public readonly BannerLocation? location;
public readonly Color color;
public readonly Color color;
public readonly TextStyle textStyle;
public readonly TextStyle textStyle;
public override Widget build(BuildContext context) {
D.assert(WidgetsD.debugCheckHasDirectionality(context));
return new CustomPaint(
foregroundPainter: new BannerPainter(
message: this.message,
location: this.location,
color: this.color,
textStyle: this.textStyle
),
child: this.child
);
}
public override Widget build(BuildContext context) {
D.assert(WidgetsD.debugCheckHasDirectionality(context));
return new CustomPaint(
foregroundPainter: new BannerPainter(
message: this.message,
location: this.location,
color: this.color,
textStyle: this.textStyle
),
child: this.child
);
}
public override void debugFillProperties(DiagnosticPropertiesBuilder properties) {
base.debugFillProperties(properties);
properties.add(new StringProperty("message", this.message, showName: false));
properties.add(new EnumProperty<BannerLocation?>("location", this.location));
properties.add(new DiagnosticsProperty<Color>("color", this.color, showName: false));
this.textStyle?.debugFillProperties(properties);
}
public override void debugFillProperties(DiagnosticPropertiesBuilder properties) {
base.debugFillProperties(properties);
properties.add(new StringProperty("message", this.message, showName: false));
properties.add(new EnumProperty<BannerLocation?>("location", this.location));
properties.add(new DiagnosticsProperty<Color>("color", this.color, showName: false));
this.textStyle?.debugFillProperties(properties);
}
}
public class CheckedModeBanner : StatelessWidget {

D.assert(child != null);
this.child = child;
}
public readonly Widget child;
public readonly Widget child;
public override Widget build(BuildContext context) {
Widget result = this.child;
D.assert(() => {
result = new Banner(
child: result,
message: "DEBUG",
location: BannerLocation.topEnd
);
return true;
});
return result;
}
public override Widget build(BuildContext context) {
Widget result = this.child;
D.assert(() => {
result = new Banner(
child: result,
message: "DEBUG",
location: BannerLocation.topEnd
);
return true;
});
return result;
}
public override void debugFillProperties(DiagnosticPropertiesBuilder properties) {
base.debugFillProperties(properties);
String message = "disabled";
D.assert(() => {
message = "'DEBUG'";
return true;
});
properties.add(DiagnosticsNode.message(message));
}
public override void debugFillProperties(DiagnosticPropertiesBuilder properties) {
base.debugFillProperties(properties);
string message = "disabled";
D.assert(() => {
message = "'DEBUG'";
return true;
});
properties.add(DiagnosticsNode.message(message));
}
}
}

11
Runtime/widgets/transitions.cs


}
}
public class RelativeRectTween : Tween<RelativeRect> {
public RelativeRectTween(RelativeRect begin = null, RelativeRect end = null) : base(begin: begin, end: end) {
}
public override RelativeRect lerp(float t) {
return RelativeRect.lerp(this.begin, this.end, t);
}
}
public class PositionedTransition : AnimatedWidget {
public PositionedTransition(

D.assert(rect != null);
D.assert(size != null);
D.assert(child != null);
this.size = size;
this.child = child;
}
Animation<Rect> rect {

257
Samples/UIWidgetsGallery/gallery/home.cs


public static bool showPreviewBanner = true;
public override State createState() {
return new _GalleryHomeState();
// return new _GalleryHomeState();
return null;
class _GalleryHomeState : SingleTickerProviderStateMixin<GalleryHome> {
static readonly GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>.key();
AnimationController _controller;
GalleryDemoCategory _category;
static Widget _topHomeLayout(Widget currentChild, List<Widget> previousChildren) {
List<Widget> children = previousChildren;
if (currentChild != null) {
children = children.ToList();
children.Add(currentChild);
}
return new Stack(
children: children,
alignment: Alignment.topCenter
);
}
public static AnimatedSwitcherLayoutBuilder _centerHomeLayout = AnimatedSwitcher.defaultLayoutBuilder;
public override void initState() {
base.initState();
this._controller = new AnimationController(
duration: new TimeSpan(0, 0, 0, 0, 600),
debugLabel: "preview banner",
vsync: this
);
this._controller.forward();
}
public override void dispose() {
this._controller.dispose();
base.dispose();
}
public override Widget build(BuildContext context) {
ThemeData theme = Theme.of(context);
bool isDark = theme.brightness == Brightness.dark;
MediaQueryData media = MediaQuery.of(context);
bool centerHome = media.orientation == Orientation.portrait && media.size.height < 800.0;
Curve switchOutCurve = new Interval(0.4f, 1.0f, curve: Curves.fastOutSlowIn);
Curve switchInCurve = new Interval(0.4f, 1.0f, curve: Curves.fastOutSlowIn);
Widget home = new Scaffold(
key: _scaffoldKey,
backgroundColor: isDark ? HomeUtils._kUIWidgetsBlue : theme.primaryColor,
body: new SafeArea(
bottom: false,
child: new WillPopScope(
onWillPop: () => {
// Pop the category page if Android back button is pressed.
if (this._category != null) {
this.setState(() => this._category = null);
return Promise<bool>.Resolved(false);
}
return Promise<bool>.Resolved(true);
},
child: new Backdrop(
backTitle: new Text("Options"),
backLayer: this.widget.optionsPage,
frontAction: new AnimatedSwitcher(
duration: HomeUtils._kFrontLayerSwitchDuration,
switchOutCurve: switchOutCurve,
switchInCurve: switchInCurve,
child: this._category == null
? (Widget) new _UIWidgetsLogo()
: new IconButton(
icon: new BackButtonIcon(),
tooltip: "Back",
onPressed: () => this.setState(() => this._category = null)
)
),
frontTitle: new AnimatedSwitcher(
duration: HomeUtils._kFrontLayerSwitchDuration,
child: this._category == null
? new Text("Flutter gallery")
: new Text(this._category.name)
),
frontHeading: this.widget.testMode ? null : new Container(height: 24.0f),
frontLayer: new AnimatedSwitcher(
duration: HomeUtils._kFrontLayerSwitchDuration,
switchOutCurve: switchOutCurve,
switchInCurve: switchInCurve,
layoutBuilder: centerHome ? _centerHomeLayout : _topHomeLayout,
child: this._category != null
? (Widget) new _DemosPage(this._category)
: new _CategoriesPage(
categories: DemoUtils.kAllGalleryDemoCategories,
onCategoryTap: (GalleryDemoCategory category) => {
this.setState(() => this._category = category);
}
)
)
)
)
)
);
D.assert(() => {
GalleryHome.showPreviewBanner = false;
return true;
});
if (GalleryHome.showPreviewBanner) {
home = new Stack(
fit: StackFit.expand,
children: new List<Widget> {
home,
new FadeTransition(
opacity: new CurvedAnimation(parent: this._controller, curve: Curves.easeInOut),
child: new Banner(
message: "PREVIEW",
location: BannerLocation.topEnd
)
)
}
);
}
home = new AnnotatedRegion<SystemUiOverlayStyle>(
child: home,
value: SystemUiOverlayStyle.light
);
return home;
}
}
// class _GalleryHomeState : SingleTickerProviderStateMixin<GalleryHome> {
// static readonly GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>.key();
// AnimationController _controller;
// GalleryDemoCategory _category;
//
// static Widget _topHomeLayout(Widget currentChild, List<Widget> previousChildren) {
// List<Widget> children = previousChildren;
// if (currentChild != null) {
// children = children.ToList();
// children.Add(currentChild);
// }
//
// return new Stack(
// children: children,
// alignment: Alignment.topCenter
// );
// }
//
// public static AnimatedSwitcherLayoutBuilder _centerHomeLayout = AnimatedSwitcher.defaultLayoutBuilder;
//
// public override void initState() {
// base.initState();
// this._controller = new AnimationController(
// duration: new TimeSpan(0, 0, 0, 0, 600),
// debugLabel: "preview banner",
// vsync: this
// );
// this._controller.forward();
// }
//
// public override void dispose() {
// this._controller.dispose();
// base.dispose();
// }
//
// public override Widget build(BuildContext context) {
// ThemeData theme = Theme.of(context);
// bool isDark = theme.brightness == Brightness.dark;
// MediaQueryData media = MediaQuery.of(context);
// bool centerHome = media.orientation == Orientation.portrait && media.size.height < 800.0;
//
// Curve switchOutCurve = new Interval(0.4f, 1.0f, curve: Curves.fastOutSlowIn);
// Curve switchInCurve = new Interval(0.4f, 1.0f, curve: Curves.fastOutSlowIn);
//
// Widget home = new Scaffold(
// key: _scaffoldKey,
// backgroundColor: isDark ? HomeUtils._kUIWidgetsBlue : theme.primaryColor,
// body: new SafeArea(
// bottom: false,
// child: new WillPopScope(
// onWillPop: () => {
// // Pop the category page if Android back button is pressed.
// if (this._category != null) {
// this.setState(() => this._category = null);
// return Promise<bool>.Resolved(false);
// }
// return Promise<bool>.Resolved(true);
// },
// child: new Backdrop(
// backTitle: new Text("Options"),
// backLayer: this.widget.optionsPage,
// frontAction: new AnimatedSwitcher(
// duration: HomeUtils._kFrontLayerSwitchDuration,
// switchOutCurve: switchOutCurve,
// switchInCurve: switchInCurve,
// child: this._category == null
// ? (Widget) new _UIWidgetsLogo()
// : new IconButton(
// icon: new BackButtonIcon(),
// tooltip: "Back",
// onPressed: () => this.setState(() => this._category = null)
// )
// ),
// frontTitle: new AnimatedSwitcher(
// duration: HomeUtils._kFrontLayerSwitchDuration,
// child: this._category == null
// ? new Text("Flutter gallery")
// : new Text(this._category.name)
// ),
// frontHeading: this.widget.testMode ? null : new Container(height: 24.0f),
// frontLayer: new AnimatedSwitcher(
// duration: HomeUtils._kFrontLayerSwitchDuration,
// switchOutCurve: switchOutCurve,
// switchInCurve: switchInCurve,
// layoutBuilder: centerHome ? _centerHomeLayout : _topHomeLayout,
// child: this._category != null
// ? (Widget) new _DemosPage(this._category)
// : new _CategoriesPage(
// categories: DemoUtils.kAllGalleryDemoCategories,
// onCategoryTap: (GalleryDemoCategory category) => {
// this.setState(() => this._category = category);
// }
// )
// )
// )
// )
// )
// );
//
// D.assert(() => {
// GalleryHome.showPreviewBanner = false;
// return true;
// });
//
// if (GalleryHome.showPreviewBanner) {
// home = new Stack(
// fit: StackFit.expand,
// children: new List<Widget> {
// home,
// new FadeTransition(
// opacity: new CurvedAnimation(parent: this._controller, curve: Curves.easeInOut),
// child: new Banner(
// message: "PREVIEW",
// location: BannerLocation.topEnd
// )
// )
// }
// );
// }
// home = new AnnotatedRegion<SystemUiOverlayStyle>(
// child: home,
// value: SystemUiOverlayStyle.light
// );
//
// return home;
// }
// }
}

8
Runtime/material/animated_icons.meta


fileFormatVersion: 2
guid: fe9d2309a41964cba855171391dab665
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

11
Runtime/widgets/animated_switcher.cs.meta


fileFormatVersion: 2
guid: bfa637befa3d147118ae1e48760e552d
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

365
Samples/UIWidgetsGallery/gallery/backdrop.cs


using System;
using System.Collections.Generic;
using Unity.UIWidgets.animation;
using Unity.UIWidgets.foundation;
using Unity.UIWidgets.gestures;
using Unity.UIWidgets.material;
using Unity.UIWidgets.painting;
using Unity.UIWidgets.rendering;
using Unity.UIWidgets.ui;
using Unity.UIWidgets.widgets;
using UnityEngine;
namespace UIWidgetsGallery.gallery {
public class BackdropConstants {
public const float _kFrontHeadingHeight = 32.0f;
public const float _kFrontClosedHeight = 92.0f;
public const float _kBackAppBarHeight = 56.0f;
public static readonly Animatable<BorderRadius> _kFrontHeadingBevelRadius = new BorderRadiusTween(
begin: BorderRadius.only(
topLeft: Radius.circular(12.0f),
topRight: Radius.circular(12.0f)
),
end: BorderRadius.only(
topLeft: Radius.circular(_kFrontHeadingHeight),
topRight: Radius.circular(_kFrontHeadingHeight)
)
);
}
class _TappableWhileStatusIs : StatefulWidget {
public _TappableWhileStatusIs(
AnimationStatus status,
Key key = null,
AnimationController controller = null,
Widget child = null
) : base(key: key) {
this.controller = controller;
this.status = status;
this.child = child;
}
public readonly AnimationController controller;
public readonly AnimationStatus status;
public readonly Widget child;
public override State createState() {
return new _TappableWhileStatusIsState();
}
}
class _TappableWhileStatusIsState : State<_TappableWhileStatusIs> {
bool _active;
public override void initState() {
base.initState();
this.widget.controller.addStatusListener(this._handleStatusChange);
this._active = this.widget.controller.status == this.widget.status;
}
public override void dispose() {
this.widget.controller.removeStatusListener(this._handleStatusChange);
base.dispose();
}
void _handleStatusChange(AnimationStatus status) {
bool value = this.widget.controller.status == this.widget.status;
if (this._active != value) {
this.setState(() => { this._active = value; });
}
}
public override Widget build(BuildContext context) {
return new AbsorbPointer(
absorbing: !this._active,
child: this.widget.child
);
}
}
class _CrossFadeTransition : AnimatedWidget {
public _CrossFadeTransition(
Key key = null,
Alignment alignment = null,
Animation<float> progress = null,
Widget child0 = null,
Widget child1 = null
) : base(key: key, listenable: progress) {
this.alignment = alignment ?? Alignment.center;
this.child0 = child0;
this.child1 = child1;
}
public readonly Alignment alignment;
public readonly Widget child0;
public readonly Widget child1;
protected override Widget build(BuildContext context) {
Animation<float> progress = this.listenable as Animation<float>;
float opacity1 = new CurvedAnimation(
parent: new ReverseAnimation(progress),
curve: new Interval(0.5f, 1.0f)
).value;
float opacity2 = new CurvedAnimation(
parent: progress,
curve: new Interval(0.5f, 1.0f)
).value;
return new Stack(
alignment: this.alignment,
children: new List<Widget> {
new Opacity(
opacity: opacity1,
child: this.child1
),
new Opacity(
opacity: opacity2,
child: this.child0
)
}
);
}
}
class _BackAppBar : StatelessWidget {
public _BackAppBar(
Key key = null,
Widget leading = null,
Widget title = null,
Widget trailing = null
) : base(key: key) {
D.assert(title != null);
this.leading = leading ?? new SizedBox(width: 56.0f);
this.title = title;
this.trailing = trailing;
}
public readonly Widget leading;
public readonly Widget title;
public readonly Widget trailing;
public override Widget build(BuildContext context) {
List<Widget> children = new List<Widget> {
new Container(
alignment: Alignment.center,
width: 56.0f,
child: this.leading
),
new Expanded(
child: this.title
),
};
if (this.trailing != null) {
children.Add(
new Container(
alignment: Alignment.center,
width: 56.0f,
child: this.trailing
)
);
}
ThemeData theme = Theme.of(context);
return IconTheme.merge(
data: theme.primaryIconTheme,
child: new DefaultTextStyle(
style: theme.primaryTextTheme.title,
child: new SizedBox(
height: BackdropConstants._kBackAppBarHeight,
child: new Row(children: children)
)
)
);
}
}
class Backdrop : StatefulWidget {
public Backdrop(
Widget frontAction,
Widget frontTitle,
Widget frontHeading,
Widget frontLayer,
Widget backTitle,
Widget backLayer
) {
this.frontAction = frontAction;
this.frontTitle = frontTitle;
this.frontHeading = frontHeading;
this.frontLayer = frontLayer;
this.backTitle = backTitle;
this.backLayer = backLayer;
}
public readonly Widget frontAction;
public readonly Widget frontTitle;
public readonly Widget frontLayer;
public readonly Widget frontHeading;
public readonly Widget backTitle;
public readonly Widget backLayer;
public override State createState() {
return new _BackdropState();
}
}
class _BackdropState : SingleTickerProviderStateMixin<Backdrop> {
GlobalKey _backdropKey = GlobalKey.key(debugLabel: "Backdrop");
AnimationController _controller;
Animation<float> _frontOpacity;
static Animatable<float> _frontOpacityTween = new FloatTween(begin: 0.2f, end: 1.0f)
.chain(new CurveTween(curve: new Interval(0.0f, 0.4f, curve: Curves.easeInOut)));
public override void initState() {
base.initState();
this._controller = new AnimationController(
duration: new TimeSpan(0, 0, 0, 0, 300),
value: 1.0f,
vsync: this
);
this._frontOpacity = this._controller.drive(_frontOpacityTween);
}
public override void dispose() {
this._controller.dispose();
base.dispose();
}
float? _backdropHeight {
get {
RenderBox renderBox = (RenderBox) this._backdropKey.currentContext.findRenderObject();
return Mathf.Max(0.0f,
renderBox.size.height - BackdropConstants._kBackAppBarHeight -
BackdropConstants._kFrontClosedHeight);
}
}
void _handleDragUpdate(DragUpdateDetails details) {
this._controller.setValue(this._controller.value -
details.primaryDelta / (this._backdropHeight ?? details.primaryDelta) ?? 0.0f);
}
void _handleDragEnd(DragEndDetails details) {
if (this._controller.isAnimating || this._controller.status == AnimationStatus.completed) {
return;
}
float? flingVelocity = details.velocity.pixelsPerSecond.dy / this._backdropHeight;
if (flingVelocity < 0.0f) {
this._controller.fling(velocity: Mathf.Max(2.0f, -flingVelocity ?? 0.0f));
}
else if (flingVelocity > 0.0f) {
this._controller.fling(velocity: Mathf.Min(-2.0f, -flingVelocity ?? 0.0f));
}
else {
this._controller.fling(velocity: this._controller.value < 0.5 ? -2.0f : 2.0f);
}
}
void _toggleFrontLayer() {
AnimationStatus status = this._controller.status;
bool isOpen = status == AnimationStatus.completed || status == AnimationStatus.forward;
this._controller.fling(velocity: isOpen ? -2.0f : 2.0f);
}
Widget _buildStack(BuildContext context, BoxConstraints constraints) {
Animation<RelativeRect> frontRelativeRect = this._controller.drive(new RelativeRectTween(
begin: RelativeRect.fromLTRB(0.0f, constraints.biggest.height - BackdropConstants._kFrontClosedHeight,
0.0f, 0.0f),
end: RelativeRect.fromLTRB(0.0f, BackdropConstants._kBackAppBarHeight, 0.0f, 0.0f)
));
List<Widget> layers = new List<Widget> {
new Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: new List<Widget> {
new _BackAppBar(
leading: this.widget.frontAction,
title: new _CrossFadeTransition(
progress: this._controller,
alignment: Alignment.centerLeft,
child0: this.widget.frontTitle,
child1: this.widget.backTitle
),
trailing: new IconButton(
onPressed: this._toggleFrontLayer,
tooltip: "Toggle options page",
icon: new AnimatedIcon(
icon: AnimatedIcons.close_menu,
progress: this._controller
)
)
),
new Expanded(
child: new Visibility(
child: this.widget.backLayer,
visible: this._controller.status != AnimationStatus.completed,
maintainState: true
)
)
}
),
new PositionedTransition(
rect: frontRelativeRect,
child: new AnimatedBuilder(
animation: this._controller,
builder: (BuildContext _context, Widget child) => {
return new PhysicalShape(
elevation: 12.0f,
color: Theme.of(_context).canvasColor,
clipper: new ShapeBorderClipper(
shape: new BeveledRectangleBorder(
borderRadius: BackdropConstants._kFrontHeadingBevelRadius.evaluate(
this._controller)
)
),
clipBehavior: Clip.antiAlias,
child: child
);
},
child: new _TappableWhileStatusIs(
AnimationStatus.completed,
controller: this._controller,
child: new FadeTransition(
opacity: this._frontOpacity,
child: this.widget.frontLayer
)
)
)
)
};
if (this.widget.frontHeading != null) {
layers.Add(
new PositionedTransition(
rect: frontRelativeRect,
child: new Container(
alignment: Alignment.topLeft,
child: new GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: this._toggleFrontLayer,
onVerticalDragUpdate: this._handleDragUpdate,
onVerticalDragEnd: this._handleDragEnd,
child: this.widget.frontHeading
)
)
)
);
}
return new Stack(
key: this._backdropKey,
children: layers
);
}
public override Widget build(BuildContext context) {
return new LayoutBuilder(builder: this._buildStack);
}
}
}

3
Samples/UIWidgetsGallery/gallery/backdrop.cs.meta


fileFormatVersion: 2
guid: f3ee24c4986845abb1356402632d8524
timeCreated: 1552886622

213
Runtime/material/animated_icons/animated_icons.cs


using System.Collections.Generic;
using Unity.UIWidgets.animation;
using Unity.UIWidgets.foundation;
using Unity.UIWidgets.ui;
using Unity.UIWidgets.widgets;
using UnityEngine;
using Color = Unity.UIWidgets.ui.Color;
namespace Unity.UIWidgets.material {
static class AnimatedIconUtils {
public static T _interpolate<T>(List<T> values, float progress, _Interpolator<T> interpolator) {
D.assert(progress <= 1.0f);
D.assert(progress >= 0.0f);
if (values.Count == 1)
return values[0];
float targetIdx = MathUtils.lerpFloat(0, values.Count -1, progress);
int lowIdx = targetIdx.floor();
int highIdx = targetIdx.ceil();
float t = targetIdx - lowIdx;
return interpolator(values[lowIdx], values[highIdx], t);
}
}
public class AnimatedIcon : StatelessWidget {
public AnimatedIcon(
Key key = null,
AnimatedIconData icon = null,
Animation<float> progress = null,
Color color = null,
float? size = null
) : base(key: key) {
D.assert(progress != null);
D.assert(icon != null);
this.progress = progress;
this.color = color;
this.size = size;
this.icon = icon;
}
public readonly Animation<float> progress;
public readonly Color color;
public readonly float? size;
public readonly AnimatedIconData icon;
public static readonly _UiPathFactory _pathFactory = () => new Path();
public override Widget build(BuildContext context) {
_AnimatedIconData iconData = (_AnimatedIconData) this.icon;
IconThemeData iconTheme = IconTheme.of(context);
float iconSize = this.size ?? iconTheme.size ?? 0.0f;
float? iconOpacity = iconTheme.opacity;
Color iconColor = this.color ?? iconTheme.color;
if (iconOpacity != 1.0f)
iconColor = iconColor.withOpacity(iconColor.opacity * (iconOpacity ?? 1.0f));
return new CustomPaint(
size: new Size(iconSize, iconSize),
painter: new _AnimatedIconPainter(
paths: iconData.paths,
progress: this.progress,
color: iconColor,
scale: iconSize / iconData.size.width,
uiPathFactory: _pathFactory
)
);
}
}
public delegate Path _UiPathFactory();
class _AnimatedIconPainter : AbstractCustomPainter {
public _AnimatedIconPainter(
List<_PathFrames> paths = null,
Animation<float> progress = null,
Color color = null,
float? scale = null,
bool? shouldMirror = null,
_UiPathFactory uiPathFactory = null
) : base(repaint: progress) {
this.paths = paths;
this.progress = progress;
this.color = color;
this.scale = scale;
this.shouldMirror = shouldMirror;
this.uiPathFactory = uiPathFactory;
}
public readonly List<_PathFrames> paths;
public readonly Animation<float> progress;
public readonly Color color;
public readonly float? scale;
public readonly bool? shouldMirror;
public readonly _UiPathFactory uiPathFactory;
public override void paint(ui.Canvas canvas, Size size) {
canvas.scale(this.scale ?? 1.0f, this.scale ?? 1.0f);
if (this.shouldMirror == true) {
canvas.rotate(Mathf.PI);
canvas.translate(-size.width, -size.height);
}
float clampedProgress = this.progress.value.clamp(0.0f, 1.0f);
foreach (_PathFrames path in this.paths)
path.paint(canvas, this.color, this.uiPathFactory, clampedProgress);
}
public override bool shouldRepaint(CustomPainter _oldDelegate) {
_AnimatedIconPainter oldDelegate = _oldDelegate as _AnimatedIconPainter;
return oldDelegate.progress.value != this.progress.value
|| oldDelegate.color != this.color
|| oldDelegate.paths != this.paths
|| oldDelegate.scale != this.scale
|| oldDelegate.uiPathFactory != this.uiPathFactory;
}
public override bool? hitTest(Offset position) => null;
}
class _PathFrames {
public _PathFrames(
List<_PathCommand> commands,
List<float> opacities
) {
this.commands = commands;
this.opacities = opacities;
}
public readonly List<_PathCommand> commands;
public readonly List<float> opacities;
public void paint(ui.Canvas canvas, Color color, _UiPathFactory uiPathFactory, float progress) {
float opacity = AnimatedIconUtils._interpolate<float>(this.opacities, progress, MathUtils.lerpFloat);
Paint paint = new Paint();
paint.style = PaintingStyle.fill;
paint.color = color.withOpacity(color.opacity * opacity);
Path path = uiPathFactory();
foreach (_PathCommand command in this.commands)
command.apply(path, progress);
canvas.drawPath(path, paint);
}
}
abstract class _PathCommand {
public _PathCommand() {}
public abstract void apply(Path path, float progress);
}
class _PathMoveTo : _PathCommand {
public _PathMoveTo(List<Offset> points) {
this.points = points;
}
public readonly List<Offset> points;
public override void apply(Path path, float progress) {
Offset offset = AnimatedIconUtils._interpolate<Offset>(this.points, progress, Offset.lerp);
path.moveTo(offset.dx, offset.dy);
}
}
class _PathCubicTo : _PathCommand {
public _PathCubicTo(List<Offset> controlPoints1, List<Offset> controlPoints2, List<Offset> targetPoints) {
this.controlPoints1 = controlPoints1;
this.controlPoints2 = controlPoints2;
this.targetPoints = targetPoints;
}
public readonly List<Offset> controlPoints2;
public readonly List<Offset> controlPoints1;
public readonly List<Offset> targetPoints;
public override void apply(Path path, float progress) {
Offset controlPoint1 = AnimatedIconUtils._interpolate<Offset>(this.controlPoints1, progress, Offset.lerp);
Offset controlPoint2 = AnimatedIconUtils._interpolate<Offset>(this.controlPoints2, progress, Offset.lerp);
Offset targetPoint = AnimatedIconUtils._interpolate<Offset>(this.targetPoints, progress, Offset.lerp);
// TODO: replace with cubicTo
path.bezierTo(
controlPoint1.dx, controlPoint1.dy,
controlPoint2.dx, controlPoint2.dy,
targetPoint.dx, targetPoint.dy
);
}
}
class _PathLineTo : _PathCommand {
public _PathLineTo(List<Offset> points) {
this.points = points;
}
List<Offset> points;
public override void apply(Path path, float progress) {
Offset point = AnimatedIconUtils._interpolate<Offset>(this.points, progress, Offset.lerp);
path.lineTo(point.dx, point.dy);
}
}
class _PathClose : _PathCommand {
public _PathClose() {}
public override void apply(Path path, float progress) {
path.close();
}
}
public delegate T _Interpolator<T>(T a, T b, float progress);
}

11
Runtime/material/animated_icons/animated_icons.cs.meta


fileFormatVersion: 2
guid: cd2f603947c5f4baea10dc2c394daafb
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

56
Runtime/material/animated_icons/animated_icons_data.cs


using System.Collections.Generic;
using Unity.UIWidgets.ui;
using UnityEngine;
namespace Unity.UIWidgets.material {
public abstract class AnimatedIcons {
public static readonly AnimatedIconData add_event = AnimatedIconsData._add_event;
public static readonly AnimatedIconData arrow_menu = AnimatedIconsData._arrow_menu;
public static readonly AnimatedIconData close_menu = AnimatedIconsData._close_menu;
// public readonly AnimatedIconData ellipsis_search = AnimatedIconsData._ellipsis_search;
// public readonly AnimatedIconData event_add = AnimatedIconsData._event_add;
// public readonly AnimatedIconData home_menu = AnimatedIconsData._home_menu;
// public readonly AnimatedIconData list_view = AnimatedIconsData._list_view;
// public readonly AnimatedIconData menu_arrow = AnimatedIconsData._menu_arrow;
// public readonly AnimatedIconData menu_close = AnimatedIconsData._menu_close;
// public readonly AnimatedIconData menu_home = AnimatedIconsData._menu_home;
// public readonly AnimatedIconData pause_play = AnimatedIconsData._pause_play;
// public readonly AnimatedIconData play_pause = AnimatedIconsData._play_pause;
// public readonly AnimatedIconData search_ellipsis = AnimatedIconsData._search_ellipsis;
// public readonly AnimatedIconData view_list = AnimatedIconsData._view_list;
}
public abstract class AnimatedIconData {
public AnimatedIconData() {}
public abstract bool matchTextDirection { get; }
}
class _AnimatedIconData : AnimatedIconData {
public _AnimatedIconData(Size size, List<_PathFrames> paths, bool matchTextDirection = false) {
this.size = size;
this.paths = paths;
this.matchTextDirection = matchTextDirection;
}
public readonly Size size;
public readonly List<_PathFrames> paths;
public override bool matchTextDirection { get; }
}
}

3
Runtime/material/animated_icons/animated_icons_data.cs.meta


fileFormatVersion: 2
guid: 439a75e2cc39472ba806029b41996e9b
timeCreated: 1552892371

8
Runtime/material/animated_icons/data.meta


fileFormatVersion: 2
guid: 14a0ec7a1462b4e50861bac1c7cfc3bf
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

1001
Runtime/material/animated_icons/data/add_event.g.cs
文件差异内容过多而无法显示
查看文件

11
Runtime/material/animated_icons/data/add_event.g.cs.meta


fileFormatVersion: 2
guid: 885b0d58b510b4b3ea77c5c4c9e47694
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

1001
Runtime/material/animated_icons/data/arrow_menu.g.cs
文件差异内容过多而无法显示
查看文件

3
Runtime/material/animated_icons/data/arrow_menu.g.cs.meta


fileFormatVersion: 2
guid: f38795e53cc54f628c2125e5e50fea1c
timeCreated: 1552894502

1001
Runtime/material/animated_icons/data/close_menu.g.cs
文件差异内容过多而无法显示
查看文件

3
Runtime/material/animated_icons/data/close_menu.g.cs.meta


fileFormatVersion: 2
guid: e3a716495016460c8599ef52f9bd690f
timeCreated: 1552894786

3
Runtime/widgets/auto_switcher.cs.meta


fileFormatVersion: 2
guid: d3a56ff3c83e439588db3af71c29d11a
timeCreated: 1552880494

/Runtime/widgets/auto_switcher.cs → /Runtime/widgets/animated_switcher.cs

正在加载...
取消
保存