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

400 行
14 KiB

using System;
using System.Collections.Generic;
using uiwidgets;
using Unity.UIWidgets.animation;
using Unity.UIWidgets.foundation;
using Unity.UIWidgets.gestures;
using Unity.UIWidgets.painting;
using Unity.UIWidgets.rendering;
using Unity.UIWidgets.ui;
using Unity.UIWidgets.widgets;
using UnityEngine;
using Color = Unity.UIWidgets.ui.Color;
namespace Unity.UIWidgets.material {
static class DrawerUtils {
public const float _kWidth = 304.0f;
public const float _kEdgeDragWidth = 20.0f;
public const float _kMinFlingVelocity = 365.0f;
public static readonly TimeSpan _kBaseSettleDuration = new TimeSpan(0, 0, 0, 0, 246);
}
public enum DrawerAlignment {
start,
end
}
public class Drawer : StatelessWidget {
public Drawer(
Key key = null,
float elevation = 16.0f,
Widget child = null) : base(key: key) {
D.assert(elevation >= 0.0f);
this.elevation = elevation;
this.child = child;
}
public readonly float elevation;
public readonly Widget child;
public override Widget build(BuildContext context) {
return new ConstrainedBox(
constraints: BoxConstraints.expand(width: DrawerUtils._kWidth),
child: new Material(
elevation: elevation,
child: child
)
);
}
}
public delegate void DrawerCallback(bool isOpened);
public class DrawerController : StatefulWidget {
public DrawerController(
GlobalKey key = null,
Widget child = null,
DrawerAlignment? alignment = null,
DrawerCallback drawerCallback = null,
DragStartBehavior dragStartBehavior = DragStartBehavior.start,
Color scrimColor = null,
bool? enableOpenDragGesture = true,
float? edgeDragWidth = null
) : base(key: key) {
D.assert(child != null);
D.assert(alignment != null);
this.child = child;
this.alignment = alignment ?? DrawerAlignment.start;
this.drawerCallback = drawerCallback;
this.dragStartBehavior = dragStartBehavior;
this.scrimColor = scrimColor;
this.enableOpenDragGesture = enableOpenDragGesture;
this.edgeDragWidth = edgeDragWidth;
}
public readonly Widget child;
public readonly DrawerAlignment alignment;
public readonly DragStartBehavior? dragStartBehavior;
public readonly DrawerCallback drawerCallback;
public readonly Color scrimColor;
public readonly bool? enableOpenDragGesture;
public readonly float? edgeDragWidth;
public override State createState() {
return new DrawerControllerState();
}
}
public class DrawerControllerState : SingleTickerProviderStateMixin<DrawerController> {
public override void initState() {
base.initState();
_scrimColorTween = _buildScrimColorTween();
_controller = new AnimationController(duration: DrawerUtils._kBaseSettleDuration, vsync: this);
_controller.addListener(_animationChanged);
_controller.addStatusListener(_animationStatusChanged);
}
public override void dispose() {
_historyEntry?.remove();
_controller.dispose();
base.dispose();
}
public override void didUpdateWidget(StatefulWidget statefulWidget) {
base.didUpdateWidget(statefulWidget);
if (statefulWidget is DrawerController oldWidget && widget.scrimColor != oldWidget.scrimColor)
_scrimColorTween = _buildScrimColorTween();
}
void _animationChanged() {
setState(() => { });
}
LocalHistoryEntry _historyEntry;
readonly FocusScopeNode _focusScopeNode = new FocusScopeNode();
void _ensureHistoryEntry() {
if (_historyEntry == null) {
ModalRoute route = ModalRoute.of(context);
if (route != null) {
_historyEntry = new LocalHistoryEntry(onRemove: _handleHistoryEntryRemoved);
route.addLocalHistoryEntry(_historyEntry);
FocusScope.of(context).setFirstFocus(_focusScopeNode);
}
}
}
void _animationStatusChanged(AnimationStatus status) {
switch (status) {
case AnimationStatus.forward:
_ensureHistoryEntry();
break;
case AnimationStatus.reverse:
_historyEntry?.remove();
_historyEntry = null;
break;
case AnimationStatus.dismissed:
break;
case AnimationStatus.completed:
break;
}
}
void _handleHistoryEntryRemoved() {
_historyEntry = null;
close();
}
AnimationController _controller;
void _handleDragDown(DragDownDetails details) {
_controller.stop();
_ensureHistoryEntry();
}
void _handleDragCancel() {
if (_controller.isDismissed || _controller.isAnimating) {
return;
}
if (_controller.value < 0.5) {
close();
}
else {
open();
}
}
public readonly GlobalKey _drawerKey = GlobalKey.key();
float _width {
get {
RenderBox box = (RenderBox) _drawerKey.currentContext?.findRenderObject();
if (box != null) {
return box.size.width;
}
return DrawerUtils._kWidth;
}
}
bool _previouslyOpened = false;
void _move(DragUpdateDetails details) {
float delta = (details.primaryDelta ?? 0) / _width;
switch (widget.alignment) {
case DrawerAlignment.start:
break;
case DrawerAlignment.end:
delta = -delta;
break;
}
_controller.setValue(_controller.value + delta);
bool opened = _controller.value > 0.5f;
if (opened != _previouslyOpened && widget.drawerCallback != null) {
widget.drawerCallback(opened);
}
_previouslyOpened = opened;
}
void _settle(DragEndDetails details) {
if (_controller.isDismissed) {
return;
}
if (details.velocity.pixelsPerSecond.dx.abs() >= DrawerUtils._kMinFlingVelocity) {
float visualVelocity = details.velocity.pixelsPerSecond.dx / DrawerUtils._kWidth;
switch (widget.alignment) {
case DrawerAlignment.start:
break;
case DrawerAlignment.end:
visualVelocity = -visualVelocity;
break;
}
switch (Directionality.of(context)) {
case TextDirection.rtl:
_controller.fling(velocity: -visualVelocity);
if (widget.drawerCallback != null)
widget.drawerCallback(visualVelocity < 0.0f);
break;
case TextDirection.ltr:
_controller.fling(velocity: visualVelocity);
if (widget.drawerCallback != null)
widget.drawerCallback(visualVelocity > 0.0f);
break;
}
}
else if (_controller.value < 0.5f) {
close();
}
else {
open();
}
}
public void open() {
_controller.fling(velocity: 1.0f);
if (widget.drawerCallback != null) {
widget.drawerCallback(true);
}
}
public void close() {
_controller.fling(velocity: -1.0f);
if (widget.drawerCallback != null) {
widget.drawerCallback(false);
}
}
ColorTween _scrimColorTween;
GlobalKey _gestureDetectorKey = GlobalKey.key();
ColorTween _buildScrimColorTween() {
return new ColorTween(begin: Colors.transparent, end: widget.scrimColor ?? Colors.black54);
}
Alignment _drawerOuterAlignment {
get {
switch (widget.alignment) {
case DrawerAlignment.start:
return Alignment.centerLeft;
case DrawerAlignment.end:
return Alignment.centerRight;
}
return null;
}
}
Alignment _drawerInnerAlignment {
get {
switch (widget.alignment) {
case DrawerAlignment.start:
return Alignment.centerRight;
case DrawerAlignment.end:
return Alignment.centerLeft;
}
return null;
}
}
Widget _buildDrawer(BuildContext context) {
bool drawerIsStart = widget.alignment == DrawerAlignment.start;
EdgeInsets padding = MediaQuery.of(context).padding;
TextDirection textDirection = Directionality.of(context);
float? dragAreaWidth = widget.edgeDragWidth;
if (widget.edgeDragWidth == null) {
switch (textDirection) {
case TextDirection.ltr:
dragAreaWidth = DrawerUtils._kEdgeDragWidth +
(drawerIsStart ? padding.left : padding.right);
break;
case TextDirection.rtl:
dragAreaWidth = DrawerUtils._kEdgeDragWidth +
(drawerIsStart ? padding.right : padding.left);
break;
}
}
if (_controller.status == AnimationStatus.dismissed) {
if (widget.enableOpenDragGesture ?? false) {
return new Align(
alignment: _drawerOuterAlignment,
child: new GestureDetector(
key: _gestureDetectorKey,
onHorizontalDragUpdate: _move,
onHorizontalDragEnd: _settle,
behavior: HitTestBehavior.translucent,
dragStartBehavior: widget.dragStartBehavior ?? DragStartBehavior.down,
child: new Container(width: dragAreaWidth)
)
);
}
else {
return SizedBox.shrink();
}
}
else {
bool? platformHasBackButton = null;
switch (Theme.of(context).platform) {
case RuntimePlatform.Android:
platformHasBackButton = true;
break;
case RuntimePlatform.IPhonePlayer:
case RuntimePlatform.OSXEditor:
case RuntimePlatform.OSXPlayer:
case RuntimePlatform.LinuxEditor:
case RuntimePlatform.LinuxPlayer:
case RuntimePlatform.WindowsEditor:
case RuntimePlatform.WindowsPlayer:
platformHasBackButton = false;
break;
}
D.assert(platformHasBackButton != null);
return new GestureDetector(
key: _gestureDetectorKey,
onHorizontalDragDown: _handleDragDown,
onHorizontalDragUpdate: _move,
onHorizontalDragEnd: _settle,
onHorizontalDragCancel: _handleDragCancel,
dragStartBehavior: widget.dragStartBehavior ?? DragStartBehavior.down,
child: new RepaintBoundary(
child: new Stack(
children: new List<Widget> {
new GestureDetector(
onTap: close,
child: new MouseRegion(
opaque: true,
child: new Container( // The drawer's "scrim"
color: _scrimColorTween.evaluate(_controller)
)
)
),
new Align(
alignment: _drawerOuterAlignment,
child: new Align(
alignment: _drawerInnerAlignment,
widthFactor: _controller.value,
child: new RepaintBoundary(
child: new FocusScope(
key: _drawerKey,
node: _focusScopeNode,
child: widget.child
)
)
)
)
}
)
)
);
}
}
public override Widget build(BuildContext context) {
return new ListTileTheme(
style: ListTileStyle.drawer,
child: _buildDrawer(context));
}
}
}