GitHub
5 年前
当前提交
41137c2c
共有 33 个文件被更改,包括 1777 次插入 和 540 次删除
-
4Runtime/Plugins/platform/ios/UIWidgetsTextInputPlugin.mm
-
1Runtime/cupertino/button.cs
-
2Runtime/cupertino/slider.cs
-
7Runtime/editor/window_config.cs
-
4Runtime/material/input_decorator.cs
-
1Runtime/painting/gradient.cs
-
2Runtime/painting/text_painter.cs
-
32Runtime/painting/text_style.cs
-
34Runtime/rendering/editable.cs
-
8Runtime/rendering/shifted_box.cs
-
8Runtime/ui/geometry.cs
-
2Runtime/ui/painting/draw_cmd.cs
-
8Runtime/ui/painting/path.cs
-
53Runtime/ui/painting/picture.cs
-
59Runtime/ui/renderer/cmdbufferCanvas/rendering/canvas_impl.cs
-
16Runtime/ui/renderer/common/geometry/path/path.cs
-
4Runtime/ui/renderer/common/geometry/path/path_cache.cs
-
8Runtime/ui/renderer/common/geometry/rect.cs
-
58Runtime/ui/renderer/common/picture.cs
-
31Runtime/ui/text.cs
-
491Runtime/ui/txt/paragraph.cs
-
1Runtime/widgets/list_wheel_scroll_view.cs
-
2Runtime/widgets/pages.cs
-
5Runtime/widgets/routes.cs
-
1Runtime/widgets/sliver.cs
-
130Runtime/cupertino/activity_indicator.cs
-
11Runtime/cupertino/activity_indicator.cs.meta
-
524Runtime/external/RTree.cs
-
11Runtime/external/RTree.cs.meta
-
493Runtime/external/SplayTree.cs
-
11Runtime/external/SplayTree.cs.meta
-
284Runtime/material/search.cs
-
11Runtime/material/search.cs.meta
|
|||
using System; |
|||
using Unity.UIWidgets.animation; |
|||
using Unity.UIWidgets.foundation; |
|||
using Unity.UIWidgets.ui; |
|||
using Unity.UIWidgets.widgets; |
|||
using UnityEngine; |
|||
using Canvas = Unity.UIWidgets.ui.Canvas; |
|||
using Color = Unity.UIWidgets.ui.Color; |
|||
|
|||
namespace Unity.UIWidgets.cupertino { |
|||
static class CupertinoActivityIndicatorUtils { |
|||
public const float _kDefaultIndicatorRadius = 10.0f; |
|||
public const float _kTwoPI = Mathf.PI * 2.0f; |
|||
public const int _kTickCount = 12; |
|||
public const int _kHalfTickCount = _kTickCount / 2; |
|||
public static readonly Color _kTickColor = CupertinoColors.lightBackgroundGray; |
|||
public static readonly Color _kActiveTickColor = new Color(0xFF9D9D9D); |
|||
} |
|||
|
|||
public class CupertinoActivityIndicator : StatefulWidget { |
|||
public CupertinoActivityIndicator( |
|||
Key key = null, |
|||
bool animating = true, |
|||
float radius = CupertinoActivityIndicatorUtils._kDefaultIndicatorRadius |
|||
) : base(key: key) { |
|||
D.assert(radius > 0); |
|||
this.animating = animating; |
|||
this.radius = radius; |
|||
} |
|||
|
|||
public readonly bool animating; |
|||
public readonly float radius; |
|||
|
|||
public override State createState() { |
|||
return new _CupertinoActivityIndicatorState(); |
|||
} |
|||
} |
|||
|
|||
class _CupertinoActivityIndicatorState : TickerProviderStateMixin<CupertinoActivityIndicator> { |
|||
AnimationController _controller; |
|||
|
|||
public override void initState() { |
|||
base.initState(); |
|||
this._controller = new AnimationController( |
|||
duration: TimeSpan.FromSeconds(1), |
|||
vsync: this |
|||
); |
|||
|
|||
if (this.widget.animating) { |
|||
this._controller.repeat(); |
|||
} |
|||
} |
|||
|
|||
public override void didUpdateWidget(StatefulWidget oldWidget) { |
|||
base.didUpdateWidget(oldWidget: oldWidget); |
|||
if (oldWidget is CupertinoActivityIndicator _oldWidget) { |
|||
if (this.widget.animating != _oldWidget.animating) { |
|||
if (this.widget.animating) { |
|||
this._controller.repeat(); |
|||
} |
|||
else { |
|||
this._controller.stop(); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
public override void dispose() { |
|||
this._controller.dispose(); |
|||
base.dispose(); |
|||
} |
|||
|
|||
public override Widget build(BuildContext context) { |
|||
return new SizedBox( |
|||
height: this.widget.radius * 2, |
|||
width: this.widget.radius * 2, |
|||
child: new CustomPaint( |
|||
painter: new _CupertinoActivityIndicatorPainter( |
|||
position: this._controller, |
|||
radius: this.widget.radius |
|||
) |
|||
) |
|||
); |
|||
} |
|||
} |
|||
|
|||
class _CupertinoActivityIndicatorPainter : AbstractCustomPainter { |
|||
public _CupertinoActivityIndicatorPainter( |
|||
Animation<float> position, |
|||
float radius |
|||
) : base(repaint: position) { |
|||
this.tickFundamentalRRect = RRect.fromLTRBXY( |
|||
left: -radius, |
|||
top: 1.0f * radius / CupertinoActivityIndicatorUtils._kDefaultIndicatorRadius, |
|||
right: -radius / 2.0f, |
|||
bottom: -1.0f * radius / CupertinoActivityIndicatorUtils._kDefaultIndicatorRadius, |
|||
radiusX: 1.0f, |
|||
radiusY: 1.0f |
|||
); |
|||
this.position = position; |
|||
} |
|||
|
|||
readonly Animation<float> position; |
|||
readonly RRect tickFundamentalRRect; |
|||
|
|||
public override void paint(Canvas canvas, Size size) { |
|||
Paint paint = new Paint(); |
|||
|
|||
canvas.save(); |
|||
canvas.translate(size.width / 2.0f, size.height / 2.0f); |
|||
|
|||
int activeTick = (CupertinoActivityIndicatorUtils._kTickCount * this.position.value).floor(); |
|||
|
|||
for (int i = 0; i < CupertinoActivityIndicatorUtils._kTickCount; ++i) { |
|||
float t = (((i + activeTick) % CupertinoActivityIndicatorUtils._kTickCount) / |
|||
CupertinoActivityIndicatorUtils._kHalfTickCount).clamp(0, 1); |
|||
paint.color = Color.lerp(a: CupertinoActivityIndicatorUtils._kActiveTickColor, |
|||
b: CupertinoActivityIndicatorUtils._kTickColor, t: t); |
|||
canvas.drawRRect(rect: this.tickFundamentalRRect, paint: paint); |
|||
canvas.rotate(-CupertinoActivityIndicatorUtils._kTwoPI / CupertinoActivityIndicatorUtils._kTickCount); |
|||
} |
|||
|
|||
canvas.restore(); |
|||
} |
|||
|
|||
public override bool shouldRepaint(CustomPainter oldPainter) { |
|||
return (oldPainter as _CupertinoActivityIndicatorPainter).position != this.position; |
|||
} |
|||
} |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: a08f265049c0646969c9b5adafa6916f |
|||
MonoImporter: |
|||
externalObjects: {} |
|||
serializedVersion: 2 |
|||
defaultReferences: [] |
|||
executionOrder: 0 |
|||
icon: {instanceID: 0} |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using Unity.UIWidgets.ui; |
|||
|
|||
namespace Unity.UIWidgets.Runtime.external |
|||
{ |
|||
public interface ISpatialData |
|||
{ |
|||
uiRect bounds { get; } |
|||
} |
|||
|
|||
public class IndexedRect : ISpatialData |
|||
{ |
|||
private uiRect _bounds; |
|||
|
|||
public uiRect bounds |
|||
{ |
|||
get { return _bounds; } |
|||
} |
|||
|
|||
public readonly int index; |
|||
|
|||
public IndexedRect(uiRect bounds, int index) |
|||
{ |
|||
this._bounds = bounds; |
|||
this.index = index; |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Non-generic class to produce instances of the generic class,
|
|||
/// optionally using type inference.
|
|||
/// </summary>
|
|||
public static class ProjectionComparer |
|||
{ |
|||
/// <summary>
|
|||
/// Creates an instance of ProjectionComparer using the specified projection.
|
|||
/// </summary>
|
|||
/// <typeparam name="TSource">Type parameter for the elements to be compared</typeparam>
|
|||
/// <typeparam name="TKey">Type parameter for the keys to be compared, after being projected from the elements</typeparam>
|
|||
/// <param name="projection">Projection to use when determining the key of an element</param>
|
|||
/// <returns>A comparer which will compare elements by projecting each element to its key, and comparing keys</returns>
|
|||
public static ProjectionComparer<TSource, TKey> Create<TSource, TKey>(Func<TSource, TKey> projection) |
|||
{ |
|||
return new ProjectionComparer<TSource, TKey>(projection); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Creates an instance of ProjectionComparer using the specified projection.
|
|||
/// The ignored parameter is solely present to aid type inference.
|
|||
/// </summary>
|
|||
/// <typeparam name="TSource">Type parameter for the elements to be compared</typeparam>
|
|||
/// <typeparam name="TKey">Type parameter for the keys to be compared, after being projected from the elements</typeparam>
|
|||
/// <param name="ignored">Value is ignored - type may be used by type inference</param>
|
|||
/// <param name="projection">Projection to use when determining the key of an element</param>
|
|||
/// <returns>A comparer which will compare elements by projecting each element to its key, and comparing keys</returns>
|
|||
public static ProjectionComparer<TSource, TKey> Create<TSource, TKey> |
|||
(TSource ignored, |
|||
Func<TSource, TKey> projection) |
|||
{ |
|||
return new ProjectionComparer<TSource, TKey>(projection); |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Class generic in the source only to produce instances of the
|
|||
/// doubly generic class, optionally using type inference.
|
|||
/// </summary>
|
|||
public static class ProjectionComparer<TSource> |
|||
{ |
|||
/// <summary>
|
|||
/// Creates an instance of ProjectionComparer using the specified projection.
|
|||
/// </summary>
|
|||
/// <typeparam name="TKey">Type parameter for the keys to be compared, after being projected from the elements</typeparam>
|
|||
/// <param name="projection">Projection to use when determining the key of an element</param>
|
|||
/// <returns>A comparer which will compare elements by projecting each element to its key, and comparing keys</returns>
|
|||
public static ProjectionComparer<TSource, TKey> Create<TKey>(Func<TSource, TKey> projection) |
|||
{ |
|||
return new ProjectionComparer<TSource, TKey>(projection); |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Comparer which projects each element of the comparison to a key, and then compares
|
|||
/// those keys using the specified (or default) comparer for the key type.
|
|||
/// </summary>
|
|||
/// <typeparam name="TSource">Type of elements which this comparer will be asked to compare</typeparam>
|
|||
/// <typeparam name="TKey">Type of the key projected from the element</typeparam>
|
|||
public class ProjectionComparer<TSource, TKey> : IComparer<TSource> |
|||
{ |
|||
private readonly IComparer<TKey> comparer; |
|||
private readonly Func<TSource, TKey> projection; |
|||
|
|||
/// <summary>
|
|||
/// Creates a new instance using the specified projection, which must not be null.
|
|||
/// The default comparer for the projected type is used.
|
|||
/// </summary>
|
|||
/// <param name="projection">Projection to use during comparisons</param>
|
|||
public ProjectionComparer(Func<TSource, TKey> projection) |
|||
: this(projection, null) |
|||
{ |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Creates a new instance using the specified projection, which must not be null.
|
|||
/// </summary>
|
|||
/// <param name="projection">Projection to use during comparisons</param>
|
|||
/// <param name="comparer">
|
|||
/// The comparer to use on the keys. May be null, in
|
|||
/// which case the default comparer will be used.
|
|||
/// </param>
|
|||
public ProjectionComparer(Func<TSource, TKey> projection, IComparer<TKey> comparer) |
|||
{ |
|||
this.comparer = comparer ?? Comparer<TKey>.Default; |
|||
this.projection = projection; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Compares x and y by projecting them to keys and then comparing the keys.
|
|||
/// Null values are not projected; they obey the
|
|||
/// standard comparer contract such that two null values are equal; any null value is
|
|||
/// less than any non-null value.
|
|||
/// </summary>
|
|||
public int Compare(TSource x, TSource y) |
|||
{ |
|||
// Don't want to project from nullity
|
|||
if (x == null && y == null) return 0; |
|||
if (x == null) return -1; |
|||
if (y == null) return 1; |
|||
return comparer.Compare(projection(x), projection(y)); |
|||
} |
|||
} |
|||
|
|||
public interface BBoxHierarchy<T> where T : ISpatialData |
|||
{ |
|||
IReadOnlyList<T> Search(in uiRect boundingBox); |
|||
void BulkLoad(IEnumerable<T> items); |
|||
|
|||
void Insert(T data); |
|||
|
|||
void Clear(); |
|||
} |
|||
|
|||
public class RTree<T> : BBoxHierarchy<T> where T : ISpatialData |
|||
{ |
|||
public class RTreeNode : ISpatialData |
|||
{ |
|||
internal readonly List<ISpatialData> children; |
|||
private uiRect _Rect; |
|||
|
|||
internal RTreeNode(List<ISpatialData> items, int height) |
|||
{ |
|||
Height = height; |
|||
children = items; |
|||
ResetRect(); |
|||
} |
|||
|
|||
public IReadOnlyList<ISpatialData> Children => children; |
|||
public int Height { get; } |
|||
public bool IsLeaf => Height == 1; |
|||
public uiRect bounds => _Rect; |
|||
|
|||
internal void Add(ISpatialData node) |
|||
{ |
|||
children.Add(node); |
|||
_Rect = bounds.expandToInclude(node.bounds); |
|||
} |
|||
|
|||
internal void Remove(ISpatialData node) |
|||
{ |
|||
children.Remove(node); |
|||
ResetRect(); |
|||
} |
|||
|
|||
internal void RemoveRange(int index, int count) |
|||
{ |
|||
children.RemoveRange(index, count); |
|||
ResetRect(); |
|||
} |
|||
|
|||
internal void ResetRect() |
|||
{ |
|||
_Rect = GetEnclosingRect(children); |
|||
} |
|||
} |
|||
#region Search
|
|||
|
|||
private List<T> DoSearch(in uiRect boundingBox) |
|||
{ |
|||
if (!uiRectHelper.overlaps(Root.bounds, boundingBox)) |
|||
return new List<T>(); |
|||
|
|||
var intersections = new List<T>(); |
|||
var queue = new Queue<RTreeNode>(); |
|||
queue.Enqueue(Root); |
|||
|
|||
while (queue.Count != 0) |
|||
{ |
|||
var item = queue.Dequeue(); |
|||
if (item.IsLeaf) |
|||
{ |
|||
foreach (var leafChildItem in item.children.Cast<T>()) |
|||
if (uiRectHelper.overlaps(leafChildItem.bounds, boundingBox)) |
|||
intersections.Add(leafChildItem); |
|||
} |
|||
else |
|||
{ |
|||
foreach (var child in item.children.Cast<RTreeNode>()) |
|||
if (uiRectHelper.overlaps(child.bounds, boundingBox)) |
|||
queue.Enqueue(child); |
|||
} |
|||
} |
|||
|
|||
return intersections; |
|||
} |
|||
|
|||
#endregion
|
|||
|
|||
private static uiRect GetEnclosingRect(IEnumerable<ISpatialData> items) |
|||
{ |
|||
var uiRect = uiRectHelper.zero; |
|||
foreach (var data in items) uiRect = uiRect.expandToInclude(data.bounds); |
|||
return uiRect; |
|||
} |
|||
|
|||
private List<T> GetAllChildren(List<T> list, RTreeNode n) |
|||
{ |
|||
if (n.IsLeaf) |
|||
list.AddRange( |
|||
n.children.Cast<T>()); |
|||
else |
|||
foreach (var node in n.children.Cast<RTreeNode>()) |
|||
GetAllChildren(list, node); |
|||
|
|||
return list; |
|||
} |
|||
|
|||
#region Sort Functions
|
|||
|
|||
private static readonly IComparer<ISpatialData> CompareMinX = |
|||
ProjectionComparer<ISpatialData>.Create(d => d.bounds.left); |
|||
|
|||
private static readonly IComparer<ISpatialData> CompareMinY = |
|||
ProjectionComparer<ISpatialData>.Create(d => d.bounds.top); |
|||
|
|||
#endregion
|
|||
|
|||
#region Insert
|
|||
|
|||
private List<RTreeNode> FindCoveringArea(in uiRect area, int depth) |
|||
{ |
|||
var path = new List<RTreeNode>(); |
|||
var node = Root; |
|||
var _area = area; //FIX CS1628
|
|||
|
|||
while (true) |
|||
{ |
|||
path.Add(node); |
|||
if (node.IsLeaf || path.Count == depth) return path; |
|||
|
|||
node = node.children |
|||
.Select(c => new |
|||
{EnlargedArea = c.bounds.expandToInclude(_area).area, c.bounds.area, Node = c as RTreeNode}) |
|||
.OrderBy(x => x.EnlargedArea) |
|||
.ThenBy(x => x.area) |
|||
.Select(x => x.Node) |
|||
.First(); |
|||
} |
|||
} |
|||
|
|||
private void Insert(ISpatialData data, int depth) |
|||
{ |
|||
var path = FindCoveringArea(data.bounds, depth); |
|||
|
|||
var insertNode = path.Last(); |
|||
insertNode.Add(data); |
|||
|
|||
while (--depth >= 0) |
|||
if (path[depth].children.Count > maxEntries) |
|||
{ |
|||
var newNode = SplitNode(path[depth]); |
|||
if (depth == 0) |
|||
SplitRoot(newNode); |
|||
else |
|||
path[depth - 1].Add(newNode); |
|||
} |
|||
else |
|||
{ |
|||
path[depth].ResetRect(); |
|||
} |
|||
} |
|||
|
|||
#region SplitNode
|
|||
|
|||
private void SplitRoot(RTreeNode newRTreeNode) |
|||
{ |
|||
Root = new RTreeNode(new List<ISpatialData> {Root, newRTreeNode}, Root.Height + 1); |
|||
} |
|||
|
|||
private RTreeNode SplitNode(RTreeNode rTreeNode) |
|||
{ |
|||
SortChildren(rTreeNode); |
|||
|
|||
var splitPoint = GetBestSplitIndex(rTreeNode.children); |
|||
var newChildren = rTreeNode.children.Skip(splitPoint).ToList(); |
|||
rTreeNode.RemoveRange(splitPoint, rTreeNode.children.Count - splitPoint); |
|||
return new RTreeNode(newChildren, rTreeNode.Height); |
|||
} |
|||
|
|||
#region SortChildren
|
|||
|
|||
private void SortChildren(RTreeNode rTreeNode) |
|||
{ |
|||
rTreeNode.children.Sort(CompareMinX); |
|||
var splitsByX = GetPotentialSplitMargins(rTreeNode.children); |
|||
rTreeNode.children.Sort(CompareMinY); |
|||
var splitsByY = GetPotentialSplitMargins(rTreeNode.children); |
|||
|
|||
if (splitsByX < splitsByY) |
|||
rTreeNode.children.Sort(CompareMinX); |
|||
} |
|||
|
|||
private float GetPotentialSplitMargins(List<ISpatialData> children) |
|||
{ |
|||
return GetPotentialEnclosingMargins(children) + |
|||
GetPotentialEnclosingMargins(children.AsEnumerable().Reverse().ToList()); |
|||
} |
|||
|
|||
private float GetPotentialEnclosingMargins(List<ISpatialData> children) |
|||
{ |
|||
var uiRect = uiRectHelper.zero; |
|||
var i = 0; |
|||
for (; i < minEntries; i++) uiRect = uiRect.expandToInclude(children[i].bounds); |
|||
|
|||
var totalMargin = uiRect.margin; |
|||
for (; i < children.Count - minEntries; i++) |
|||
{ |
|||
uiRect = uiRect.expandToInclude(children[i].bounds); |
|||
totalMargin += uiRect.margin; |
|||
} |
|||
|
|||
return totalMargin; |
|||
} |
|||
|
|||
#endregion
|
|||
|
|||
private int GetBestSplitIndex(List<ISpatialData> children) |
|||
{ |
|||
return Enumerable.Range(minEntries, children.Count - minEntries) |
|||
.Select(i => |
|||
{ |
|||
var leftRect = GetEnclosingRect(children.Take(i)); |
|||
var rightRect = GetEnclosingRect(children.Skip(i)); |
|||
|
|||
var overlap = leftRect.intersect(rightRect).area; |
|||
var totalArea = leftRect.area + rightRect.area; |
|||
return new {i, overlap, totalArea}; |
|||
}) |
|||
.OrderBy(x => x.overlap) |
|||
.ThenBy(x => x.totalArea) |
|||
.Select(x => x.i) |
|||
.First(); |
|||
} |
|||
|
|||
#endregion
|
|||
|
|||
#endregion
|
|||
|
|||
#region BuildTree
|
|||
|
|||
private RTreeNode BuildTree(List<ISpatialData> data) |
|||
{ |
|||
var treeHeight = GetDepth(data.Count); |
|||
var rootMaxEntries = (int) Math.Ceiling(data.Count / Math.Pow(maxEntries, treeHeight - 1)); |
|||
return BuildNodes(data, 0, data.Count - 1, treeHeight, rootMaxEntries); |
|||
} |
|||
|
|||
private int GetDepth(int numNodes) |
|||
{ |
|||
return (int) Math.Ceiling(Math.Log(numNodes) / Math.Log(maxEntries)); |
|||
} |
|||
|
|||
private RTreeNode BuildNodes(List<ISpatialData> data, int left, int right, int height, int maxEntries) |
|||
{ |
|||
var num = right - left + 1; |
|||
if (num <= maxEntries) |
|||
return height == 1 |
|||
? new RTreeNode(data.GetRange(left, num), height) |
|||
: new RTreeNode( |
|||
new List<ISpatialData> |
|||
{ |
|||
BuildNodes(data, left, right, height - 1, this.maxEntries) |
|||
}, |
|||
height); |
|||
|
|||
data.Sort(left, num, CompareMinX); |
|||
|
|||
var nodeSize = (num + (maxEntries - 1)) / maxEntries; |
|||
var subSortLength = nodeSize * (int) Math.Ceiling(Math.Sqrt(maxEntries)); |
|||
|
|||
var children = new List<ISpatialData>(maxEntries); |
|||
for (var subCounter = left; subCounter <= right; subCounter += subSortLength) |
|||
{ |
|||
var subRight = Math.Min(subCounter + subSortLength - 1, right); |
|||
data.Sort(subCounter, subRight - subCounter + 1, CompareMinY); |
|||
|
|||
for (var nodeCounter = subCounter; nodeCounter <= subRight; nodeCounter += nodeSize) |
|||
children.Add( |
|||
BuildNodes( |
|||
data, |
|||
nodeCounter, |
|||
Math.Min(nodeCounter + nodeSize - 1, subRight), |
|||
height - 1, |
|||
this.maxEntries)); |
|||
} |
|||
|
|||
return new RTreeNode(children, height); |
|||
} |
|||
|
|||
#endregion
|
|||
private const int DefaultMaxEntries = 9; |
|||
private const int MinimumMaxEntries = 4; |
|||
private const int MinimumMinEntries = 2; |
|||
private const float DefaultFillFactor = 0.4f; |
|||
|
|||
private readonly EqualityComparer<T> comparer; |
|||
private readonly int maxEntries; |
|||
private readonly int minEntries; |
|||
|
|||
public RTree() : this(DefaultMaxEntries) |
|||
{ |
|||
} |
|||
|
|||
public RTree(int maxEntries) |
|||
: this(maxEntries, EqualityComparer<T>.Default) |
|||
{ |
|||
} |
|||
|
|||
public RTree(int maxEntries, EqualityComparer<T> comparer) |
|||
{ |
|||
this.comparer = comparer; |
|||
this.maxEntries = Math.Max(MinimumMaxEntries, maxEntries); |
|||
minEntries = Math.Max(MinimumMinEntries, (int) Math.Ceiling(this.maxEntries * DefaultFillFactor)); |
|||
|
|||
Clear(); |
|||
} |
|||
|
|||
public RTreeNode Root { get; private set; } |
|||
public uiRect uiRect => Root.bounds; |
|||
|
|||
public int Count { get; private set; } |
|||
|
|||
public void Clear() |
|||
{ |
|||
Root = new RTreeNode(new List<ISpatialData>(), 1); |
|||
Count = 0; |
|||
} |
|||
|
|||
public IReadOnlyList<T> Search() |
|||
{ |
|||
return GetAllChildren(new List<T>(), Root); |
|||
} |
|||
|
|||
public IReadOnlyList<T> Search(in uiRect boundingBox) |
|||
{ |
|||
return DoSearch(boundingBox); |
|||
} |
|||
|
|||
public void Insert(T item) |
|||
{ |
|||
Insert(item, Root.Height); |
|||
Count++; |
|||
} |
|||
|
|||
public void BulkLoad(IEnumerable<T> items) |
|||
{ |
|||
var data = items.Cast<ISpatialData>().ToList(); |
|||
if (data.Count == 0) return; |
|||
|
|||
if (Root.IsLeaf && |
|||
Root.children.Count + data.Count < maxEntries) |
|||
{ |
|||
foreach (var i in data) |
|||
Insert((T) i); |
|||
return; |
|||
} |
|||
|
|||
if (data.Count < minEntries) |
|||
{ |
|||
foreach (var i in data) |
|||
Insert((T) i); |
|||
return; |
|||
} |
|||
|
|||
var dataRoot = BuildTree(data); |
|||
Count += data.Count; |
|||
|
|||
if (Root.children.Count == 0) |
|||
{ |
|||
Root = dataRoot; |
|||
} |
|||
else if (Root.Height == dataRoot.Height) |
|||
{ |
|||
if (Root.children.Count + dataRoot.children.Count <= maxEntries) |
|||
foreach (var isd in dataRoot.children) |
|||
Root.Add(isd); |
|||
else |
|||
SplitRoot(dataRoot); |
|||
} |
|||
else |
|||
{ |
|||
if (Root.Height < dataRoot.Height) |
|||
{ |
|||
var tmp = Root; |
|||
Root = dataRoot; |
|||
dataRoot = tmp; |
|||
} |
|||
|
|||
Insert(dataRoot, Root.Height - dataRoot.Height); |
|||
} |
|||
} |
|||
} |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: 0a93ee633aad3dc4395851f56b650cc2 |
|||
MonoImporter: |
|||
externalObjects: {} |
|||
serializedVersion: 2 |
|||
defaultReferences: [] |
|||
executionOrder: 0 |
|||
icon: {instanceID: 0} |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
using System; |
|||
using System.Collections; |
|||
using System.Collections.Generic; |
|||
|
|||
namespace Unity.UIWidgets.Runtime.external |
|||
{ class SplayTree<TKey, TValue> : IDictionary<TKey, TValue> where TKey : IComparable<TKey> { |
|||
SplayTreeNode root; |
|||
int count; |
|||
int version = 0; |
|||
|
|||
public void Add(TKey key, TValue value) { |
|||
this.Set(key, value, throwOnExisting: true); |
|||
} |
|||
|
|||
public void Add(KeyValuePair<TKey, TValue> item) { |
|||
this.Set(item.Key, item.Value, throwOnExisting: true); |
|||
} |
|||
|
|||
public void AddAll(IEnumerable<TKey> list) { |
|||
foreach (var key in list) { |
|||
this.Add(new KeyValuePair<TKey, TValue>(key, default)); |
|||
} |
|||
} |
|||
|
|||
void Set(TKey key, TValue value, bool throwOnExisting) { |
|||
if (this.count == 0) { |
|||
this.version++; |
|||
this.root = new SplayTreeNode(key, value); |
|||
this.count = 1; |
|||
return; |
|||
} |
|||
|
|||
this.Splay(key); |
|||
|
|||
var c = key.CompareTo(this.root.Key); |
|||
if (c == 0) { |
|||
if (throwOnExisting) { |
|||
throw new ArgumentException("An item with the same key already exists in the tree."); |
|||
} |
|||
|
|||
this.version++; |
|||
this.root.Value = value; |
|||
return; |
|||
} |
|||
|
|||
var n = new SplayTreeNode(key, value); |
|||
if (c < 0) { |
|||
n.LeftChild = this.root.LeftChild; |
|||
n.RightChild = this.root; |
|||
this.root.LeftChild = null; |
|||
} |
|||
else { |
|||
n.RightChild = this.root.RightChild; |
|||
n.LeftChild = this.root; |
|||
this.root.RightChild = null; |
|||
} |
|||
|
|||
this.root = n; |
|||
this.count++; |
|||
this.Splay(key); |
|||
this.version++; |
|||
} |
|||
|
|||
public void Clear() { |
|||
this.root = null; |
|||
this.count = 0; |
|||
this.version++; |
|||
} |
|||
|
|||
public bool ContainsKey(TKey key) { |
|||
if (this.count == 0) { |
|||
return false; |
|||
} |
|||
|
|||
this.Splay(key); |
|||
|
|||
return key.CompareTo(this.root.Key) == 0; |
|||
} |
|||
|
|||
public bool Contains(KeyValuePair<TKey, TValue> item) { |
|||
if (this.count == 0) { |
|||
return false; |
|||
} |
|||
|
|||
this.Splay(item.Key); |
|||
|
|||
return item.Key.CompareTo(this.root.Key) == 0 && |
|||
(ReferenceEquals(this.root.Value, item.Value) || |
|||
(!ReferenceEquals(item.Value, null) && item.Value.Equals(this.root.Value))); |
|||
} |
|||
|
|||
public KeyValuePair<TKey, TValue>? First() { |
|||
SplayTreeNode t = this.root; |
|||
if (t == null) { |
|||
return null; |
|||
} |
|||
|
|||
while (t.LeftChild != null) { |
|||
t = t.LeftChild; |
|||
} |
|||
|
|||
return new KeyValuePair<TKey, TValue>(t.Key, t.Value); |
|||
} |
|||
|
|||
public KeyValuePair<TKey, TValue> FirstOrDefault() { |
|||
SplayTreeNode t = this.root; |
|||
if (t == null) { |
|||
return new KeyValuePair<TKey, TValue>(default(TKey), default(TValue)); |
|||
} |
|||
|
|||
while (t.LeftChild != null) { |
|||
t = t.LeftChild; |
|||
} |
|||
|
|||
return new KeyValuePair<TKey, TValue>(t.Key, t.Value); |
|||
} |
|||
|
|||
public KeyValuePair<TKey, TValue>? Last() { |
|||
SplayTreeNode t = this.root; |
|||
if (t == null) { |
|||
return null; |
|||
} |
|||
|
|||
while (t.RightChild != null) { |
|||
t = t.RightChild; |
|||
} |
|||
|
|||
return new KeyValuePair<TKey, TValue>(t.Key, t.Value); |
|||
} |
|||
|
|||
public KeyValuePair<TKey, TValue> LastOrDefault() { |
|||
SplayTreeNode t = this.root; |
|||
if (t == null) { |
|||
return new KeyValuePair<TKey, TValue>(default(TKey), default(TValue)); |
|||
} |
|||
|
|||
while (t.RightChild != null) { |
|||
t = t.RightChild; |
|||
} |
|||
|
|||
return new KeyValuePair<TKey, TValue>(t.Key, t.Value); |
|||
} |
|||
|
|||
void Splay(TKey key) { |
|||
SplayTreeNode l, r, t, y, header; |
|||
l = r = header = new SplayTreeNode(default(TKey), default(TValue)); |
|||
t = this.root; |
|||
while (true) { |
|||
var c = key.CompareTo(t.Key); |
|||
if (c < 0) { |
|||
if (t.LeftChild == null) { |
|||
break; |
|||
} |
|||
|
|||
if (key.CompareTo(t.LeftChild.Key) < 0) { |
|||
y = t.LeftChild; |
|||
t.LeftChild = y.RightChild; |
|||
y.RightChild = t; |
|||
t = y; |
|||
if (t.LeftChild == null) { |
|||
break; |
|||
} |
|||
} |
|||
|
|||
r.LeftChild = t; |
|||
r = t; |
|||
t = t.LeftChild; |
|||
} |
|||
else if (c > 0) { |
|||
if (t.RightChild == null) { |
|||
break; |
|||
} |
|||
|
|||
if (key.CompareTo(t.RightChild.Key) > 0) { |
|||
y = t.RightChild; |
|||
t.RightChild = y.LeftChild; |
|||
y.LeftChild = t; |
|||
t = y; |
|||
if (t.RightChild == null) { |
|||
break; |
|||
} |
|||
} |
|||
|
|||
l.RightChild = t; |
|||
l = t; |
|||
t = t.RightChild; |
|||
} |
|||
else { |
|||
break; |
|||
} |
|||
} |
|||
|
|||
l.RightChild = t.LeftChild; |
|||
r.LeftChild = t.RightChild; |
|||
t.LeftChild = header.RightChild; |
|||
t.RightChild = header.LeftChild; |
|||
this.root = t; |
|||
} |
|||
|
|||
public bool Remove(TKey key) { |
|||
if (this.count == 0) { |
|||
return false; |
|||
} |
|||
|
|||
this.Splay(key); |
|||
|
|||
if (key.CompareTo(this.root.Key) != 0) { |
|||
return false; |
|||
} |
|||
|
|||
if (this.root.LeftChild == null) { |
|||
this.root = this.root.RightChild; |
|||
} |
|||
else { |
|||
var swap = this.root.RightChild; |
|||
this.root = this.root.LeftChild; |
|||
this.Splay(key); |
|||
this.root.RightChild = swap; |
|||
} |
|||
|
|||
this.version++; |
|||
this.count--; |
|||
return true; |
|||
} |
|||
|
|||
public bool TryGetValue(TKey key, out TValue value) { |
|||
if (this.count == 0) { |
|||
value = default(TValue); |
|||
return false; |
|||
} |
|||
|
|||
this.Splay(key); |
|||
if (key.CompareTo(this.root.Key) != 0) { |
|||
value = default(TValue); |
|||
return false; |
|||
} |
|||
|
|||
value = this.root.Value; |
|||
return true; |
|||
} |
|||
|
|||
public TValue this[TKey key] { |
|||
get { |
|||
if (this.count == 0) { |
|||
throw new KeyNotFoundException("The key was not found in the tree."); |
|||
} |
|||
|
|||
this.Splay(key); |
|||
if (key.CompareTo(this.root.Key) != 0) { |
|||
throw new KeyNotFoundException("The key was not found in the tree."); |
|||
} |
|||
|
|||
return this.root.Value; |
|||
} |
|||
|
|||
set { this.Set(key, value, throwOnExisting: false); } |
|||
} |
|||
|
|||
public int Count { |
|||
get { return this.count; } |
|||
} |
|||
|
|||
public bool IsReadOnly { |
|||
get { return false; } |
|||
} |
|||
|
|||
public bool Remove(KeyValuePair<TKey, TValue> item) { |
|||
if (this.count == 0) { |
|||
return false; |
|||
} |
|||
|
|||
this.Splay(item.Key); |
|||
|
|||
if (item.Key.CompareTo(this.root.Key) == 0 && (ReferenceEquals(this.root.Value, item.Value) || |
|||
(!ReferenceEquals(item.Value, null) && |
|||
item.Value.Equals(this.root.Value)))) { |
|||
return false; |
|||
} |
|||
|
|||
if (this.root.LeftChild == null) { |
|||
this.root = this.root.RightChild; |
|||
} |
|||
else { |
|||
var swap = this.root.RightChild; |
|||
this.root = this.root.LeftChild; |
|||
this.Splay(item.Key); |
|||
this.root.RightChild = swap; |
|||
} |
|||
|
|||
this.version++; |
|||
this.count--; |
|||
return true; |
|||
} |
|||
|
|||
public void Trim(int depth) { |
|||
if (depth < 0) { |
|||
throw new ArgumentOutOfRangeException("depth", "The trim depth must not be negative."); |
|||
} |
|||
|
|||
if (this.count == 0) { |
|||
return; |
|||
} |
|||
|
|||
if (depth == 0) { |
|||
this.Clear(); |
|||
} |
|||
else { |
|||
var prevCount = this.count; |
|||
this.count = this.Trim(this.root, depth - 1); |
|||
if (prevCount != this.count) { |
|||
this.version++; |
|||
} |
|||
} |
|||
} |
|||
|
|||
int Trim(SplayTreeNode node, int depth) { |
|||
if (depth == 0) { |
|||
node.LeftChild = null; |
|||
node.RightChild = null; |
|||
return 1; |
|||
} |
|||
else { |
|||
int count = 1; |
|||
|
|||
if (node.LeftChild != null) { |
|||
count += this.Trim(node.LeftChild, depth - 1); |
|||
} |
|||
|
|||
if (node.RightChild != null) { |
|||
count += this.Trim(node.RightChild, depth - 1); |
|||
} |
|||
|
|||
return count; |
|||
} |
|||
} |
|||
|
|||
public ICollection<TKey> Keys { |
|||
get { return new TiedList<TKey>(this, this.version, this.AsList(node => node.Key)); } |
|||
} |
|||
|
|||
public ICollection<TValue> Values { |
|||
get { return new TiedList<TValue>(this, this.version, this.AsList(node => node.Value)); } |
|||
} |
|||
|
|||
public void CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex) { |
|||
this.AsList(node => new KeyValuePair<TKey, TValue>(node.Key, node.Value)).CopyTo(array, arrayIndex); |
|||
} |
|||
|
|||
public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator() { |
|||
return new TiedList<KeyValuePair<TKey, TValue>>(this, this.version, |
|||
this.AsList(node => new KeyValuePair<TKey, TValue>(node.Key, node.Value))).GetEnumerator(); |
|||
} |
|||
|
|||
IList<TEnumerator> AsList<TEnumerator>(Func<SplayTreeNode, TEnumerator> selector) { |
|||
if (this.root == null) { |
|||
return new TEnumerator[0]; |
|||
} |
|||
|
|||
var result = new List<TEnumerator>(this.count); |
|||
this.PopulateList(this.root, result, selector); |
|||
return result; |
|||
} |
|||
|
|||
void PopulateList<TEnumerator>(SplayTreeNode node, List<TEnumerator> list, |
|||
Func<SplayTreeNode, TEnumerator> selector) { |
|||
if (node.LeftChild != null) { |
|||
this.PopulateList(node.LeftChild, list, selector); |
|||
} |
|||
|
|||
list.Add(selector(node)); |
|||
if (node.RightChild != null) { |
|||
this.PopulateList(node.RightChild, list, selector); |
|||
} |
|||
} |
|||
|
|||
IEnumerator IEnumerable.GetEnumerator() { |
|||
return this.GetEnumerator(); |
|||
} |
|||
|
|||
sealed class SplayTreeNode { |
|||
public readonly TKey Key; |
|||
|
|||
public TValue Value; |
|||
public SplayTreeNode LeftChild; |
|||
public SplayTreeNode RightChild; |
|||
|
|||
public SplayTreeNode(TKey key, TValue value) { |
|||
this.Key = key; |
|||
this.Value = value; |
|||
} |
|||
} |
|||
|
|||
sealed class TiedList<T> : IList<T> { |
|||
readonly SplayTree<TKey, TValue> tree; |
|||
readonly int version; |
|||
readonly IList<T> backingList; |
|||
|
|||
public TiedList(SplayTree<TKey, TValue> tree, int version, IList<T> backingList) { |
|||
if (tree == null) { |
|||
throw new ArgumentNullException("tree"); |
|||
} |
|||
|
|||
if (backingList == null) { |
|||
throw new ArgumentNullException("backingList"); |
|||
} |
|||
|
|||
this.tree = tree; |
|||
this.version = version; |
|||
this.backingList = backingList; |
|||
} |
|||
|
|||
public int IndexOf(T item) { |
|||
if (this.tree.version != this.version) { |
|||
throw new InvalidOperationException("The collection has been modified."); |
|||
} |
|||
|
|||
return this.backingList.IndexOf(item); |
|||
} |
|||
|
|||
public void Insert(int index, T item) { |
|||
throw new NotSupportedException(); |
|||
} |
|||
|
|||
public void RemoveAt(int index) { |
|||
throw new NotSupportedException(); |
|||
} |
|||
|
|||
public T this[int index] { |
|||
get { |
|||
if (this.tree.version != this.version) { |
|||
throw new InvalidOperationException("The collection has been modified."); |
|||
} |
|||
|
|||
return this.backingList[index]; |
|||
} |
|||
set { throw new NotSupportedException(); } |
|||
} |
|||
|
|||
public void Add(T item) { |
|||
throw new NotSupportedException(); |
|||
} |
|||
|
|||
public void Clear() { |
|||
throw new NotSupportedException(); |
|||
} |
|||
|
|||
public bool Contains(T item) { |
|||
if (this.tree.version != this.version) { |
|||
throw new InvalidOperationException("The collection has been modified."); |
|||
} |
|||
|
|||
return this.backingList.Contains(item); |
|||
} |
|||
|
|||
public void CopyTo(T[] array, int arrayIndex) { |
|||
if (this.tree.version != this.version) { |
|||
throw new InvalidOperationException("The collection has been modified."); |
|||
} |
|||
|
|||
this.backingList.CopyTo(array, arrayIndex); |
|||
} |
|||
|
|||
public int Count { |
|||
get { return this.tree.count; } |
|||
} |
|||
|
|||
public bool IsReadOnly { |
|||
get { return true; } |
|||
} |
|||
|
|||
public bool Remove(T item) { |
|||
throw new NotSupportedException(); |
|||
} |
|||
|
|||
public IEnumerator<T> GetEnumerator() { |
|||
if (this.tree.version != this.version) { |
|||
throw new InvalidOperationException("The collection has been modified."); |
|||
} |
|||
|
|||
foreach (var item in this.backingList) { |
|||
yield return item; |
|||
if (this.tree.version != this.version) { |
|||
throw new InvalidOperationException("The collection has been modified."); |
|||
} |
|||
} |
|||
} |
|||
|
|||
IEnumerator IEnumerable.GetEnumerator() { |
|||
return this.GetEnumerator(); |
|||
} |
|||
} |
|||
} |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: 600f58b77585e6845aa9f0924a5af554 |
|||
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.service; |
|||
using Unity.UIWidgets.widgets; |
|||
using UnityEngine; |
|||
using Color = Unity.UIWidgets.ui.Color; |
|||
|
|||
namespace Unity.UIWidgets.material { |
|||
public class SearchUtils { |
|||
public static IPromise<object> showSearch( |
|||
BuildContext context, |
|||
SearchDelegate del, |
|||
string query = "" |
|||
) { |
|||
D.assert(del != null); |
|||
D.assert(context != null); |
|||
|
|||
del.query = query ?? del.query; |
|||
del._currentBody = _SearchBody.suggestions; |
|||
return Navigator.of(context).push(new _SearchPageRoute( |
|||
del: del |
|||
)); |
|||
} |
|||
} |
|||
|
|||
public abstract class SearchDelegate { |
|||
public abstract Widget buildSuggestions(BuildContext context); |
|||
public abstract Widget buildResults(BuildContext context); |
|||
public abstract Widget buildLeading(BuildContext context); |
|||
public abstract List<Widget> buildActions(BuildContext context); |
|||
|
|||
public virtual ThemeData appBarTheme(BuildContext context) { |
|||
D.assert(context != null); |
|||
ThemeData theme = Theme.of(context); |
|||
D.assert(theme != null); |
|||
return theme.copyWith( |
|||
primaryColor: Colors.white, |
|||
primaryIconTheme: theme.primaryIconTheme.copyWith(color: Colors.grey), |
|||
primaryColorBrightness: Brightness.light, |
|||
primaryTextTheme: theme.textTheme |
|||
); |
|||
} |
|||
|
|||
public virtual string query { |
|||
get { return this._queryTextController.text; } |
|||
set { |
|||
D.assert(this.query != null); |
|||
this._queryTextController.text = value; |
|||
} |
|||
} |
|||
|
|||
public virtual void showResults(BuildContext context) { |
|||
this._focusNode.unfocus(); |
|||
this._currentBody = _SearchBody.results; |
|||
} |
|||
|
|||
public virtual void showSuggestions(BuildContext context) { |
|||
FocusScope.of(context).requestFocus(this._focusNode); |
|||
this._currentBody = _SearchBody.suggestions; |
|||
} |
|||
|
|||
public virtual void close(BuildContext context, object result) { |
|||
this._currentBody = null; |
|||
this._focusNode.unfocus(); |
|||
var state = Navigator.of(context); |
|||
state.popUntil((Route route) => route == this._route); |
|||
state.pop(result); |
|||
} |
|||
|
|||
|
|||
public virtual Animation<float> transitionAnimation { |
|||
get { return this._proxyAnimation; } |
|||
} |
|||
|
|||
readonly internal FocusNode _focusNode = new FocusNode(); |
|||
|
|||
readonly internal TextEditingController _queryTextController = new TextEditingController(); |
|||
|
|||
readonly internal ProxyAnimation _proxyAnimation = new ProxyAnimation(Animations.kAlwaysDismissedAnimation); |
|||
|
|||
readonly internal ValueNotifier<_SearchBody?> _currentBodyNotifier = new ValueNotifier<_SearchBody?>(null); |
|||
|
|||
internal _SearchBody? _currentBody { |
|||
get { return this._currentBodyNotifier.value; } |
|||
set { this._currentBodyNotifier.value = value; } |
|||
} |
|||
|
|||
internal _SearchPageRoute _route; |
|||
} |
|||
|
|||
enum _SearchBody { |
|||
suggestions, |
|||
results |
|||
} |
|||
|
|||
class _SearchPageRoute : PageRoute { |
|||
public _SearchPageRoute(SearchDelegate del) { |
|||
D.assert(del != null); |
|||
D.assert(del._route == null, |
|||
() => $"The {this.del.GetType()} instance is currently used by another active " + |
|||
"search. Please close that search by calling close() on the SearchDelegate " + |
|||
"before openening another search with the same delegate instance." |
|||
); |
|||
this.del = del; |
|||
this.del._route = this; |
|||
} |
|||
|
|||
public readonly SearchDelegate del; |
|||
|
|||
public override Color barrierColor { |
|||
get { return null; } |
|||
} |
|||
|
|||
public override TimeSpan transitionDuration { |
|||
get { return new TimeSpan(0, 0, 0, 0, 300); } |
|||
} |
|||
|
|||
public override bool maintainState { |
|||
get { return false; } |
|||
} |
|||
|
|||
public override Widget buildTransitions( |
|||
BuildContext context, |
|||
Animation<float> animation, |
|||
Animation<float> secondaryAnimation, |
|||
Widget child |
|||
) { |
|||
return new FadeTransition( |
|||
opacity: animation, |
|||
child: child |
|||
); |
|||
} |
|||
|
|||
public override Animation<float> createAnimation() { |
|||
Animation<float> animation = base.createAnimation(); |
|||
this.del._proxyAnimation.parent = animation; |
|||
return animation; |
|||
} |
|||
|
|||
public override Widget buildPage( |
|||
BuildContext context, |
|||
Animation<float> animation, |
|||
Animation<float> secondaryAnimation |
|||
) { |
|||
return new _SearchPage( |
|||
del: this.del, |
|||
animation: animation |
|||
); |
|||
} |
|||
|
|||
protected internal override void didComplete(object result) { |
|||
base.didComplete(result); |
|||
D.assert(this.del._route == this); |
|||
this.del._route = null; |
|||
this.del._currentBody = null; |
|||
} |
|||
} |
|||
|
|||
class _SearchPage : StatefulWidget { |
|||
public _SearchPage( |
|||
SearchDelegate del, |
|||
Animation<float> animation |
|||
) { |
|||
this.del = del; |
|||
this.animation = animation; |
|||
} |
|||
|
|||
public readonly SearchDelegate del; |
|||
|
|||
public readonly Animation<float> animation; |
|||
|
|||
public override State createState() { |
|||
return new _SearchPageState(); |
|||
} |
|||
} |
|||
|
|||
class _SearchPageState : State<_SearchPage> { |
|||
public override void initState() { |
|||
base.initState(); |
|||
this.queryTextController.addListener(this._onQueryChanged); |
|||
this.widget.animation.addStatusListener(this._onAnimationStatusChanged); |
|||
this.widget.del._currentBodyNotifier.addListener(this._onSearchBodyChanged); |
|||
this.widget.del._focusNode.addListener(this._onFocusChanged); |
|||
} |
|||
|
|||
public override void dispose() { |
|||
base.dispose(); |
|||
this.queryTextController.removeListener(this._onQueryChanged); |
|||
this.widget.animation.removeStatusListener(this._onAnimationStatusChanged); |
|||
this.widget.del._currentBodyNotifier.removeListener(this._onSearchBodyChanged); |
|||
this.widget.del._focusNode.removeListener(this._onFocusChanged); |
|||
} |
|||
|
|||
void _onAnimationStatusChanged(AnimationStatus status) { |
|||
if (status != AnimationStatus.completed) { |
|||
return; |
|||
} |
|||
|
|||
this.widget.animation.removeStatusListener(this._onAnimationStatusChanged); |
|||
if (this.widget.del._currentBody == _SearchBody.suggestions) { |
|||
FocusScope.of(this.context).requestFocus(this.widget.del._focusNode); |
|||
} |
|||
} |
|||
|
|||
void _onFocusChanged() { |
|||
if (this.widget.del._focusNode.hasFocus && this.widget.del._currentBody != _SearchBody.suggestions) { |
|||
this.widget.del.showSuggestions(this.context); |
|||
} |
|||
} |
|||
|
|||
void _onQueryChanged() { |
|||
this.setState(() => { }); |
|||
} |
|||
|
|||
void _onSearchBodyChanged() { |
|||
this.setState(() => { }); |
|||
} |
|||
|
|||
public override Widget build(BuildContext context) { |
|||
MaterialD.debugCheckHasMaterialLocalizations(context); |
|||
|
|||
ThemeData theme = this.widget.del.appBarTheme(context); |
|||
string searchFieldLabel = MaterialLocalizations.of(context).searchFieldLabel; |
|||
Widget body = null; |
|||
switch (this.widget.del._currentBody) { |
|||
case _SearchBody.suggestions: |
|||
body = new KeyedSubtree( |
|||
key: new ValueKey<_SearchBody>(_SearchBody.suggestions), |
|||
child: this.widget.del.buildSuggestions(context) |
|||
); |
|||
break; |
|||
case _SearchBody.results: |
|||
body = new KeyedSubtree( |
|||
key: new ValueKey<_SearchBody>(_SearchBody.results), |
|||
child: this.widget.del.buildResults(context) |
|||
); |
|||
break; |
|||
} |
|||
|
|||
string routeName; |
|||
switch (Theme.of(this.context).platform) { |
|||
case RuntimePlatform.IPhonePlayer: |
|||
routeName = ""; |
|||
break; |
|||
case RuntimePlatform.Android: |
|||
routeName = searchFieldLabel; |
|||
break; |
|||
} |
|||
|
|||
return new Scaffold( |
|||
appBar: new AppBar( |
|||
backgroundColor: theme.primaryColor, |
|||
iconTheme: theme.primaryIconTheme, |
|||
textTheme: theme.primaryTextTheme, |
|||
brightness: theme.primaryColorBrightness, |
|||
leading: this.widget.del.buildLeading(context), |
|||
title: new TextField( |
|||
controller: this.queryTextController, |
|||
focusNode: this.widget.del._focusNode, |
|||
style: theme.textTheme.title, |
|||
textInputAction: TextInputAction.search, |
|||
onSubmitted: (string _) => { this.widget.del.showResults(context); }, |
|||
decoration: new InputDecoration( |
|||
border: InputBorder.none, |
|||
hintText: searchFieldLabel |
|||
) |
|||
), |
|||
actions: this.widget.del.buildActions(context) |
|||
), |
|||
body: new AnimatedSwitcher( |
|||
duration: new TimeSpan(0, 0, 0, 0, 300), |
|||
child: body |
|||
) |
|||
); |
|||
} |
|||
|
|||
TextEditingController queryTextController { |
|||
get { return this.widget.del._queryTextController; } |
|||
} |
|||
} |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: 421b92c9ff7d642af9b2e60e013c297d |
|||
MonoImporter: |
|||
externalObjects: {} |
|||
serializedVersion: 2 |
|||
defaultReferences: [] |
|||
executionOrder: 0 |
|||
icon: {instanceID: 0} |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
撰写
预览
正在加载...
取消
保存
Reference in new issue