GitHub
5 年前
当前提交
e27405d3
共有 22 个文件被更改,包括 3272 次插入 和 38 次删除
-
11Runtime/cupertino/app.cs
-
2Runtime/cupertino/localization.cs
-
9Runtime/material/app.cs
-
56Runtime/painting/matrix_utils.cs
-
15Runtime/service/keyboard.cs
-
7Runtime/service/text_formatter.cs
-
6Runtime/service/text_input.cs
-
9Runtime/ui/renderer/compositeCanvas/flow/raster_cache.cs
-
8Runtime/widgets/editable_text.cs
-
11Runtime/widgets/scroll_metrics.cs
-
5Runtime/widgets/scroll_physics.cs
-
16Samples/UIWidgetsGallery/gallery/demos.cs
-
1001Runtime/cupertino/date_picker.cs
-
11Runtime/cupertino/date_picker.cs.meta
-
262Runtime/cupertino/picker.cs
-
11Runtime/cupertino/picker.cs.meta
-
751Runtime/rendering/list_wheel_viewport.cs
-
11Runtime/rendering/list_wheel_viewport.cs.meta
-
803Runtime/widgets/list_wheel_scroll_view.cs
-
11Runtime/widgets/list_wheel_scroll_view.cs.meta
-
283Samples/UIWidgetsGallery/demo/cupertino/cupertino_picker_demo.cs
-
11Samples/UIWidgetsGallery/demo/cupertino/cupertino_picker_demo.cs.meta
1001
Runtime/cupertino/date_picker.cs
文件差异内容过多而无法显示
查看文件
文件差异内容过多而无法显示
查看文件
|
|||
fileFormatVersion: 2 |
|||
guid: b8c8750ecccc84021b9aafc99e9ee64b |
|||
MonoImporter: |
|||
externalObjects: {} |
|||
serializedVersion: 2 |
|||
defaultReferences: [] |
|||
executionOrder: 0 |
|||
icon: {instanceID: 0} |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
using System.Collections.Generic; |
|||
using Unity.UIWidgets.foundation; |
|||
using Unity.UIWidgets.painting; |
|||
using Unity.UIWidgets.rendering; |
|||
using Unity.UIWidgets.ui; |
|||
using Unity.UIWidgets.widgets; |
|||
|
|||
namespace Unity.UIWidgets.cupertino { |
|||
static class CupertinoPickerUtils { |
|||
public static Color _kHighlighterBorder = new Color(0xFF7F7F7F); |
|||
public static Color _kDefaultBackground = new Color(0xFFD2D4DB); |
|||
public const float _kDefaultDiameterRatio = 1.35f; |
|||
public const float _kDefaultPerspective = 0.004f; |
|||
public const float _kForegroundScreenOpacityFraction = 0.7f; |
|||
} |
|||
|
|||
public class CupertinoPicker : StatefulWidget { |
|||
public CupertinoPicker( |
|||
float itemExtent, |
|||
ValueChanged<int> onSelectedItemChanged, |
|||
List<Widget> children = null, |
|||
Key key = null, |
|||
float diameterRatio = CupertinoPickerUtils._kDefaultDiameterRatio, |
|||
Color backgroundColor = null, |
|||
float offAxisFraction = 0.0f, |
|||
bool useMagnifier = false, |
|||
float magnification = 1.0f, |
|||
FixedExtentScrollController scrollController = null, |
|||
bool looping = false, |
|||
ListWheelChildDelegate childDelegate = null |
|||
) : base(key: key) { |
|||
D.assert(children != null || childDelegate != null); |
|||
D.assert(diameterRatio > 0.0, () => RenderListWheelViewport.diameterRatioZeroMessage); |
|||
D.assert(magnification > 0); |
|||
D.assert(itemExtent > 0); |
|||
|
|||
this.childDelegate = childDelegate ?? (looping |
|||
? (ListWheelChildDelegate) new ListWheelChildLoopingListDelegate( |
|||
children: children) |
|||
: (ListWheelChildDelegate) new ListWheelChildListDelegate(children: children)); |
|||
|
|||
this.itemExtent = itemExtent; |
|||
this.onSelectedItemChanged = onSelectedItemChanged; |
|||
this.diameterRatio = diameterRatio; |
|||
this.backgroundColor = backgroundColor ?? CupertinoPickerUtils._kDefaultBackground; |
|||
this.offAxisFraction = offAxisFraction; |
|||
this.useMagnifier = useMagnifier; |
|||
this.magnification = magnification; |
|||
this.scrollController = scrollController; |
|||
} |
|||
|
|||
public static CupertinoPicker builder( |
|||
float itemExtent, |
|||
ValueChanged<int> onSelectedItemChanged, |
|||
IndexedWidgetBuilder itemBuilder, |
|||
Key key = null, |
|||
float diameterRatio = CupertinoPickerUtils._kDefaultDiameterRatio, |
|||
Color backgroundColor = null, |
|||
float offAxisFraction = 0.0f, |
|||
bool useMagnifier = false, |
|||
float magnification = 1.0f, |
|||
FixedExtentScrollController scrollController = null, |
|||
int? childCount = null |
|||
) { |
|||
D.assert(itemBuilder != null); |
|||
D.assert(diameterRatio > 0.0f, () => RenderListWheelViewport.diameterRatioZeroMessage); |
|||
D.assert(magnification > 0); |
|||
D.assert(itemExtent > 0); |
|||
|
|||
return new CupertinoPicker( |
|||
itemExtent: itemExtent, |
|||
onSelectedItemChanged: onSelectedItemChanged, |
|||
key: key, |
|||
diameterRatio: diameterRatio, |
|||
backgroundColor: backgroundColor, |
|||
offAxisFraction: offAxisFraction, |
|||
useMagnifier: useMagnifier, |
|||
magnification: magnification, |
|||
scrollController: scrollController, |
|||
childDelegate: new ListWheelChildBuilderDelegate(builder: itemBuilder, childCount: childCount) |
|||
); |
|||
} |
|||
|
|||
public readonly float diameterRatio; |
|||
public readonly Color backgroundColor; |
|||
public readonly float offAxisFraction; |
|||
public readonly bool useMagnifier; |
|||
public readonly float magnification; |
|||
public readonly FixedExtentScrollController scrollController; |
|||
public readonly float itemExtent; |
|||
public readonly ValueChanged<int> onSelectedItemChanged; |
|||
public readonly ListWheelChildDelegate childDelegate; |
|||
|
|||
public override State createState() { |
|||
return new _CupertinoPickerState(); |
|||
} |
|||
} |
|||
|
|||
class _CupertinoPickerState : State<CupertinoPicker> { |
|||
FixedExtentScrollController _controller; |
|||
|
|||
public override void initState() { |
|||
base.initState(); |
|||
if (this.widget.scrollController == null) { |
|||
this._controller = new FixedExtentScrollController(); |
|||
} |
|||
} |
|||
|
|||
public override void didUpdateWidget(StatefulWidget oldWidget) { |
|||
if (this.widget.scrollController != null && ((CupertinoPicker) oldWidget).scrollController == null) { |
|||
this._controller = null; |
|||
} |
|||
else if (this.widget.scrollController == null && ((CupertinoPicker) oldWidget).scrollController != null) { |
|||
D.assert(this._controller == null); |
|||
this._controller = new FixedExtentScrollController(); |
|||
} |
|||
|
|||
base.didUpdateWidget(oldWidget); |
|||
} |
|||
|
|||
public override void dispose() { |
|||
this._controller?.dispose(); |
|||
base.dispose(); |
|||
} |
|||
|
|||
void _handleSelectedItemChanged(int index) { |
|||
if (this.widget.onSelectedItemChanged != null) { |
|||
this.widget.onSelectedItemChanged(index); |
|||
} |
|||
} |
|||
|
|||
Widget _buildGradientScreen() { |
|||
if (this.widget.backgroundColor != null && this.widget.backgroundColor.alpha < 255) { |
|||
return new Container(); |
|||
} |
|||
|
|||
Color widgetBackgroundColor = this.widget.backgroundColor ?? new Color(0xFFFFFFFF); |
|||
return Positioned.fill( |
|||
child: new IgnorePointer( |
|||
child: new Container( |
|||
decoration: new BoxDecoration( |
|||
gradient: new LinearGradient( |
|||
colors: new List<Color> { |
|||
widgetBackgroundColor, |
|||
widgetBackgroundColor.withAlpha(0xF2), |
|||
widgetBackgroundColor.withAlpha(0xDD), |
|||
widgetBackgroundColor.withAlpha(0), |
|||
widgetBackgroundColor.withAlpha(0), |
|||
widgetBackgroundColor.withAlpha(0xDD), |
|||
widgetBackgroundColor.withAlpha(0xF2), |
|||
widgetBackgroundColor, |
|||
}, |
|||
stops: new List<float> { |
|||
0.0f, 0.05f, 0.09f, 0.22f, 0.78f, 0.91f, 0.95f, 1.0f |
|||
}, |
|||
begin: Alignment.topCenter, |
|||
end: Alignment.bottomCenter |
|||
) |
|||
) |
|||
) |
|||
) |
|||
); |
|||
} |
|||
|
|||
Widget _buildMagnifierScreen() { |
|||
Color foreground = this.widget.backgroundColor?.withAlpha( |
|||
(int) (this.widget.backgroundColor.alpha * CupertinoPickerUtils._kForegroundScreenOpacityFraction) |
|||
); |
|||
|
|||
return new IgnorePointer( |
|||
child: new Column( |
|||
children: new List<Widget> { |
|||
new Expanded( |
|||
child: new Container( |
|||
color: foreground |
|||
) |
|||
), |
|||
new Container( |
|||
decoration: new BoxDecoration( |
|||
border: new Border( |
|||
top: new BorderSide(width: 0.0f, color: CupertinoPickerUtils._kHighlighterBorder), |
|||
bottom: new BorderSide(width: 0.0f, color: CupertinoPickerUtils._kHighlighterBorder) |
|||
) |
|||
), |
|||
constraints: BoxConstraints.expand( |
|||
height: this.widget.itemExtent * this.widget.magnification |
|||
) |
|||
), |
|||
new Expanded( |
|||
child: new Container( |
|||
color: foreground |
|||
) |
|||
), |
|||
} |
|||
) |
|||
); |
|||
} |
|||
|
|||
Widget _buildUnderMagnifierScreen() { |
|||
Color foreground = this.widget.backgroundColor?.withAlpha( |
|||
(int) (this.widget.backgroundColor.alpha * CupertinoPickerUtils._kForegroundScreenOpacityFraction) |
|||
); |
|||
|
|||
return new Column( |
|||
children: new List<Widget> { |
|||
new Expanded(child: new Container()), |
|||
new Container( |
|||
color: foreground, |
|||
constraints: BoxConstraints.expand( |
|||
height: this.widget.itemExtent * this.widget.magnification |
|||
) |
|||
), |
|||
new Expanded(child: new Container()) |
|||
} |
|||
); |
|||
} |
|||
|
|||
Widget _addBackgroundToChild(Widget child) { |
|||
return new DecoratedBox( |
|||
decoration: new BoxDecoration( |
|||
color: this.widget.backgroundColor |
|||
), |
|||
child: child |
|||
); |
|||
} |
|||
|
|||
public override Widget build(BuildContext context) { |
|||
Widget result = new Stack( |
|||
children: new List<Widget> { |
|||
Positioned.fill( |
|||
child: ListWheelScrollView.useDelegate( |
|||
controller: this.widget.scrollController ?? this._controller, |
|||
physics: new FixedExtentScrollPhysics(), |
|||
diameterRatio: this.widget.diameterRatio, |
|||
perspective: CupertinoPickerUtils._kDefaultPerspective, |
|||
offAxisFraction: this.widget.offAxisFraction, |
|||
useMagnifier: this.widget.useMagnifier, |
|||
magnification: this.widget.magnification, |
|||
itemExtent: this.widget.itemExtent, |
|||
onSelectedItemChanged: this._handleSelectedItemChanged, |
|||
childDelegate: this.widget.childDelegate |
|||
) |
|||
), |
|||
this._buildGradientScreen(), |
|||
this._buildMagnifierScreen() |
|||
} |
|||
); |
|||
if (this.widget.backgroundColor != null && this.widget.backgroundColor.alpha < 255) { |
|||
result = new Stack( |
|||
children: new List<Widget> { |
|||
this._buildUnderMagnifierScreen(), this._addBackgroundToChild(result), |
|||
} |
|||
); |
|||
} |
|||
else { |
|||
result = this._addBackgroundToChild(result); |
|||
} |
|||
|
|||
return result; |
|||
} |
|||
} |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: e1f9860a10b464e9da0c6258c08fa91e |
|||
MonoImporter: |
|||
externalObjects: {} |
|||
serializedVersion: 2 |
|||
defaultReferences: [] |
|||
executionOrder: 0 |
|||
icon: {instanceID: 0} |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
using System; |
|||
using System.Collections.Generic; |
|||
using Unity.UIWidgets.animation; |
|||
using Unity.UIWidgets.foundation; |
|||
using Unity.UIWidgets.gestures; |
|||
using Unity.UIWidgets.painting; |
|||
using Unity.UIWidgets.ui; |
|||
using UnityEngine; |
|||
using Rect = Unity.UIWidgets.ui.Rect; |
|||
|
|||
namespace Unity.UIWidgets.rendering { |
|||
delegate float ___ChildSizingFunction(RenderBox child); |
|||
|
|||
public interface IListWheelChildManager { |
|||
int? childCount { get; } |
|||
bool childExistsAt(int index); |
|||
void createChild(int index, RenderBox after); |
|||
void removeChild(RenderBox child); |
|||
} |
|||
|
|||
public class ListWheelParentData : ContainerBoxParentData<RenderBox> { |
|||
public int index; |
|||
} |
|||
|
|||
public class RenderListWheelViewport : ContainerRenderObjectMixinRenderBox<RenderBox, ListWheelParentData>, |
|||
RenderAbstractViewport { |
|||
public RenderListWheelViewport( |
|||
IListWheelChildManager childManager, |
|||
ViewportOffset offset, |
|||
float itemExtent, |
|||
float diameterRatio = defaultDiameterRatio, |
|||
float perspective = defaultPerspective, |
|||
float offAxisFraction = 0.0f, |
|||
bool useMagnifier = false, |
|||
float magnification = 1.0f, |
|||
bool clipToSize = true, |
|||
bool renderChildrenOutsideViewport = false, |
|||
List<RenderBox> children = null |
|||
) { |
|||
D.assert(childManager != null); |
|||
D.assert(offset != null); |
|||
D.assert(diameterRatio > 0, () => diameterRatioZeroMessage); |
|||
D.assert(perspective > 0); |
|||
D.assert(perspective <= 0.01f, () => perspectiveTooHighMessage); |
|||
D.assert(magnification > 0); |
|||
D.assert(itemExtent > 0); |
|||
D.assert( |
|||
!renderChildrenOutsideViewport || !clipToSize, |
|||
() => clipToSizeAndRenderChildrenOutsideViewportConflict |
|||
); |
|||
|
|||
this.childManager = childManager; |
|||
this._offset = offset; |
|||
this._diameterRatio = diameterRatio; |
|||
this._perspective = perspective; |
|||
this._offAxisFraction = offAxisFraction; |
|||
this._useMagnifier = useMagnifier; |
|||
this._magnification = magnification; |
|||
this._itemExtent = itemExtent; |
|||
this._clipToSize = clipToSize; |
|||
this._renderChildrenOutsideViewport = renderChildrenOutsideViewport; |
|||
this.addAll(children); |
|||
} |
|||
|
|||
public const float defaultDiameterRatio = 2.0f; |
|||
|
|||
public const float defaultPerspective = 0.003f; |
|||
|
|||
public const string diameterRatioZeroMessage = "You can't set a diameterRatio " + |
|||
"of 0 or of a negative number. It would imply a cylinder of 0 in diameter " + |
|||
"in which case nothing will be drawn."; |
|||
|
|||
public const string perspectiveTooHighMessage = "A perspective too high will " + |
|||
"be clipped in the z-axis and therefore not renderable. Value must be " + |
|||
"between 0 and 0.0f1."; |
|||
|
|||
public const string clipToSizeAndRenderChildrenOutsideViewportConflict = |
|||
"Cannot renderChildrenOutsideViewport and clipToSize since children " + |
|||
"rendered outside will be clipped anyway."; |
|||
|
|||
public readonly IListWheelChildManager childManager; |
|||
|
|||
public ViewportOffset offset { |
|||
get { return this._offset; } |
|||
set { |
|||
D.assert(value != null); |
|||
if (value == this._offset) { |
|||
return; |
|||
} |
|||
|
|||
if (this.attached) { |
|||
this._offset.removeListener(this._hasScrolled); |
|||
} |
|||
|
|||
this._offset = value; |
|||
if (this.attached) { |
|||
this._offset.addListener(this._hasScrolled); |
|||
} |
|||
|
|||
this.markNeedsLayout(); |
|||
} |
|||
} |
|||
|
|||
ViewportOffset _offset; |
|||
|
|||
public float diameterRatio { |
|||
get { return this._diameterRatio; } |
|||
set { |
|||
D.assert( |
|||
value > 0, |
|||
() => diameterRatioZeroMessage |
|||
); |
|||
|
|||
this._diameterRatio = value; |
|||
this.markNeedsPaint(); |
|||
} |
|||
} |
|||
|
|||
float _diameterRatio; |
|||
|
|||
public float perspective { |
|||
get { return this._perspective; } |
|||
set { |
|||
D.assert(value > 0); |
|||
D.assert( |
|||
value <= 0.01f, |
|||
() => perspectiveTooHighMessage |
|||
); |
|||
if (value == this._perspective) { |
|||
return; |
|||
} |
|||
|
|||
this._perspective = value; |
|||
this.markNeedsPaint(); |
|||
} |
|||
} |
|||
|
|||
float _perspective; |
|||
|
|||
public float offAxisFraction { |
|||
get { return this._offAxisFraction; } |
|||
set { |
|||
if (value == this._offAxisFraction) { |
|||
return; |
|||
} |
|||
|
|||
this._offAxisFraction = value; |
|||
this.markNeedsPaint(); |
|||
} |
|||
} |
|||
|
|||
float _offAxisFraction = 0.0f; |
|||
|
|||
public bool useMagnifier { |
|||
get { return this._useMagnifier; } |
|||
set { |
|||
if (value == this._useMagnifier) { |
|||
return; |
|||
} |
|||
|
|||
this._useMagnifier = value; |
|||
this.markNeedsPaint(); |
|||
} |
|||
} |
|||
|
|||
bool _useMagnifier = false; |
|||
|
|||
public float magnification { |
|||
get { return this._magnification; } |
|||
set { |
|||
D.assert(value > 0); |
|||
if (value == this._magnification) { |
|||
return; |
|||
} |
|||
|
|||
this._magnification = value; |
|||
this.markNeedsPaint(); |
|||
} |
|||
} |
|||
|
|||
float _magnification = 1.0f; |
|||
|
|||
public float itemExtent { |
|||
get { return this._itemExtent; } |
|||
set { |
|||
D.assert(value > 0); |
|||
if (value == this._itemExtent) { |
|||
return; |
|||
} |
|||
|
|||
this._itemExtent = value; |
|||
this.markNeedsLayout(); |
|||
} |
|||
} |
|||
|
|||
float _itemExtent; |
|||
|
|||
public bool clipToSize { |
|||
get { return this._clipToSize; } |
|||
set { |
|||
D.assert( |
|||
!this.renderChildrenOutsideViewport || !this.clipToSize, |
|||
() => clipToSizeAndRenderChildrenOutsideViewportConflict |
|||
); |
|||
if (value == this._clipToSize) { |
|||
return; |
|||
} |
|||
|
|||
this._clipToSize = value; |
|||
this.markNeedsPaint(); |
|||
} |
|||
} |
|||
|
|||
bool _clipToSize; |
|||
|
|||
public bool renderChildrenOutsideViewport { |
|||
get { return this._renderChildrenOutsideViewport; } |
|||
set { |
|||
D.assert( |
|||
!this.renderChildrenOutsideViewport || !this.clipToSize, |
|||
() => clipToSizeAndRenderChildrenOutsideViewportConflict |
|||
); |
|||
if (value == this._renderChildrenOutsideViewport) { |
|||
return; |
|||
} |
|||
|
|||
this._renderChildrenOutsideViewport = value; |
|||
this.markNeedsLayout(); |
|||
} |
|||
} |
|||
|
|||
bool _renderChildrenOutsideViewport; |
|||
|
|||
|
|||
void _hasScrolled() { |
|||
this.markNeedsLayout(); |
|||
} |
|||
|
|||
public override void setupParentData(RenderObject child) { |
|||
if (!(child.parentData is ListWheelParentData)) { |
|||
child.parentData = new ListWheelParentData(); |
|||
} |
|||
} |
|||
|
|||
public override void attach(object owner) { |
|||
base.attach(owner); |
|||
this._offset.addListener(this._hasScrolled); |
|||
} |
|||
|
|||
public override void detach() { |
|||
this._offset.removeListener(this._hasScrolled); |
|||
base.detach(); |
|||
} |
|||
|
|||
public override bool isRepaintBoundary { |
|||
get { return true; } |
|||
} |
|||
|
|||
float _viewportExtent { |
|||
get { |
|||
D.assert(this.hasSize); |
|||
return this.size.height; |
|||
} |
|||
} |
|||
|
|||
float _minEstimatedScrollExtent { |
|||
get { |
|||
D.assert(this.hasSize); |
|||
if (this.childManager.childCount == null) { |
|||
return float.NegativeInfinity; |
|||
} |
|||
|
|||
return 0.0f; |
|||
} |
|||
} |
|||
|
|||
float _maxEstimatedScrollExtent { |
|||
get { |
|||
D.assert(this.hasSize); |
|||
if (this.childManager.childCount == null) { |
|||
return float.PositiveInfinity; |
|||
} |
|||
|
|||
return Mathf.Max(0.0f, ((this.childManager.childCount ?? 0) - 1) * this._itemExtent); |
|||
} |
|||
} |
|||
|
|||
float _topScrollMarginExtent { |
|||
get { |
|||
D.assert(this.hasSize); |
|||
return -this.size.height / 2.0f + this._itemExtent / 2.0f; |
|||
} |
|||
} |
|||
|
|||
float _getUntransformedPaintingCoordinateY(float layoutCoordinateY) { |
|||
return layoutCoordinateY - this._topScrollMarginExtent - this.offset.pixels; |
|||
} |
|||
|
|||
float _maxVisibleRadian { |
|||
get { |
|||
if (this._diameterRatio < 1.0f) { |
|||
return Mathf.PI / 2.0f; |
|||
} |
|||
|
|||
return Mathf.Asin(1.0f / this._diameterRatio); |
|||
} |
|||
} |
|||
|
|||
float _getIntrinsicCrossAxis(___ChildSizingFunction childSize) { |
|||
float extent = 0.0f; |
|||
RenderBox child = this.firstChild; |
|||
while (child != null) { |
|||
extent = Mathf.Max(extent, childSize(child)); |
|||
child = this.childAfter(child); |
|||
} |
|||
|
|||
return extent; |
|||
} |
|||
|
|||
protected override float computeMinIntrinsicWidth(float height) { |
|||
return this._getIntrinsicCrossAxis( |
|||
(RenderBox child) => child.getMinIntrinsicWidth(height) |
|||
); |
|||
} |
|||
|
|||
protected override float computeMaxIntrinsicWidth(float height) { |
|||
return this._getIntrinsicCrossAxis( |
|||
(RenderBox child) => child.getMaxIntrinsicWidth(height) |
|||
); |
|||
} |
|||
|
|||
protected override float computeMinIntrinsicHeight(float width) { |
|||
if (this.childManager.childCount == null) { |
|||
return 0.0f; |
|||
} |
|||
|
|||
return (this.childManager.childCount ?? 0) * this._itemExtent; |
|||
} |
|||
|
|||
protected internal override float computeMaxIntrinsicHeight(float width) { |
|||
if (this.childManager.childCount == null) { |
|||
return 0.0f; |
|||
} |
|||
|
|||
return (this.childManager.childCount ?? 0) * this._itemExtent; |
|||
} |
|||
|
|||
protected override bool sizedByParent { |
|||
get { return true; } |
|||
} |
|||
|
|||
protected override void performResize() { |
|||
this.size = this.constraints.biggest; |
|||
} |
|||
|
|||
public int indexOf(RenderBox child) { |
|||
D.assert(child != null); |
|||
ListWheelParentData childParentData = (ListWheelParentData) child.parentData; |
|||
return childParentData.index; |
|||
} |
|||
|
|||
public int scrollOffsetToIndex(float scrollOffset) { |
|||
return (scrollOffset / this.itemExtent).floor(); |
|||
} |
|||
|
|||
public float indexToScrollOffset(int index) { |
|||
return index * this.itemExtent; |
|||
} |
|||
|
|||
void _createChild(int index, |
|||
RenderBox after = null |
|||
) { |
|||
this.invokeLayoutCallback<BoxConstraints>((BoxConstraints constraints) => { |
|||
D.assert(this.constraints == this.constraints); |
|||
this.childManager.createChild(index, after: after); |
|||
}); |
|||
} |
|||
|
|||
void _destroyChild(RenderBox child) { |
|||
this.invokeLayoutCallback<BoxConstraints>((BoxConstraints constraints) => { |
|||
D.assert(this.constraints == this.constraints); |
|||
this.childManager.removeChild(child); |
|||
}); |
|||
} |
|||
|
|||
void _layoutChild(RenderBox child, BoxConstraints constraints, int index) { |
|||
child.layout(constraints, parentUsesSize: true); |
|||
ListWheelParentData childParentData = (ListWheelParentData) child.parentData; |
|||
float crossPosition = this.size.width / 2.0f - child.size.width / 2.0f; |
|||
childParentData.offset = new Offset(crossPosition, this.indexToScrollOffset(index)); |
|||
} |
|||
|
|||
protected override void performLayout() { |
|||
BoxConstraints childConstraints = this.constraints.copyWith( |
|||
minHeight: this._itemExtent, |
|||
maxHeight: this._itemExtent, |
|||
minWidth: 0.0f |
|||
); |
|||
|
|||
float visibleHeight = this.size.height; |
|||
if (this.renderChildrenOutsideViewport) { |
|||
visibleHeight *= 2; |
|||
} |
|||
|
|||
float firstVisibleOffset = this.offset.pixels + this._itemExtent / 2 - visibleHeight / 2; |
|||
float lastVisibleOffset = firstVisibleOffset + visibleHeight; |
|||
|
|||
int targetFirstIndex = this.scrollOffsetToIndex(firstVisibleOffset); |
|||
int targetLastIndex = this.scrollOffsetToIndex(lastVisibleOffset); |
|||
|
|||
if (targetLastIndex * this._itemExtent == lastVisibleOffset) { |
|||
targetLastIndex--; |
|||
} |
|||
|
|||
while (!this.childManager.childExistsAt(targetFirstIndex) && targetFirstIndex <= targetLastIndex) { |
|||
targetFirstIndex++; |
|||
} |
|||
|
|||
while (!this.childManager.childExistsAt(targetLastIndex) && targetFirstIndex <= targetLastIndex) { |
|||
targetLastIndex--; |
|||
} |
|||
|
|||
if (targetFirstIndex > targetLastIndex) { |
|||
while (this.firstChild != null) { |
|||
this._destroyChild(this.firstChild); |
|||
} |
|||
|
|||
return; |
|||
} |
|||
|
|||
|
|||
if (this.childCount > 0 && |
|||
(this.indexOf(this.firstChild) > targetLastIndex || this.indexOf(this.lastChild) < targetFirstIndex)) { |
|||
while (this.firstChild != null) { |
|||
this._destroyChild(this.firstChild); |
|||
} |
|||
} |
|||
|
|||
|
|||
if (this.childCount == 0) { |
|||
this._createChild(targetFirstIndex); |
|||
this._layoutChild(this.firstChild, childConstraints, targetFirstIndex); |
|||
} |
|||
|
|||
int currentFirstIndex = this.indexOf(this.firstChild); |
|||
int currentLastIndex = this.indexOf(this.lastChild); |
|||
|
|||
while (currentFirstIndex < targetFirstIndex) { |
|||
this._destroyChild(this.firstChild); |
|||
currentFirstIndex++; |
|||
} |
|||
|
|||
while (currentLastIndex > targetLastIndex) { |
|||
this._destroyChild(this.lastChild); |
|||
currentLastIndex--; |
|||
} |
|||
|
|||
RenderBox child = this.firstChild; |
|||
while (child != null) { |
|||
child.layout(childConstraints, parentUsesSize: true); |
|||
child = this.childAfter(child); |
|||
} |
|||
|
|||
while (currentFirstIndex > targetFirstIndex) { |
|||
this._createChild(currentFirstIndex - 1); |
|||
this._layoutChild(this.firstChild, childConstraints, --currentFirstIndex); |
|||
} |
|||
|
|||
while (currentLastIndex < targetLastIndex) { |
|||
this._createChild(currentLastIndex + 1, after: this.lastChild); |
|||
this._layoutChild(this.lastChild, childConstraints, ++currentLastIndex); |
|||
} |
|||
|
|||
this.offset.applyViewportDimension(this._viewportExtent); |
|||
|
|||
float minScrollExtent = this.childManager.childExistsAt(targetFirstIndex - 1) |
|||
? this._minEstimatedScrollExtent |
|||
: this.indexToScrollOffset(targetFirstIndex); |
|||
float maxScrollExtent = this.childManager.childExistsAt(targetLastIndex + 1) |
|||
? this._maxEstimatedScrollExtent |
|||
: this.indexToScrollOffset(targetLastIndex); |
|||
this.offset.applyContentDimensions(minScrollExtent, maxScrollExtent); |
|||
} |
|||
|
|||
bool _shouldClipAtCurrentOffset() { |
|||
float highestUntransformedPaintY = this._getUntransformedPaintingCoordinateY(0.0f); |
|||
return highestUntransformedPaintY < 0.0f |
|||
|| this.size.height < highestUntransformedPaintY + this._maxEstimatedScrollExtent + this._itemExtent; |
|||
} |
|||
|
|||
public override void paint(PaintingContext context, Offset offset) { |
|||
if (this.childCount > 0) { |
|||
if (this._clipToSize && this._shouldClipAtCurrentOffset()) { |
|||
context.pushClipRect( |
|||
this.needsCompositing, |
|||
offset, |
|||
Offset.zero & this.size, this._paintVisibleChildren |
|||
); |
|||
} |
|||
else { |
|||
this._paintVisibleChildren(context, offset); |
|||
} |
|||
} |
|||
} |
|||
|
|||
void _paintVisibleChildren(PaintingContext context, Offset offset) { |
|||
RenderBox childToPaint = this.firstChild; |
|||
ListWheelParentData childParentData = (ListWheelParentData) childToPaint?.parentData; |
|||
|
|||
while (childParentData != null) { |
|||
this._paintTransformedChild(childToPaint, context, offset, childParentData.offset); |
|||
childToPaint = this.childAfter(childToPaint); |
|||
childParentData = (ListWheelParentData) childToPaint?.parentData; |
|||
} |
|||
} |
|||
|
|||
void _paintTransformedChild(RenderBox child, PaintingContext context, Offset offset, Offset layoutOffset) { |
|||
Offset untransformedPaintingCoordinates = offset + new Offset( |
|||
layoutOffset.dx, |
|||
this._getUntransformedPaintingCoordinateY(layoutOffset.dy) |
|||
); |
|||
|
|||
|
|||
float fractionalY = (untransformedPaintingCoordinates.dy + this._itemExtent / 2.0f) / this.size.height; |
|||
|
|||
float angle = -(fractionalY - 0.5f) * 2.0f * this._maxVisibleRadian; |
|||
if (angle > Mathf.PI / 2.0f || angle < -Mathf.PI / 2.0f) { |
|||
return; |
|||
} |
|||
|
|||
var radius = this.size.height * this._diameterRatio / 2.0f; |
|||
var deltaY = radius * Mathf.Sin(angle); |
|||
|
|||
Matrix3 transform = Matrix3.I(); |
|||
// Matrix4x4 transform2 = MatrixUtils.createCylindricalProjectionTransform(
|
|||
// radius: this.size.height * this._diameterRatio / 2.0f,
|
|||
// angle: angle,
|
|||
// perspective: this._perspective
|
|||
// );
|
|||
|
|||
// Offset offsetToCenter = new Offset(untransformedPaintingCoordinates.dx, -this._topScrollMarginExtent);
|
|||
|
|||
Offset offsetToCenter = |
|||
new Offset(untransformedPaintingCoordinates.dx, -deltaY - this._topScrollMarginExtent); |
|||
|
|||
if (!this.useMagnifier) { |
|||
this._paintChildCylindrically(context, offset, child, transform, offsetToCenter); |
|||
} |
|||
else { |
|||
this._paintChildWithMagnifier( |
|||
context, |
|||
offset, |
|||
child, |
|||
transform, |
|||
offsetToCenter, |
|||
untransformedPaintingCoordinates |
|||
); |
|||
} |
|||
} |
|||
|
|||
void _paintChildWithMagnifier( |
|||
PaintingContext context, |
|||
Offset offset, |
|||
RenderBox child, |
|||
// Matrix4x4 cylindricalTransform,
|
|||
Matrix3 cylindricalTransform, |
|||
Offset offsetToCenter, |
|||
Offset untransformedPaintingCoordinates |
|||
) { |
|||
float magnifierTopLinePosition = this.size.height / 2 - this._itemExtent * this._magnification / 2; |
|||
float magnifierBottomLinePosition = this.size.height / 2 + this._itemExtent * this._magnification / 2; |
|||
|
|||
bool isAfterMagnifierTopLine = untransformedPaintingCoordinates.dy |
|||
>= magnifierTopLinePosition - this._itemExtent * this._magnification; |
|||
bool isBeforeMagnifierBottomLine = untransformedPaintingCoordinates.dy |
|||
<= magnifierBottomLinePosition; |
|||
|
|||
if (isAfterMagnifierTopLine && isBeforeMagnifierBottomLine) { |
|||
Rect centerRect = Rect.fromLTWH( |
|||
0.0f, |
|||
magnifierTopLinePosition, this.size.width, this._itemExtent * this._magnification); |
|||
Rect topHalfRect = Rect.fromLTWH( |
|||
0.0f, |
|||
0.0f, this.size.width, |
|||
magnifierTopLinePosition); |
|||
Rect bottomHalfRect = Rect.fromLTWH( |
|||
0.0f, |
|||
magnifierBottomLinePosition, this.size.width, |
|||
magnifierTopLinePosition); |
|||
|
|||
context.pushClipRect( |
|||
false, |
|||
offset, |
|||
centerRect, |
|||
(PaintingContext context1, Offset offset1) => { |
|||
context1.pushTransform( |
|||
false, |
|||
offset1, |
|||
cylindricalTransform, |
|||
// this._centerOriginTransform(cylindricalTransform),
|
|||
(PaintingContext context2, Offset offset2) => { |
|||
context2.paintChild( |
|||
child, |
|||
offset2 + untransformedPaintingCoordinates); |
|||
}); |
|||
}); |
|||
|
|||
context.pushClipRect( |
|||
false, |
|||
offset, |
|||
untransformedPaintingCoordinates.dy <= magnifierTopLinePosition |
|||
? topHalfRect |
|||
: bottomHalfRect, |
|||
(PaintingContext context1, Offset offset1) => { |
|||
this._paintChildCylindrically( |
|||
context1, |
|||
offset1, |
|||
child, |
|||
cylindricalTransform, |
|||
offsetToCenter |
|||
); |
|||
} |
|||
); |
|||
} |
|||
else { |
|||
this._paintChildCylindrically( |
|||
context, |
|||
offset, |
|||
child, |
|||
cylindricalTransform, |
|||
offsetToCenter |
|||
); |
|||
} |
|||
} |
|||
|
|||
void _paintChildCylindrically( |
|||
PaintingContext context, |
|||
Offset offset, |
|||
RenderBox child, |
|||
// Matrix4x4 cylindricalTransform,
|
|||
Matrix3 cylindricalTransform, |
|||
Offset offsetToCenter |
|||
) { |
|||
context.pushTransform( |
|||
false, |
|||
offset, |
|||
cylindricalTransform, |
|||
// this._centerOriginTransform(cylindricalTransform),
|
|||
(PaintingContext _context, Offset _offset) => { _context.paintChild(child, _offset + offsetToCenter); } |
|||
); |
|||
} |
|||
|
|||
Matrix4x4 _magnifyTransform() { |
|||
Matrix4x4 magnify = Matrix4x4.identity; |
|||
magnify.translate(this.size.width * (-this._offAxisFraction + 0.5f), this.size.height / 2f); |
|||
magnify.scale(this._magnification, this._magnification, this._magnification); |
|||
magnify.translate(-this.size.width * (-this._offAxisFraction + 0.5f), -this.size.height / 2f); |
|||
return magnify; |
|||
} |
|||
|
|||
Matrix3 _centerOriginTransform(Matrix3 originalMatrix) { |
|||
Matrix3 result = Matrix3.I(); |
|||
Offset centerOriginTranslation = Alignment.center.alongSize(this.size); |
|||
result.setTranslate(centerOriginTranslation.dx * (-this._offAxisFraction * 2 + 1), |
|||
centerOriginTranslation.dy); |
|||
result.multiply(originalMatrix); |
|||
result.setTranslate(-centerOriginTranslation.dx * (-this._offAxisFraction * 2 + 1), |
|||
-centerOriginTranslation.dy); |
|||
return result; |
|||
} |
|||
|
|||
Matrix4x4 _centerOriginTransform(Matrix4x4 originalMatrix) { |
|||
Matrix4x4 result = Matrix4x4.identity; |
|||
Offset centerOriginTranslation = Alignment.center.alongSize(this.size); |
|||
result.translate(centerOriginTranslation.dx * (-this._offAxisFraction * 2 + 1), |
|||
centerOriginTranslation.dy); |
|||
result.multiply(originalMatrix); |
|||
result.translate(-centerOriginTranslation.dx * (-this._offAxisFraction * 2 + 1), |
|||
-centerOriginTranslation.dy); |
|||
return result; |
|||
} |
|||
|
|||
public void applyPaintTransform(RenderBox child, Matrix4x4 transform) { |
|||
ListWheelParentData parentData = (ListWheelParentData) child?.parentData; |
|||
transform.translate(0.0f, this._getUntransformedPaintingCoordinateY(parentData.offset.dy)); |
|||
} |
|||
|
|||
public override Rect describeApproximatePaintClip(RenderObject child) { |
|||
if (child != null && this._shouldClipAtCurrentOffset()) { |
|||
return Offset.zero & this.size; |
|||
} |
|||
|
|||
return null; |
|||
} |
|||
|
|||
protected override bool hitTestChildren(HitTestResult result, Offset position = null |
|||
) { |
|||
return false; |
|||
} |
|||
|
|||
public RevealedOffset getOffsetToReveal(RenderObject target, float alignment, |
|||
Rect rect = null |
|||
) { |
|||
rect = rect ?? target.paintBounds; |
|||
|
|||
RenderObject child = target; |
|||
while (child.parent != this) { |
|||
child = (RenderObject) child.parent; |
|||
} |
|||
|
|||
ListWheelParentData parentData = (ListWheelParentData) child.parentData; |
|||
float targetOffset = parentData.offset.dy; |
|||
Matrix4x4 transform = target.getTransformTo(this).toMatrix4x4(); |
|||
Rect bounds = MatrixUtils.transformRect(transform, rect); |
|||
Rect targetRect = bounds.translate(0.0f, (this.size.height - this.itemExtent) / 2); |
|||
|
|||
return new RevealedOffset(offset: targetOffset, rect: targetRect); |
|||
} |
|||
|
|||
public new RenderObject parent { |
|||
get { return (RenderObject) base.parent; } |
|||
} |
|||
|
|||
public new void showOnScreen( |
|||
RenderObject descendant = null, |
|||
Rect rect = null, |
|||
TimeSpan? duration = null, |
|||
Curve curve = null |
|||
) { |
|||
duration = duration ?? TimeSpan.Zero; |
|||
curve = curve ?? Curves.ease; |
|||
if (descendant != null) { |
|||
RevealedOffset revealedOffset = this.getOffsetToReveal(descendant, 0.5f, rect: rect); |
|||
if (duration == TimeSpan.Zero) { |
|||
this.offset.jumpTo(revealedOffset.offset); |
|||
} |
|||
else { |
|||
this.offset.animateTo(revealedOffset.offset, duration: (TimeSpan) duration, curve: curve); |
|||
} |
|||
|
|||
rect = revealedOffset.rect; |
|||
} |
|||
|
|||
base.showOnScreen( |
|||
rect: rect, |
|||
duration: duration, |
|||
curve: curve |
|||
); |
|||
} |
|||
} |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: 19267e4bc9a214b5eacd791e58a63f11 |
|||
MonoImporter: |
|||
externalObjects: {} |
|||
serializedVersion: 2 |
|||
defaultReferences: [] |
|||
executionOrder: 0 |
|||
icon: {instanceID: 0} |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
using System; |
|||
using System.Collections.Generic; |
|||
using RSG; |
|||
using Unity.UIWidgets.animation; |
|||
using Unity.UIWidgets.foundation; |
|||
using Unity.UIWidgets.painting; |
|||
using Unity.UIWidgets.physics; |
|||
using Unity.UIWidgets.rendering; |
|||
using Unity.UIWidgets.scheduler; |
|||
using Unity.UIWidgets.ui; |
|||
using UnityEngine; |
|||
|
|||
namespace Unity.UIWidgets.widgets { |
|||
public interface ListWheelChildDelegate { |
|||
Widget build(BuildContext context, int index); |
|||
int? estimatedChildCount { get; } |
|||
int trueIndexOf(int index); |
|||
bool shouldRebuild(ListWheelChildDelegate oldDelegate); |
|||
} |
|||
|
|||
public class ListWheelChildListDelegate : ListWheelChildDelegate { |
|||
public ListWheelChildListDelegate( |
|||
List<Widget> children |
|||
) { |
|||
D.assert(children != null); |
|||
this.children = children; |
|||
} |
|||
|
|||
public readonly List<Widget> children; |
|||
|
|||
public int? estimatedChildCount { |
|||
get { return this.children.Count; } |
|||
} |
|||
|
|||
public Widget build(BuildContext context, int index) { |
|||
if (index < 0 || index >= this.children.Count) { |
|||
return null; |
|||
} |
|||
|
|||
return new Container(child: this.children[index]); |
|||
} |
|||
|
|||
public int trueIndexOf(int index) { |
|||
return index; |
|||
} |
|||
|
|||
public bool shouldRebuild(ListWheelChildDelegate oldDelegate) { |
|||
return this.children != ((ListWheelChildListDelegate) oldDelegate).children; |
|||
} |
|||
} |
|||
|
|||
public class ListWheelChildLoopingListDelegate : ListWheelChildDelegate { |
|||
public ListWheelChildLoopingListDelegate( |
|||
List<Widget> children |
|||
) { |
|||
D.assert(children != null); |
|||
this.children = children; |
|||
} |
|||
|
|||
public readonly List<Widget> children; |
|||
|
|||
public int? estimatedChildCount { |
|||
get { return null; } |
|||
} |
|||
|
|||
public int trueIndexOf(int index) { |
|||
while (index < 0) { |
|||
index += this.children.Count; |
|||
} |
|||
|
|||
return index % this.children.Count; |
|||
} |
|||
|
|||
public Widget build(BuildContext context, int index) { |
|||
if (this.children.isEmpty()) { |
|||
return null; |
|||
} |
|||
|
|||
while (index < 0) { |
|||
index += this.children.Count; |
|||
} |
|||
|
|||
return new Container(child: this.children[index % this.children.Count]); |
|||
} |
|||
|
|||
public bool shouldRebuild(ListWheelChildDelegate oldDelegate) { |
|||
return this.children != ((ListWheelChildLoopingListDelegate) oldDelegate).children; |
|||
} |
|||
} |
|||
|
|||
public class ListWheelChildBuilderDelegate : ListWheelChildDelegate { |
|||
public ListWheelChildBuilderDelegate( |
|||
IndexedWidgetBuilder builder, |
|||
int? childCount = null |
|||
) { |
|||
D.assert(builder != null); |
|||
this.builder = builder; |
|||
this.childCount = childCount; |
|||
} |
|||
|
|||
public readonly IndexedWidgetBuilder builder; |
|||
|
|||
public readonly int? childCount; |
|||
|
|||
public int? estimatedChildCount { |
|||
get { return this.childCount; } |
|||
} |
|||
|
|||
public Widget build(BuildContext context, int index) { |
|||
if (this.childCount == null) { |
|||
Widget child = this.builder(context, index); |
|||
return child == null ? null : new Container(child: child); |
|||
} |
|||
|
|||
if (index < 0 || index >= this.childCount) { |
|||
return null; |
|||
} |
|||
|
|||
return new Container(child: this.builder(context, index)); |
|||
} |
|||
|
|||
public int trueIndexOf(int index) { |
|||
return index; |
|||
} |
|||
|
|||
public bool shouldRebuild(ListWheelChildDelegate oldDelegate) { |
|||
return this.builder != ((ListWheelChildBuilderDelegate) oldDelegate).builder || |
|||
this.childCount != ((ListWheelChildBuilderDelegate) oldDelegate).childCount; |
|||
} |
|||
} |
|||
|
|||
class ListWheelScrollViewUtils { |
|||
public static int _getItemFromOffset( |
|||
float offset, |
|||
float itemExtent, |
|||
float minScrollExtent, |
|||
float maxScrollExtent |
|||
) { |
|||
return (_clipOffsetToScrollableRange(offset, minScrollExtent, maxScrollExtent) / itemExtent).round(); |
|||
} |
|||
|
|||
public static float _clipOffsetToScrollableRange( |
|||
float offset, |
|||
float minScrollExtent, |
|||
float maxScrollExtent |
|||
) { |
|||
return Mathf.Min(Mathf.Max(offset, minScrollExtent), maxScrollExtent); |
|||
} |
|||
} |
|||
|
|||
public class FixedExtentScrollController : ScrollController { |
|||
public FixedExtentScrollController( |
|||
int initialItem = 0 |
|||
) { |
|||
this.initialItem = initialItem; |
|||
} |
|||
|
|||
public readonly int initialItem; |
|||
|
|||
public int selectedItem { |
|||
get { |
|||
D.assert(this.positions.isNotEmpty(), |
|||
() => |
|||
"FixedExtentScrollController.selectedItem cannot be accessed before a scroll view is built with it." |
|||
); |
|||
D.assert(this.positions.Count == 1, |
|||
() => |
|||
"The selectedItem property cannot be read when multiple scroll views are attached to the same FixedExtentScrollController." |
|||
); |
|||
_FixedExtentScrollPosition position = (_FixedExtentScrollPosition) this.position; |
|||
return position.itemIndex; |
|||
} |
|||
} |
|||
|
|||
public IPromise animateToItem( |
|||
int itemIndex, |
|||
TimeSpan duration, |
|||
Curve curve |
|||
) { |
|||
if (!this.hasClients) { |
|||
return Promise.Resolved(); |
|||
} |
|||
|
|||
List<IPromise> futures = new List<IPromise>(); |
|||
foreach (_FixedExtentScrollPosition position in this.positions) { |
|||
futures.Add(position.animateTo( |
|||
itemIndex * position.itemExtent, |
|||
duration: duration, |
|||
curve: curve |
|||
)); |
|||
} |
|||
|
|||
return Promise.All(futures); |
|||
} |
|||
|
|||
public void jumpToItem(int itemIndex) { |
|||
foreach (_FixedExtentScrollPosition position in this.positions) { |
|||
position.jumpTo(itemIndex * position.itemExtent); |
|||
} |
|||
} |
|||
|
|||
public override ScrollPosition createScrollPosition(ScrollPhysics physics, ScrollContext context, |
|||
ScrollPosition oldPosition) { |
|||
return new _FixedExtentScrollPosition( |
|||
physics: physics, |
|||
context: context, |
|||
initialItem: this.initialItem, |
|||
oldPosition: oldPosition |
|||
); |
|||
} |
|||
} |
|||
|
|||
public interface IFixedExtentMetrics { |
|||
int itemIndex { set; get; } |
|||
|
|||
FixedExtentMetrics copyWith( |
|||
float? minScrollExtent = null, |
|||
float? maxScrollExtent = null, |
|||
float? pixels = null, |
|||
float? viewportDimension = null, |
|||
AxisDirection? axisDirection = null, |
|||
int? itemIndex = null |
|||
); |
|||
} |
|||
|
|||
public class FixedExtentMetrics : FixedScrollMetrics, IFixedExtentMetrics { |
|||
public FixedExtentMetrics( |
|||
int itemIndex, |
|||
float minScrollExtent = 0.0f, |
|||
float maxScrollExtent = 0.0f, |
|||
float pixels = 0.0f, |
|||
float viewportDimension = 0.0f, |
|||
AxisDirection axisDirection = AxisDirection.down |
|||
) : base( |
|||
minScrollExtent: minScrollExtent, |
|||
maxScrollExtent: maxScrollExtent, |
|||
pixels: pixels, |
|||
viewportDimension: viewportDimension, |
|||
axisDirection: axisDirection |
|||
) { |
|||
this.itemIndex = itemIndex; |
|||
} |
|||
|
|||
public int itemIndex { get; set; } |
|||
|
|||
public FixedExtentMetrics copyWith( |
|||
float? minScrollExtent = null, |
|||
float? maxScrollExtent = null, |
|||
float? pixels = null, |
|||
float? viewportDimension = null, |
|||
AxisDirection? axisDirection = null, |
|||
int? itemIndex = null |
|||
) { |
|||
return new FixedExtentMetrics( |
|||
minScrollExtent: minScrollExtent ?? this.minScrollExtent, |
|||
maxScrollExtent: maxScrollExtent ?? this.maxScrollExtent, |
|||
pixels: pixels ?? this.pixels, |
|||
viewportDimension: viewportDimension ?? this.viewportDimension, |
|||
axisDirection: axisDirection ?? this.axisDirection, |
|||
itemIndex: itemIndex ?? this.itemIndex |
|||
); |
|||
} |
|||
} |
|||
|
|||
class _FixedExtentScrollPosition : ScrollPositionWithSingleContext, IFixedExtentMetrics { |
|||
public _FixedExtentScrollPosition( |
|||
ScrollPhysics physics, |
|||
ScrollContext context, |
|||
int initialItem, |
|||
bool keepScrollOffset = true, |
|||
ScrollPosition oldPosition = null, |
|||
string debugLabel = null |
|||
) : base( |
|||
physics: physics, |
|||
context: context, |
|||
initialPixels: _getItemExtentFromScrollContext(context) * initialItem, |
|||
keepScrollOffset: keepScrollOffset, |
|||
oldPosition: oldPosition, |
|||
debugLabel: debugLabel |
|||
) { |
|||
D.assert( |
|||
context is _FixedExtentScrollableState, |
|||
() => "FixedExtentScrollController can only be used with ListWheelScrollViews" |
|||
); |
|||
} |
|||
|
|||
static float _getItemExtentFromScrollContext(ScrollContext context) { |
|||
_FixedExtentScrollableState scrollable = (_FixedExtentScrollableState) context; |
|||
return scrollable.itemExtent; |
|||
} |
|||
|
|||
public float itemExtent { |
|||
get { return _getItemExtentFromScrollContext(this.context); } |
|||
} |
|||
|
|||
|
|||
public int itemIndex { |
|||
get { |
|||
return ListWheelScrollViewUtils._getItemFromOffset( |
|||
offset: this.pixels, |
|||
itemExtent: this.itemExtent, |
|||
minScrollExtent: this.minScrollExtent, |
|||
maxScrollExtent: this.maxScrollExtent |
|||
); |
|||
} |
|||
set { } |
|||
} |
|||
|
|||
public FixedExtentMetrics copyWith( |
|||
float? minScrollExtent = null, |
|||
float? maxScrollExtent = null, |
|||
float? pixels = null, |
|||
float? viewportDimension = null, |
|||
AxisDirection? axisDirection = null, |
|||
int? itemIndex = null |
|||
) { |
|||
return new FixedExtentMetrics( |
|||
minScrollExtent: minScrollExtent ?? this.minScrollExtent, |
|||
maxScrollExtent: maxScrollExtent ?? this.maxScrollExtent, |
|||
pixels: pixels ?? this.pixels, |
|||
viewportDimension: viewportDimension ?? this.viewportDimension, |
|||
axisDirection: axisDirection ?? this.axisDirection, |
|||
itemIndex: itemIndex ?? this.itemIndex |
|||
); |
|||
} |
|||
} |
|||
|
|||
class _FixedExtentScrollable : Scrollable { |
|||
public _FixedExtentScrollable( |
|||
float itemExtent, |
|||
ViewportBuilder viewportBuilder, |
|||
Key key = null, |
|||
AxisDirection axisDirection = AxisDirection.down, |
|||
ScrollController controller = null, |
|||
ScrollPhysics physics = null |
|||
) : base( |
|||
key: key, |
|||
axisDirection: axisDirection, |
|||
controller: controller, |
|||
physics: physics, |
|||
viewportBuilder: viewportBuilder |
|||
) { |
|||
this.itemExtent = itemExtent; |
|||
} |
|||
|
|||
public readonly float itemExtent; |
|||
|
|||
public override State createState() { |
|||
return new _FixedExtentScrollableState(); |
|||
} |
|||
} |
|||
|
|||
class _FixedExtentScrollableState : ScrollableState { |
|||
public float itemExtent { |
|||
get { |
|||
_FixedExtentScrollable actualWidget = (_FixedExtentScrollable) this.widget; |
|||
return actualWidget.itemExtent; |
|||
} |
|||
} |
|||
} |
|||
|
|||
|
|||
public class FixedExtentScrollPhysics : ScrollPhysics { |
|||
public FixedExtentScrollPhysics( |
|||
ScrollPhysics parent = null |
|||
) : base(parent: parent) { } |
|||
|
|||
public override ScrollPhysics applyTo(ScrollPhysics ancestor) { |
|||
return new FixedExtentScrollPhysics(parent: this.buildParent(ancestor)); |
|||
} |
|||
|
|||
public override Simulation createBallisticSimulation(ScrollMetrics position, float velocity) { |
|||
D.assert( |
|||
position is _FixedExtentScrollPosition, |
|||
() => "FixedExtentScrollPhysics can only be used with Scrollables that uses " + |
|||
"the FixedExtentScrollController" |
|||
); |
|||
|
|||
_FixedExtentScrollPosition metrics = (_FixedExtentScrollPosition) position; |
|||
|
|||
if ((velocity <= 0.0f && metrics.pixels <= metrics.minScrollExtent) || |
|||
(velocity >= 0.0f && metrics.pixels >= metrics.maxScrollExtent)) { |
|||
return base.createBallisticSimulation(metrics, velocity); |
|||
} |
|||
|
|||
Simulation testFrictionSimulation = |
|||
base.createBallisticSimulation(metrics, velocity); |
|||
|
|||
if (testFrictionSimulation != null |
|||
&& (testFrictionSimulation.x(float.PositiveInfinity) == metrics.minScrollExtent |
|||
|| testFrictionSimulation.x(float.PositiveInfinity) == metrics.maxScrollExtent)) { |
|||
return base.createBallisticSimulation(metrics, velocity); |
|||
} |
|||
|
|||
int settlingItemIndex = ListWheelScrollViewUtils._getItemFromOffset( |
|||
offset: testFrictionSimulation?.x(float.PositiveInfinity) ?? metrics.pixels, |
|||
itemExtent: metrics.itemExtent, |
|||
minScrollExtent: metrics.minScrollExtent, |
|||
maxScrollExtent: metrics.maxScrollExtent |
|||
); |
|||
|
|||
float settlingPixels = settlingItemIndex * metrics.itemExtent; |
|||
|
|||
if (velocity.abs() < this.tolerance.velocity |
|||
&& (settlingPixels - metrics.pixels).abs() < this.tolerance.distance) { |
|||
return null; |
|||
} |
|||
|
|||
if (settlingItemIndex == metrics.itemIndex) { |
|||
return new SpringSimulation(this.spring, |
|||
metrics.pixels, |
|||
settlingPixels, |
|||
velocity, |
|||
tolerance: this.tolerance |
|||
); |
|||
} |
|||
|
|||
return FrictionSimulation.through( |
|||
metrics.pixels, |
|||
settlingPixels, |
|||
velocity, this.tolerance.velocity * velocity.sign() |
|||
); |
|||
} |
|||
} |
|||
|
|||
public class ListWheelScrollView : StatefulWidget { |
|||
public ListWheelScrollView( |
|||
float itemExtent, |
|||
List<Widget> children = null, |
|||
Key key = null, |
|||
ScrollController controller = null, |
|||
ScrollPhysics physics = null, |
|||
float diameterRatio = RenderListWheelViewport.defaultDiameterRatio, |
|||
float perspective = RenderListWheelViewport.defaultPerspective, |
|||
float offAxisFraction = 0.0f, |
|||
bool useMagnifier = false, |
|||
float magnification = 1.0f, |
|||
ValueChanged<int> onSelectedItemChanged = null, |
|||
bool clipToSize = true, |
|||
bool renderChildrenOutsideViewport = false, |
|||
ListWheelChildDelegate childDelegate = null |
|||
) : base(key: key) { |
|||
D.assert(children != null || childDelegate != null); |
|||
D.assert(diameterRatio > 0.0, () => RenderListWheelViewport.diameterRatioZeroMessage); |
|||
D.assert(perspective > 0); |
|||
D.assert(perspective <= 0.01f, () => RenderListWheelViewport.perspectiveTooHighMessage); |
|||
D.assert(magnification > 0); |
|||
D.assert(itemExtent > 0); |
|||
D.assert( |
|||
!renderChildrenOutsideViewport || !clipToSize, |
|||
() => RenderListWheelViewport.clipToSizeAndRenderChildrenOutsideViewportConflict |
|||
); |
|||
|
|||
this.childDelegate = childDelegate ?? new ListWheelChildListDelegate(children: children); |
|||
this.itemExtent = itemExtent; |
|||
this.controller = controller; |
|||
this.physics = physics; |
|||
this.diameterRatio = diameterRatio; |
|||
this.perspective = perspective; |
|||
this.offAxisFraction = offAxisFraction; |
|||
this.useMagnifier = useMagnifier; |
|||
this.magnification = magnification; |
|||
this.onSelectedItemChanged = onSelectedItemChanged; |
|||
this.clipToSize = clipToSize; |
|||
this.renderChildrenOutsideViewport = renderChildrenOutsideViewport; |
|||
} |
|||
|
|||
public static ListWheelScrollView useDelegate( |
|||
float itemExtent, |
|||
List<Widget> children = null, |
|||
ListWheelChildDelegate childDelegate = null, |
|||
Key key = null, |
|||
ScrollController controller = null, |
|||
ScrollPhysics physics = null, |
|||
float diameterRatio = RenderListWheelViewport.defaultDiameterRatio, |
|||
float perspective = RenderListWheelViewport.defaultPerspective, |
|||
float offAxisFraction = 0.0f, |
|||
bool useMagnifier = false, |
|||
float magnification = 1.0f, |
|||
ValueChanged<int> onSelectedItemChanged = null, |
|||
bool clipToSize = true, |
|||
bool renderChildrenOutsideViewport = false |
|||
) { |
|||
return new ListWheelScrollView( |
|||
itemExtent: itemExtent, |
|||
children: children, |
|||
childDelegate: childDelegate, |
|||
key: key, |
|||
controller: controller, |
|||
physics: physics, |
|||
diameterRatio: diameterRatio, |
|||
perspective: perspective, |
|||
offAxisFraction: offAxisFraction, |
|||
useMagnifier: useMagnifier, |
|||
magnification: magnification, |
|||
onSelectedItemChanged: onSelectedItemChanged, |
|||
clipToSize: clipToSize, |
|||
renderChildrenOutsideViewport: renderChildrenOutsideViewport |
|||
); |
|||
} |
|||
|
|||
public readonly ScrollController controller; |
|||
public readonly ScrollPhysics physics; |
|||
public readonly float diameterRatio; |
|||
public readonly float perspective; |
|||
public readonly float offAxisFraction; |
|||
public readonly bool useMagnifier; |
|||
public readonly float magnification; |
|||
public readonly float itemExtent; |
|||
public readonly ValueChanged<int> onSelectedItemChanged; |
|||
public readonly bool clipToSize; |
|||
public readonly bool renderChildrenOutsideViewport; |
|||
public readonly ListWheelChildDelegate childDelegate; |
|||
|
|||
public override State createState() { |
|||
return new _ListWheelScrollViewState(); |
|||
} |
|||
} |
|||
|
|||
class _ListWheelScrollViewState : State<ListWheelScrollView> { |
|||
int _lastReportedItemIndex = 0; |
|||
ScrollController scrollController; |
|||
|
|||
public override void initState() { |
|||
base.initState(); |
|||
this.scrollController = this.widget.controller ?? new FixedExtentScrollController(); |
|||
if (this.widget.controller is FixedExtentScrollController controller) { |
|||
this._lastReportedItemIndex = controller.initialItem; |
|||
} |
|||
} |
|||
|
|||
public override void didUpdateWidget(StatefulWidget oldWidget) { |
|||
base.didUpdateWidget(oldWidget); |
|||
if (this.widget.controller != null && this.widget.controller != this.scrollController) { |
|||
ScrollController oldScrollController = this.scrollController; |
|||
SchedulerBinding.instance.addPostFrameCallback((_) => { oldScrollController.dispose(); }); |
|||
this.scrollController = this.widget.controller; |
|||
} |
|||
} |
|||
|
|||
public override Widget build(BuildContext context) { |
|||
return new NotificationListener<ScrollNotification>( |
|||
onNotification: (ScrollNotification notification) => { |
|||
if (notification.depth == 0 |
|||
&& this.widget.onSelectedItemChanged != null |
|||
&& notification is ScrollUpdateNotification |
|||
&& notification.metrics is FixedExtentMetrics metrics) { |
|||
int currentItemIndex = metrics.itemIndex; |
|||
|
|||
if (currentItemIndex != this._lastReportedItemIndex) { |
|||
this._lastReportedItemIndex = currentItemIndex; |
|||
int trueIndex = this.widget.childDelegate.trueIndexOf(currentItemIndex); |
|||
this.widget.onSelectedItemChanged(trueIndex); |
|||
} |
|||
} |
|||
|
|||
return false; |
|||
}, |
|||
child: new _FixedExtentScrollable( |
|||
controller: this.scrollController, |
|||
physics: this.widget.physics, |
|||
itemExtent: this.widget.itemExtent, |
|||
viewportBuilder: (BuildContext _context, ViewportOffset _offset) => { |
|||
return new ListWheelViewport( |
|||
diameterRatio: this.widget.diameterRatio, |
|||
perspective: this.widget.perspective, |
|||
offAxisFraction: this.widget.offAxisFraction, |
|||
useMagnifier: this.widget.useMagnifier, |
|||
magnification: this.widget.magnification, |
|||
itemExtent: this.widget.itemExtent, |
|||
clipToSize: this.widget.clipToSize, |
|||
renderChildrenOutsideViewport: this.widget.renderChildrenOutsideViewport, |
|||
offset: _offset, |
|||
childDelegate: this.widget.childDelegate |
|||
); |
|||
} |
|||
) |
|||
); |
|||
} |
|||
} |
|||
|
|||
public class ListWheelElement : RenderObjectElement, IListWheelChildManager { |
|||
public ListWheelElement(ListWheelViewport widget) : base(widget) { } |
|||
|
|||
public new ListWheelViewport widget { |
|||
get { return (ListWheelViewport) base.widget; } |
|||
} |
|||
|
|||
public new RenderListWheelViewport renderObject { |
|||
get { return (RenderListWheelViewport) base.renderObject; } |
|||
} |
|||
|
|||
|
|||
readonly Dictionary<int, Widget> _childWidgets = new Dictionary<int, Widget>(); |
|||
|
|||
readonly SplayTree<int, Element> _childElements = new SplayTree<int, Element>(); |
|||
|
|||
public override void update(Widget newWidget) { |
|||
ListWheelViewport oldWidget = this.widget; |
|||
base.update(newWidget); |
|||
ListWheelChildDelegate newDelegate = ((ListWheelViewport) newWidget).childDelegate; |
|||
ListWheelChildDelegate oldDelegate = oldWidget.childDelegate; |
|||
if (newDelegate != oldDelegate && |
|||
(newDelegate.GetType() != oldDelegate.GetType() || newDelegate.shouldRebuild(oldDelegate))) { |
|||
this.performRebuild(); |
|||
} |
|||
} |
|||
|
|||
public int? childCount { |
|||
get { return this.widget.childDelegate.estimatedChildCount; } |
|||
} |
|||
|
|||
protected override void performRebuild() { |
|||
this._childWidgets.Clear(); |
|||
base.performRebuild(); |
|||
if (this._childElements.isEmpty()) { |
|||
return; |
|||
} |
|||
|
|||
int firstIndex = this._childElements.First().Key; |
|||
int lastIndex = this._childElements.Last().Key; |
|||
|
|||
for (int index = firstIndex; index <= lastIndex; ++index) { |
|||
Element newChild = this.updateChild(this._childElements[index], this.retrieveWidget(index), index); |
|||
if (newChild != null) { |
|||
this._childElements[index] = newChild; |
|||
} |
|||
else { |
|||
this._childElements.Remove(index); |
|||
} |
|||
} |
|||
} |
|||
|
|||
Widget retrieveWidget(int index) { |
|||
return this._childWidgets.putIfAbsent(index, |
|||
() => { return this.widget.childDelegate.build(this, index); }); |
|||
} |
|||
|
|||
public bool childExistsAt(int index) { |
|||
return this.retrieveWidget(index) != null; |
|||
} |
|||
|
|||
public void createChild(int index, RenderBox after) { |
|||
this.owner.buildScope(this, () => { |
|||
bool insertFirst = after == null; |
|||
D.assert(insertFirst || this._childElements[index - 1] != null); |
|||
// Debug.Log($"{index}: {this._childElements.getOrDefault(index)}");
|
|||
|
|||
Element newChild = this.updateChild(this._childElements.getOrDefault(index), this.retrieveWidget(index), |
|||
index); |
|||
|
|||
// Debug.Log(newChild);
|
|||
if (newChild != null) { |
|||
this._childElements[index] = newChild; |
|||
} |
|||
else { |
|||
this._childElements.Remove(index); |
|||
} |
|||
}); |
|||
} |
|||
|
|||
public void removeChild(RenderBox child) { |
|||
int index = this.renderObject.indexOf(child); |
|||
this.owner.buildScope(this, () => { |
|||
D.assert(this._childElements.ContainsKey(index)); |
|||
Element result = this.updateChild(this._childElements[index], null, index); |
|||
D.assert(result == null); |
|||
this._childElements.Remove(index); |
|||
D.assert(!this._childElements.ContainsKey(index)); |
|||
}); |
|||
} |
|||
|
|||
protected override Element updateChild(Element child, Widget newWidget, object newSlot) { |
|||
ListWheelParentData oldParentData = (ListWheelParentData) child?.renderObject?.parentData; |
|||
Element newChild = base.updateChild(child, newWidget, newSlot); |
|||
ListWheelParentData newParentData = (ListWheelParentData) newChild?.renderObject?.parentData; |
|||
if (newParentData != null) { |
|||
newParentData.index = (int) newSlot; |
|||
if (oldParentData != null) { |
|||
newParentData.offset = oldParentData.offset; |
|||
} |
|||
} |
|||
|
|||
return newChild; |
|||
} |
|||
|
|||
protected override void insertChildRenderObject(RenderObject child, object slot) { |
|||
RenderListWheelViewport renderObject = this.renderObject; |
|||
D.assert(renderObject.debugValidateChild(child)); |
|||
|
|||
renderObject.insert((RenderBox) child, |
|||
(RenderBox) this._childElements.getOrDefault((int) slot - 1)?.renderObject); |
|||
// Debug.Log($"insert: {this._childElements.getOrDefault((int) slot - 1)}");
|
|||
|
|||
|
|||
D.assert(renderObject == this.renderObject); |
|||
} |
|||
|
|||
protected override void moveChildRenderObject(RenderObject child, dynamic slot) { |
|||
const string moveChildRenderObjectErrorMessage = |
|||
"Currently we maintain the list in contiguous increasing order, so " + |
|||
"moving children around is not allowed."; |
|||
D.assert(false, () => moveChildRenderObjectErrorMessage); |
|||
} |
|||
|
|||
protected override void removeChildRenderObject(RenderObject child) { |
|||
D.assert(child.parent == this.renderObject); |
|||
this.renderObject.remove((RenderBox) child); |
|||
} |
|||
|
|||
public override void visitChildren(ElementVisitor visitor) { |
|||
foreach (var item in this._childElements) { |
|||
visitor(item.Value); |
|||
} |
|||
} |
|||
|
|||
protected override void forgetChild(Element child) { |
|||
this._childElements.Remove((int) (child.slot)); |
|||
} |
|||
} |
|||
|
|||
public class ListWheelViewport : RenderObjectWidget { |
|||
public ListWheelViewport( |
|||
float itemExtent, |
|||
ViewportOffset offset, |
|||
ListWheelChildDelegate childDelegate, |
|||
Key key = null, |
|||
float diameterRatio = RenderListWheelViewport.defaultDiameterRatio, |
|||
float perspective = RenderListWheelViewport.defaultPerspective, |
|||
float offAxisFraction = 0.0f, |
|||
bool useMagnifier = false, |
|||
float magnification = 1.0f, |
|||
bool clipToSize = true, |
|||
bool renderChildrenOutsideViewport = false |
|||
) : base(key: key) { |
|||
D.assert(childDelegate != null); |
|||
D.assert(offset != null); |
|||
D.assert(diameterRatio > 0, () => RenderListWheelViewport.diameterRatioZeroMessage); |
|||
D.assert(perspective > 0); |
|||
D.assert(perspective <= 0.01, () => RenderListWheelViewport.perspectiveTooHighMessage); |
|||
D.assert(itemExtent > 0); |
|||
D.assert( |
|||
!renderChildrenOutsideViewport || !clipToSize, |
|||
() => RenderListWheelViewport.clipToSizeAndRenderChildrenOutsideViewportConflict |
|||
); |
|||
|
|||
this.itemExtent = itemExtent; |
|||
this.offset = offset; |
|||
this.childDelegate = childDelegate; |
|||
this.diameterRatio = diameterRatio; |
|||
this.perspective = perspective; |
|||
this.offAxisFraction = offAxisFraction; |
|||
this.useMagnifier = useMagnifier; |
|||
this.magnification = magnification; |
|||
this.clipToSize = clipToSize; |
|||
this.renderChildrenOutsideViewport = renderChildrenOutsideViewport; |
|||
} |
|||
|
|||
public readonly float diameterRatio; |
|||
public readonly float perspective; |
|||
public readonly float offAxisFraction; |
|||
public readonly bool useMagnifier; |
|||
public readonly float magnification; |
|||
public readonly float itemExtent; |
|||
public readonly bool clipToSize; |
|||
public readonly bool renderChildrenOutsideViewport; |
|||
public readonly ViewportOffset offset; |
|||
public readonly ListWheelChildDelegate childDelegate; |
|||
|
|||
public override Element createElement() { |
|||
return new ListWheelElement(this); |
|||
} |
|||
|
|||
public override RenderObject createRenderObject(BuildContext context) { |
|||
ListWheelElement childManager = (ListWheelElement) context; |
|||
return new RenderListWheelViewport( |
|||
childManager: childManager, |
|||
offset: this.offset, |
|||
diameterRatio: this.diameterRatio, |
|||
perspective: this.perspective, |
|||
offAxisFraction: this.offAxisFraction, |
|||
useMagnifier: this.useMagnifier, |
|||
magnification: this.magnification, |
|||
itemExtent: this.itemExtent, |
|||
clipToSize: this.clipToSize, |
|||
renderChildrenOutsideViewport: this.renderChildrenOutsideViewport |
|||
); |
|||
} |
|||
|
|||
public override void updateRenderObject(BuildContext context, RenderObject renderObject) { |
|||
var viewport = (RenderListWheelViewport) renderObject; |
|||
viewport.offset = this.offset; |
|||
viewport.diameterRatio = this.diameterRatio; |
|||
viewport.perspective = this.perspective; |
|||
viewport.offAxisFraction = this.offAxisFraction; |
|||
viewport.useMagnifier = this.useMagnifier; |
|||
viewport.magnification = this.magnification; |
|||
viewport.itemExtent = this.itemExtent; |
|||
viewport.clipToSize = this.clipToSize; |
|||
viewport.renderChildrenOutsideViewport = this.renderChildrenOutsideViewport; |
|||
} |
|||
} |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: 5f33e2b8a13bf4308b91f226530921e3 |
|||
MonoImporter: |
|||
externalObjects: {} |
|||
serializedVersion: 2 |
|||
defaultReferences: [] |
|||
executionOrder: 0 |
|||
icon: {instanceID: 0} |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
using System; |
|||
using System.Collections.Generic; |
|||
using Unity.UIWidgets.cupertino; |
|||
using Unity.UIWidgets.painting; |
|||
using Unity.UIWidgets.rendering; |
|||
using Unity.UIWidgets.service; |
|||
using Unity.UIWidgets.ui; |
|||
using Unity.UIWidgets.widgets; |
|||
|
|||
namespace UIWidgetsGallery.gallery { |
|||
class CupertinoPickerDemoUtils { |
|||
public const float _kPickerSheetHeight = 216.0f; |
|||
public const float _kPickerItemHeight = 32.0f; |
|||
} |
|||
|
|||
class CupertinoPickerDemo : StatefulWidget { |
|||
public const string routeName = "/cupertino/picker"; |
|||
|
|||
public override State createState() { |
|||
return new _CupertinoPickerDemoState(); |
|||
} |
|||
} |
|||
|
|||
class _CupertinoPickerDemoState : State<CupertinoPickerDemo> { |
|||
int _selectedColorIndex = 0; |
|||
TimeSpan timer = new TimeSpan(); |
|||
|
|||
// Value that is shown in the date picker in date mode.
|
|||
DateTime date = DateTime.Now; |
|||
|
|||
// Value that is shown in the date picker in time mode.
|
|||
DateTime time = DateTime.Now; |
|||
|
|||
// Value that is shown in the date picker in dateAndTime mode.
|
|||
DateTime dateTime = DateTime.Now; |
|||
|
|||
Widget _buildMenu(List<Widget> children) { |
|||
return new Container( |
|||
decoration: new BoxDecoration( |
|||
color: CupertinoTheme.of(this.context).scaffoldBackgroundColor, |
|||
border: new Border( |
|||
top: new BorderSide(color: new Color(0xFFBCBBC1), width: 0.0f), |
|||
bottom: new BorderSide(color: new Color(0xFFBCBBC1), width: 0.0f) |
|||
) |
|||
), |
|||
height: 44.0f, |
|||
child: new Padding( |
|||
padding: EdgeInsets.symmetric(horizontal: 16.0f), |
|||
child: new SafeArea( |
|||
top: false, |
|||
bottom: false, |
|||
child: new Row( |
|||
mainAxisAlignment: MainAxisAlignment.spaceBetween, |
|||
children: children |
|||
) |
|||
) |
|||
) |
|||
); |
|||
} |
|||
|
|||
Widget _buildBottomPicker(Widget picker) { |
|||
return new Container( |
|||
height: CupertinoPickerDemoUtils._kPickerSheetHeight, |
|||
padding: EdgeInsets.only(top: 6.0f), |
|||
color: CupertinoColors.white, |
|||
child: new DefaultTextStyle( |
|||
style: new TextStyle( |
|||
color: CupertinoColors.black, |
|||
fontSize: 22.0f |
|||
), |
|||
child: new GestureDetector( |
|||
// Blocks taps from propagating to the modal sheet and popping.
|
|||
onTap: () => { }, |
|||
child: new SafeArea( |
|||
top: false, |
|||
child: picker |
|||
) |
|||
) |
|||
) |
|||
); |
|||
} |
|||
|
|||
Widget _buildColorPicker(BuildContext context) { |
|||
FixedExtentScrollController scrollController = |
|||
new FixedExtentScrollController(initialItem: this._selectedColorIndex); |
|||
|
|||
List<Widget> generateList() { |
|||
var list = new List<Widget>(); |
|||
foreach (var item in CupertinoNavigationDemoUtils.coolColorNames) { |
|||
list.Add(new Center(child: |
|||
new Text(item) |
|||
)); |
|||
} |
|||
|
|||
return list; |
|||
} |
|||
|
|||
|
|||
return new GestureDetector( |
|||
onTap: () => { |
|||
CupertinoRouteUtils.showCupertinoModalPopup( |
|||
context: context, |
|||
builder: (BuildContext _context) => { |
|||
return this._buildBottomPicker( |
|||
new CupertinoPicker( |
|||
scrollController: scrollController, |
|||
itemExtent: CupertinoPickerDemoUtils._kPickerItemHeight, |
|||
backgroundColor: CupertinoColors.white, |
|||
onSelectedItemChanged: (int index) => { |
|||
this.setState(() => this._selectedColorIndex = index); |
|||
}, |
|||
children: generateList() |
|||
) |
|||
); |
|||
} |
|||
); |
|||
}, |
|||
child: this._buildMenu(new List<Widget> { |
|||
new Text("Favorite Color"), |
|||
new Text( |
|||
CupertinoNavigationDemoUtils.coolColorNames[this._selectedColorIndex], |
|||
style: new TextStyle( |
|||
color: CupertinoColors.inactiveGray |
|||
) |
|||
) |
|||
} |
|||
) |
|||
); |
|||
} |
|||
|
|||
Widget _buildCountdownTimerPicker(BuildContext context) { |
|||
return new GestureDetector( |
|||
onTap: () => { |
|||
CupertinoRouteUtils.showCupertinoModalPopup( |
|||
context: context, |
|||
builder: (BuildContext _context) => { |
|||
return this._buildBottomPicker( |
|||
new CupertinoTimerPicker( |
|||
initialTimerDuration: this.timer, |
|||
onTimerDurationChanged: (TimeSpan newTimer) => { |
|||
this.setState(() => this.timer = newTimer); |
|||
} |
|||
) |
|||
); |
|||
} |
|||
); |
|||
}, |
|||
child: this._buildMenu(new List<Widget> { |
|||
new Text("Countdown Timer"), |
|||
new Text( |
|||
$"{this.timer.Hours}:" + |
|||
$"{(this.timer.Minutes % 60).ToString("00")}:" + |
|||
$"{(this.timer.Seconds % 60).ToString("00")}", |
|||
style: new TextStyle(color: CupertinoColors.inactiveGray) |
|||
) |
|||
} |
|||
) |
|||
); |
|||
} |
|||
|
|||
Widget _buildDatePicker(BuildContext context) { |
|||
return new GestureDetector( |
|||
onTap: () => { |
|||
CupertinoRouteUtils.showCupertinoModalPopup( |
|||
context: context, |
|||
builder: (BuildContext _context) => { |
|||
return this._buildBottomPicker( |
|||
new CupertinoDatePicker( |
|||
mode: CupertinoDatePickerMode.date, |
|||
initialDateTime: this.date, |
|||
onDateTimeChanged: (DateTime newDateTime) => { |
|||
this.setState(() => this.date = newDateTime); |
|||
} |
|||
) |
|||
); |
|||
} |
|||
); |
|||
}, |
|||
child: this._buildMenu(new List<Widget> { |
|||
new Text("Date"), |
|||
new Text( |
|||
this.date.ToString("MMMM dd, yyyy"), |
|||
style: new TextStyle(color: CupertinoColors.inactiveGray) |
|||
) |
|||
} |
|||
) |
|||
); |
|||
} |
|||
|
|||
Widget _buildTimePicker(BuildContext context) { |
|||
return new GestureDetector( |
|||
onTap: () => { |
|||
CupertinoRouteUtils.showCupertinoModalPopup( |
|||
context: context, |
|||
builder: (BuildContext _context) => { |
|||
return this._buildBottomPicker( |
|||
new CupertinoDatePicker( |
|||
mode: CupertinoDatePickerMode.time, |
|||
initialDateTime: this.time, |
|||
onDateTimeChanged: (DateTime newDateTime) => { |
|||
this.setState(() => this.time = newDateTime); |
|||
} |
|||
) |
|||
); |
|||
} |
|||
); |
|||
}, |
|||
child: this._buildMenu(new List<Widget> { |
|||
new Text("Time"), |
|||
new Text( |
|||
this.time.ToString("h:mm tt"), |
|||
style: new TextStyle(color: CupertinoColors.inactiveGray) |
|||
) |
|||
} |
|||
) |
|||
); |
|||
} |
|||
|
|||
Widget _buildDateAndTimePicker(BuildContext context) { |
|||
return new GestureDetector( |
|||
onTap: () => { |
|||
CupertinoRouteUtils.showCupertinoModalPopup( |
|||
context: context, |
|||
builder: (BuildContext _context) => { |
|||
return this._buildBottomPicker( |
|||
new CupertinoDatePicker( |
|||
mode: CupertinoDatePickerMode.dateAndTime, |
|||
initialDateTime: this.dateTime, |
|||
onDateTimeChanged: (DateTime newDateTime) => { |
|||
this.setState(() => this.dateTime = newDateTime); |
|||
} |
|||
) |
|||
); |
|||
} |
|||
); |
|||
}, |
|||
child: this._buildMenu(new List<Widget> { |
|||
new Text("Date and Time"), |
|||
new Text( |
|||
this.dateTime.ToString("MMMM dd, yyyy h:mm tt"), |
|||
style: new TextStyle(color: CupertinoColors.inactiveGray) |
|||
) |
|||
} |
|||
) |
|||
); |
|||
} |
|||
|
|||
public override Widget build(BuildContext context) { |
|||
return new CupertinoPageScaffold( |
|||
navigationBar: new CupertinoNavigationBar( |
|||
middle: new Text("Picker"), |
|||
// We"re specifying a back label here because the previous page is a
|
|||
// Material page. CupertinoPageRoutes could auto-populate these back
|
|||
// labels.
|
|||
previousPageTitle: "Cupertino", |
|||
trailing: new CupertinoDemoDocumentationButton(CupertinoPickerDemo.routeName) |
|||
), |
|||
child: new DefaultTextStyle( |
|||
style: CupertinoTheme.of(context).textTheme.textStyle, |
|||
child: new DecoratedBox( |
|||
decoration: new BoxDecoration( |
|||
color: CupertinoTheme.of(context).brightness == Brightness.light |
|||
? CupertinoColors.extraLightBackgroundGray |
|||
: CupertinoColors.darkBackgroundGray |
|||
), |
|||
child: new SafeArea( |
|||
child: new ListView( |
|||
children: new List<Widget> { |
|||
new Padding(padding: EdgeInsets.only(top: 32.0f)), |
|||
this._buildColorPicker(context), |
|||
this._buildCountdownTimerPicker(context), |
|||
this._buildDatePicker(context), |
|||
this._buildTimePicker(context), |
|||
this._buildDateAndTimePicker(context) |
|||
} |
|||
) |
|||
) |
|||
) |
|||
) |
|||
); |
|||
} |
|||
} |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: 6cb09763e9a60447490569afa586f063 |
|||
MonoImporter: |
|||
externalObjects: {} |
|||
serializedVersion: 2 |
|||
defaultReferences: [] |
|||
executionOrder: 0 |
|||
icon: {instanceID: 0} |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
撰写
预览
正在加载...
取消
保存
Reference in new issue