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

466 行
17 KiB

using System;
using uiwidgets;
using Unity.UIWidgets.animation;
using Unity.UIWidgets.async;
using Unity.UIWidgets.async2;
using Unity.UIWidgets.foundation;
using Unity.UIWidgets.gestures;
using Unity.UIWidgets.painting;
using Unity.UIWidgets.rendering;
using Unity.UIWidgets.service;
using Unity.UIWidgets.ui;
using Unity.UIWidgets.widgets;
using TextStyle = Unity.UIWidgets.painting.TextStyle;
namespace Unity.UIWidgets.material {
static class TooltipUtils {
public static readonly TimeSpan _kFadeDuration = new TimeSpan(0, 0, 0, 0, 200);
public static readonly TimeSpan _kShowDuration = new TimeSpan(0, 0, 0, 0, 1500);
}
public class Tooltip : StatefulWidget {
public Tooltip(
Key key = null,
string message = null,
float? height = null,
EdgeInsetsGeometry padding = null,
EdgeInsetsGeometry margin = null,
float? verticalOffset = null,
bool? preferBelow = null,
bool? excludeFromSemantics = null,
Decoration decoration = null,
TextStyle textStyle = null,
TimeSpan? waitDuration = null,
TimeSpan? showDuration = null,
Widget child = null
) : base(key: key) {
D.assert(message != null);
this.message = message;
this.height = height;
this.padding = padding ;
this.margin = margin;
this.verticalOffset = verticalOffset ;
this.preferBelow = preferBelow ;
this.excludeFromSemantics = excludeFromSemantics;
this.decoration = decoration;
this.textStyle = textStyle;
this.waitDuration = waitDuration;
this.showDuration = showDuration;
this.child = child;
}
public readonly string message;
public readonly float? height;
public readonly EdgeInsetsGeometry padding;
public readonly EdgeInsetsGeometry margin;
public readonly float? verticalOffset;
public readonly bool? preferBelow;
public bool? excludeFromSemantics ;
public Decoration decoration ;
public TextStyle textStyle ;
public TimeSpan? waitDuration ;
public TimeSpan? showDuration ;
public readonly Widget child;
public override State createState() {
return new _TooltipState();
}
public override void debugFillProperties(DiagnosticPropertiesBuilder properties) {
base.debugFillProperties(properties);
properties.add( new StringProperty("message", message, showName: false));
properties.add( new FloatProperty("height", height, defaultValue: null));
properties.add( new DiagnosticsProperty<EdgeInsetsGeometry>("padding", padding, defaultValue: null));
properties.add( new DiagnosticsProperty<EdgeInsetsGeometry>("margin", margin, defaultValue: null));
properties.add( new FloatProperty("vertical offset", verticalOffset, defaultValue: null));
properties.add( new FlagProperty("position", value: preferBelow, ifTrue: "below", ifFalse: "above", showName: true, defaultValue: null));
properties.add( new FlagProperty("semantics", value: excludeFromSemantics, ifTrue: "excluded", showName: true, defaultValue: null));
properties.add( new DiagnosticsProperty<TimeSpan?>("wait duration", waitDuration, defaultValue: null));
properties.add( new DiagnosticsProperty<TimeSpan?>("show duration", showDuration, defaultValue: null));
}
}
public class _TooltipState : SingleTickerProviderStateMixin<Tooltip> {
static float _defaultTooltipHeight = 32.0f;
static float _defaultVerticalOffset = 24.0f;
static bool _defaultPreferBelow = true;
static EdgeInsetsGeometry _defaultPadding = EdgeInsets.symmetric(horizontal: 16.0f);
static EdgeInsetsGeometry _defaultMargin = EdgeInsets.all(0.0f);
static TimeSpan _fadeInDuration = new TimeSpan(0,0,0,0, 150);
static TimeSpan _fadeOutDuration =new TimeSpan(0,0,0,0, 75);
static TimeSpan _defaultShowDuration =new TimeSpan(0,0,0,0,1500);
static TimeSpan _defaultWaitDuration =new TimeSpan(0,0,0,0, 0);
static bool _defaultExcludeFromSemantics = false;
float height;
EdgeInsetsGeometry padding;
EdgeInsetsGeometry margin;
Decoration decoration;
TextStyle textStyle;
float verticalOffset;
bool preferBelow;
bool excludeFromSemantics;
AnimationController _controller;
OverlayEntry _entry;
Timer _hideTimer;
Timer _showTimer;
TimeSpan showDuration;
TimeSpan waitDuration;
bool _mouseIsConnected;
bool _longPressActivated = false;
public override void initState() {
base.initState();
_mouseIsConnected = RendererBinding.instance.mouseTracker.mouseIsConnected;
_controller = new AnimationController(duration: _fadeInDuration, reverseDuration: _fadeOutDuration, vsync: this);
_controller.addStatusListener(_handleStatusChanged);
RendererBinding.instance.mouseTracker.addListener(_handleMouseTrackerChange);
GestureBinding.instance.pointerRouter.addGlobalRoute(_handlePointerEvent);
}
public void _handleMouseTrackerChange() {
if (!mounted) {
return;
}
bool mouseIsConnected = RendererBinding.instance.mouseTracker.mouseIsConnected;
if (mouseIsConnected != _mouseIsConnected) {
setState(()=>{
_mouseIsConnected = mouseIsConnected;
});
}
}
void _handleStatusChanged(AnimationStatus status) {
if (status == AnimationStatus.dismissed) {
_hideTooltip(immediately: true);
}
}
void _hideTooltip( bool immediately = false ) {
_showTimer?.cancel();
_showTimer = null;
if (immediately) {
_removeEntry();
return;
}
if (_longPressActivated) {
_hideTimer = _hideTimer ?? Timer.create(showDuration, () => {
_controller.reverse();
});
} else {
_controller.reverse();
}
_longPressActivated = false;
}
void _showTooltip( bool immediately = false ) {
_hideTimer?.cancel();
_hideTimer = null;
if (immediately) {
ensureTooltipVisible();
return;
}
_showTimer = _showTimer ?? Timer.create(waitDuration, () => {
ensureTooltipVisible();
});
}
bool ensureTooltipVisible() {
_showTimer?.cancel();
_showTimer = null;
if (_entry != null) {
_hideTimer?.cancel();
_hideTimer = null;
_controller.forward();
return false;
}
_createNewEntry();
_controller.forward();
return true;
}
void _createNewEntry() {
RenderBox box = context.findRenderObject() as RenderBox;
Offset target = box.localToGlobal(box.size.center(Offset.zero));
Widget overlay = new Directionality(
textDirection: Directionality.of(context),
child: new _TooltipOverlay(
message: widget.message,
height: height,
padding: padding,
margin: margin,
decoration: decoration,
textStyle: textStyle,
animation: new CurvedAnimation(
parent: _controller,
curve: Curves.fastOutSlowIn
),
target: target,
verticalOffset: verticalOffset,
preferBelow: preferBelow
)
);
_entry = new OverlayEntry(builder: (BuildContext context) => overlay);
Overlay.of(context, debugRequiredFor: widget).insert(_entry);
}
void _removeEntry() {
_hideTimer?.cancel();
_hideTimer = null;
_showTimer?.cancel();
_showTimer = null;
_entry?.remove();
_entry = null;
}
void _handlePointerEvent(PointerEvent pEvent) {
if (_entry == null) {
return;
}
if (pEvent is PointerUpEvent || pEvent is PointerCancelEvent) {
_hideTooltip();
} else if (pEvent is PointerDownEvent) {
_hideTooltip(immediately: true);
}
}
public override void deactivate() {
if (_entry != null) {
_hideTooltip(immediately: true);
}
base.deactivate();
}
public override void dispose() {
GestureBinding.instance.pointerRouter.removeGlobalRoute(_handlePointerEvent);
RendererBinding.instance.mouseTracker.removeListener(_handleMouseTrackerChange);
if (_entry != null) {
_removeEntry();
}
_controller.dispose();
base.dispose();
}
void _handleLongPress() {
_longPressActivated = true;
bool tooltipCreated = ensureTooltipVisible();
if (tooltipCreated) {
Feedback.forLongPress(context);
}
}
public override Widget build(BuildContext context) {
D.assert(Overlay.of(context, debugRequiredFor: widget) != null);
ThemeData theme = Theme.of(context);
TooltipThemeData tooltipTheme = TooltipTheme.of(context);
TextStyle defaultTextStyle;
BoxDecoration defaultDecoration;
if (theme.brightness == Brightness.dark) {
defaultTextStyle = theme.textTheme.bodyText2.copyWith(
color: Colors.black
);
defaultDecoration = new BoxDecoration(
color: Colors.white.withOpacity(0.9f),
borderRadius: BorderRadius.all(Radius.circular(4))
);
} else {
defaultTextStyle = theme.textTheme.bodyText2.copyWith(
color: Colors.white
);
defaultDecoration = new BoxDecoration(
color: Colors.grey[700].withOpacity(0.9f),
borderRadius: BorderRadius.all(Radius.circular(4))
);
}
height = widget.height ?? tooltipTheme?.height ?? _defaultTooltipHeight;
padding = widget.padding ?? tooltipTheme?.padding ?? _defaultPadding;
margin = widget.margin ?? tooltipTheme?.margin ?? _defaultMargin;
verticalOffset = widget.verticalOffset ?? tooltipTheme?.verticalOffset ?? _defaultVerticalOffset;
preferBelow = widget.preferBelow ?? tooltipTheme?.preferBelow ?? _defaultPreferBelow;
excludeFromSemantics = widget.excludeFromSemantics ?? tooltipTheme?.excludeFromSemantics ?? _defaultExcludeFromSemantics;
decoration = widget.decoration ?? tooltipTheme?.decoration ?? defaultDecoration;
textStyle = widget.textStyle ?? tooltipTheme?.textStyle ?? defaultTextStyle;
waitDuration = widget.waitDuration ?? tooltipTheme?.waitDuration ?? _defaultWaitDuration;
showDuration = widget.showDuration ?? tooltipTheme?.showDuration ?? _defaultShowDuration;
Widget result = new GestureDetector(
behavior: HitTestBehavior.opaque,
onLongPress: _handleLongPress,
child: widget.child
);
if (_mouseIsConnected) {
result = new MouseRegion(
onEnter: (PointerEnterEvent _event) => _showTooltip(),
onExit: (PointerExitEvent _event) => _hideTooltip(),
child: result
);
}
return result;
}
}
public class _TooltipPositionDelegate : SingleChildLayoutDelegate {
public _TooltipPositionDelegate(
Offset target = null,
float? verticalOffset = null,
bool? preferBelow = null) {
D.assert(target != null);
D.assert(verticalOffset != null);
D.assert(preferBelow != null);
this.target = target;
this.verticalOffset = verticalOffset ?? 0.0f;
this.preferBelow = preferBelow ?? true;
}
public readonly Offset target;
public readonly float verticalOffset;
public readonly bool preferBelow;
public override BoxConstraints getConstraintsForChild(BoxConstraints constraints) {
return constraints.loosen();
}
public override Offset getPositionForChild(Size size, Size childSize) {
return Geometry.positionDependentBox(
size: size,
childSize: childSize,
target: target,
verticalOffset: verticalOffset,
preferBelow: preferBelow);
}
public override bool shouldRelayout(SingleChildLayoutDelegate oldDelegate) {
_TooltipPositionDelegate _oldDelegate = (_TooltipPositionDelegate) oldDelegate;
return target != _oldDelegate.target ||
verticalOffset != _oldDelegate.verticalOffset ||
preferBelow != _oldDelegate.preferBelow;
}
}
class _TooltipOverlay : StatelessWidget {
public _TooltipOverlay(
Key key = null,
string message = null,
float? height = null,
EdgeInsetsGeometry padding = null,
EdgeInsetsGeometry margin = null,
Decoration decoration = null,
TextStyle textStyle = null,
Animation<float> animation = null,
Offset target = null,
float? verticalOffset = null,
bool? preferBelow = null
) : base(key: key) {
this.message = message;
this.height = height;
this.padding = padding;
this.margin = margin;
this.decoration = decoration;
this.textStyle = textStyle;
this.animation = animation;
this.target = target;
this.verticalOffset = verticalOffset;
this.preferBelow = preferBelow;
}
public readonly string message;
public readonly float? height;
public readonly EdgeInsetsGeometry padding;
public readonly EdgeInsetsGeometry margin;
public readonly Decoration decoration;
public readonly TextStyle textStyle;
public readonly Animation<float> animation;
public readonly Offset target;
public readonly float? verticalOffset;
public readonly bool? preferBelow;
public override Widget build(BuildContext context) {
return Positioned.fill(
child: new IgnorePointer(
child: new CustomSingleChildLayout(
layoutDelegate: new _TooltipPositionDelegate(
target: target,
verticalOffset: verticalOffset,
preferBelow: preferBelow),
child: new FadeTransition(
opacity: animation,
child: new ConstrainedBox(
constraints: new BoxConstraints(minHeight: height.Value),
child: new DefaultTextStyle(
style: Theme.of(context).textTheme.bodyText2,
child: new Container(
decoration: decoration,
padding: padding,
margin: margin,
child: new Center(
widthFactor: 1.0f,
heightFactor: 1.0f,
child: new Text(message, style: textStyle)
)
))
)
)
)
)
);
}
}
}