您最多选择25个主题 主题必须以中文或者字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符
 
 
 
 
 
 

483 行
18 KiB

using System;
using uiwidgets;
using Unity.UIWidget.material;
using Unity.UIWidgets.animation;
using Unity.UIWidgets.async;
using Unity.UIWidgets.foundation;
using Unity.UIWidgets.gestures;
using Unity.UIWidgets.painting;
using Unity.UIWidgets.rendering;
using Unity.UIWidgets.scheduler;
using Unity.UIWidgets.ui;
using Unity.UIWidgets.widgets;
using UnityEngine;
using Color = Unity.UIWidgets.ui.Color;
namespace Unity.UIWidgets.material {
public partial class material_ {
public static readonly TimeSpan _bottomSheetEnterDuration = new TimeSpan(0, 0, 0, 0, 250);
public static readonly TimeSpan _bottomSheetExitDuration = new TimeSpan(0, 0, 0, 0, 200);
public static Curve _modalBottomSheetCurve {
get => decelerateEasing;
}
public const float _minFlingVelocity = 700.0f;
public const float _closeProgressThreshold = 0.5f;
public delegate void BottomSheetDragStartHandler(DragStartDetails details);
public delegate void BottomSheetDragEndHandler(
DragEndDetails details,
bool? isClosing = false
);
public static Future<T> showModalBottomSheet<T>(
BuildContext context,
WidgetBuilder builder,
Color backgroundColor = null,
float? elevation = null,
ShapeBorder shape = null,
Clip? clipBehavior = null,
Color barrierColor = null,
bool isScrollControlled = false,
bool useRootNavigator = false,
bool isDismissible = true,
bool enableDrag = true
) {
D.assert(context != null);
D.assert(builder != null);
D.assert(WidgetsD.debugCheckHasMediaQuery(context));
D.assert(material_.debugCheckHasMaterialLocalizations(context));
return Navigator.of(context, rootNavigator: useRootNavigator).push(new _ModalBottomSheetRoute<T>(
builder: builder,
theme: Theme.of(context, shadowThemeOnly: true),
isScrollControlled: isScrollControlled,
barrierLabel: MaterialLocalizations.of(context).modalBarrierDismissLabel,
backgroundColor: backgroundColor,
elevation: elevation,
shape: shape,
clipBehavior: clipBehavior,
isDismissible: isDismissible,
modalBarrierColor: barrierColor,
enableDrag: enableDrag
)).to<T>();
}
public static PersistentBottomSheetController<object> showBottomSheet(
BuildContext context,
WidgetBuilder builder,
Color backgroundColor = null,
float? elevation = null,
ShapeBorder shape = null,
Clip? clipBehavior = null
) {
D.assert(context != null);
D.assert(builder != null);
D.assert(debugCheckHasScaffold(context));
return Scaffold.of(context).showBottomSheet(
builder
//TODO: update showBottomSheet
// ,
// backgroundColor: backgroundColor,
// elevation: elevation,
// shape: shape,
// clipBehavior: clipBehavior
);
}
}
public class BottomSheet : StatefulWidget {
public BottomSheet(
Key key = null,
AnimationController animationController = null,
bool enableDrag = true,
material_.BottomSheetDragStartHandler onDragStart = null,
material_.BottomSheetDragEndHandler onDragEnd = null,
Color backgroundColor = null,
float? elevation = null,
ShapeBorder shape = null,
Clip? clipBehavior = null,
VoidCallback onClosing = null,
WidgetBuilder builder = null
) : base(key: key) {
D.assert(onClosing != null);
D.assert(builder != null);
D.assert(elevation == null || elevation >= 0.0);
this.animationController = animationController;
this.enableDrag = enableDrag;
this.elevation = elevation;
this.onClosing = onClosing;
this.builder = builder;
}
public readonly AnimationController animationController;
public readonly VoidCallback onClosing;
public readonly WidgetBuilder builder;
public readonly bool enableDrag;
public readonly material_.BottomSheetDragStartHandler onDragStart;
public readonly material_.BottomSheetDragEndHandler onDragEnd;
public readonly Color backgroundColor;
public readonly float? elevation;
public readonly ShapeBorder shape;
public readonly Clip? clipBehavior;
public override State createState() {
return new _BottomSheetState();
}
public static AnimationController createAnimationController(TickerProvider vsync) {
return new AnimationController(
duration: material_._bottomSheetEnterDuration,
reverseDuration: material_._bottomSheetExitDuration,
debugLabel: "BottomSheet",
vsync: vsync
);
}
}
class _BottomSheetState : State<BottomSheet> {
readonly GlobalKey _childKey = GlobalKey.key(debugLabel: "BottomSheet child");
float? _childHeight {
get {
RenderBox renderBox = (RenderBox) _childKey.currentContext.findRenderObject();
return renderBox.size.height;
}
}
bool _dismissUnderway {
get { return widget.animationController.status == AnimationStatus.reverse; }
}
void _handleDragStart(DragStartDetails details) {
if (widget.onDragStart != null) {
widget.onDragStart(details);
}
}
void _handleDragUpdate(DragUpdateDetails details) {
D.assert(widget.enableDrag);
if (_dismissUnderway) {
return;
}
widget.animationController.setValue(
widget.animationController.value -
details.primaryDelta.Value / (_childHeight ?? details.primaryDelta.Value));
}
void _handleDragEnd(DragEndDetails details) {
D.assert(widget.enableDrag);
if (_dismissUnderway) {
return;
}
bool isClosing = false;
if (details.velocity.pixelsPerSecond.dy > material_._minFlingVelocity) {
float? flingVelocity = -details.velocity.pixelsPerSecond.dy / _childHeight;
if (widget.animationController.value > 0.0) {
widget.animationController.fling(velocity: flingVelocity ?? 0);
}
if (flingVelocity < 0.0) {
isClosing = true;
}
}
else if (widget.animationController.value < material_._closeProgressThreshold) {
if (widget.animationController.value > 0.0)
widget.animationController.fling(velocity: -1.0f);
isClosing = true;
}
else {
widget.animationController.forward();
}
if (widget.onDragEnd != null) {
widget.onDragEnd(
details,
isClosing: isClosing
);
}
if (isClosing) {
widget.onClosing();
}
}
public bool extentChanged(DraggableScrollableNotification notification) {
if (notification.extent == notification.minExtent) {
widget.onClosing();
}
return false;
}
public override Widget build(BuildContext context) {
BottomSheetThemeData bottomSheetTheme = Theme.of(context).bottomSheetTheme;
Color color = widget.backgroundColor ?? bottomSheetTheme?.backgroundColor;
float elevation = widget.elevation ?? bottomSheetTheme?.elevation ?? 0;
ShapeBorder shape = widget.shape ?? bottomSheetTheme?.shape;
Clip clipBehavior = widget.clipBehavior ?? bottomSheetTheme?.clipBehavior ?? Clip.none;
Widget bottomSheet = new Material(
key: _childKey,
color: color,
elevation: elevation,
shape: shape,
clipBehavior: clipBehavior,
child: new NotificationListener<DraggableScrollableNotification>(
onNotification: extentChanged,
child: widget.builder(context)
)
);
return !widget.enableDrag
? bottomSheet
: new GestureDetector(
onVerticalDragStart: _handleDragStart,
onVerticalDragUpdate: _handleDragUpdate,
onVerticalDragEnd: _handleDragEnd,
child: bottomSheet
);
}
}
class _ModalBottomSheetLayout : SingleChildLayoutDelegate {
public _ModalBottomSheetLayout(float progress, bool isScrollControlled) {
this.progress = progress;
this.isScrollControlled = isScrollControlled;
}
public readonly float progress;
public readonly bool isScrollControlled;
public override BoxConstraints getConstraintsForChild(BoxConstraints constraints) {
return new BoxConstraints(
minWidth: constraints.maxWidth,
maxWidth: constraints.maxWidth,
minHeight: 0.0f,
maxHeight: isScrollControlled
? constraints.maxHeight
: constraints.maxHeight * 9.0f / 16.0f
);
}
public override Offset getPositionForChild(Size size, Size childSize) {
return new Offset(0.0f, size.height - childSize.height * progress);
}
public override bool shouldRelayout(SingleChildLayoutDelegate _oldDelegate) {
_ModalBottomSheetLayout oldDelegate = _oldDelegate as _ModalBottomSheetLayout;
return progress != oldDelegate.progress;
}
}
class _ModalBottomSheet<T> : StatefulWidget {
public _ModalBottomSheet(
Key key = null,
_ModalBottomSheetRoute<T> route = null,
Color backgroundColor = null,
float? elevation = null,
ShapeBorder shape = null,
Clip? clipBehavior = null,
bool isScrollControlled = false,
bool enableDrag = true
) : base(key: key) {
this.route = route;
this.backgroundColor = backgroundColor;
this.elevation = elevation;
this.shape = shape;
this.clipBehavior = clipBehavior;
this.isScrollControlled = isScrollControlled;
this.enableDrag = enableDrag;
}
public readonly _ModalBottomSheetRoute<T> route;
public readonly bool isScrollControlled;
public readonly Color backgroundColor;
public readonly float? elevation;
public readonly ShapeBorder shape;
public readonly Clip? clipBehavior;
public readonly bool enableDrag;
public override State createState() {
return new _ModalBottomSheetState<T>();
}
}
class _ModalBottomSheetState<T> : State<_ModalBottomSheet<T>> {
ParametricCurve<float> animationCurve = material_._modalBottomSheetCurve;
string _getRouteLabel(MaterialLocalizations localizations) {
switch (Theme.of(context).platform) {
case RuntimePlatform.IPhonePlayer:
case RuntimePlatform.OSXEditor:
case RuntimePlatform.OSXPlayer:
return "";
case RuntimePlatform.Android:
case RuntimePlatform.LinuxEditor:
case RuntimePlatform.LinuxPlayer:
case RuntimePlatform.WindowsEditor:
case RuntimePlatform.WindowsPlayer:
return localizations.dialogLabel;
}
return null;
}
void handleDragStart(DragStartDetails details) {
animationCurve = Curves.linear;
}
void handleDragEnd(DragEndDetails details, bool? isClosing = null) {
animationCurve = new _BottomSheetSuspendedCurve(
widget.route.animation.value,
curve: material_._modalBottomSheetCurve
);
}
public override Widget build(BuildContext context) {
D.assert(WidgetsD.debugCheckHasMediaQuery(context));
D.assert(material_.debugCheckHasMaterialLocalizations(context));
MediaQueryData mediaQuery = MediaQuery.of(context);
MaterialLocalizations localizations = MaterialLocalizations.of(context);
string routeLabel = _getRouteLabel(localizations);
return new AnimatedBuilder(
animation: widget.route.animation,
builder: (BuildContext _context, Widget child) => {
float animationValue = animationCurve.transform(
mediaQuery.accessibleNavigation ? 1.0f : widget.route.animation.value
);
return new ClipRect(
child: new CustomSingleChildLayout(
layoutDelegate: new _ModalBottomSheetLayout(animationValue, widget.isScrollControlled),
child: new BottomSheet(
animationController: widget.route._animationController,
onClosing: () => {
if (widget.route.isCurrent) {
Navigator.pop<object>(_context);
}
},
builder: widget.route.builder,
backgroundColor: widget.backgroundColor,
elevation: widget.elevation,
shape: widget.shape,
clipBehavior: widget.clipBehavior,
enableDrag: widget.enableDrag,
onDragStart: handleDragStart,
onDragEnd: handleDragEnd
)
)
);
}
);
}
}
class _ModalBottomSheetRoute<T> : PopupRoute {
public _ModalBottomSheetRoute(
WidgetBuilder builder = null,
ThemeData theme = null,
string barrierLabel = null,
Color backgroundColor = null,
float? elevation = null,
ShapeBorder shape = null,
Clip? clipBehavior = null,
Color modalBarrierColor = null,
bool isDismissible = true,
bool enableDrag = true,
bool? isScrollControlled = null,
RouteSettings settings = null
) : base(settings: settings) {
D.assert(isScrollControlled != null);
this.builder = builder;
this.theme = theme;
this.barrierLabel = barrierLabel;
this.backgroundColor = backgroundColor;
this.elevation = elevation;
this.shape = shape;
this.clipBehavior = clipBehavior;
this.modalBarrierColor = modalBarrierColor;
this.isDismissible = isDismissible;
this.enableDrag = enableDrag;
}
public readonly WidgetBuilder builder;
public readonly ThemeData theme;
public readonly bool? isScrollControlled;
public readonly Color backgroundColor;
public readonly float? elevation;
public readonly ShapeBorder shape;
public readonly Clip? clipBehavior;
public readonly Color modalBarrierColor;
public readonly bool isDismissible;
public readonly bool enableDrag;
public override TimeSpan transitionDuration {
get { return material_._bottomSheetEnterDuration; }
}
public override
TimeSpan reverseTransitionDuration {
get { return material_._bottomSheetExitDuration; }
}
public override bool barrierDismissible {
get { return isDismissible; }
}
public readonly string barrierLabel;
public override Color barrierColor {
get { return modalBarrierColor ?? Colors.black54; }
}
public AnimationController _animationController;
public override AnimationController createAnimationController() {
D.assert(_animationController == null);
_animationController = BottomSheet.createAnimationController(navigator.overlay);
return _animationController;
}
public override Widget buildPage(BuildContext context, Animation<float> animation,
Animation<float> secondaryAnimation) {
BottomSheetThemeData sheetTheme = theme?.bottomSheetTheme ?? Theme.of(context).bottomSheetTheme;
Widget bottomSheet = MediaQuery.removePadding(
context: context,
removeTop: true,
child: new _ModalBottomSheet<T>(
route: this,
backgroundColor: backgroundColor ?? sheetTheme?.modalBackgroundColor ?? sheetTheme?.backgroundColor,
elevation: elevation ?? sheetTheme?.modalElevation ?? sheetTheme?.elevation,
shape: shape,
clipBehavior: clipBehavior,
isScrollControlled: isScrollControlled ?? false,
enableDrag: enableDrag
)
);
if (theme != null) {
bottomSheet = new Theme(data: theme, child: bottomSheet);
}
return bottomSheet;
}
}
}