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

520 行
16 KiB

using System.Collections.Generic;
using System.Linq;
using Unity.UIWidgets.external;
using Unity.UIWidgets.foundation;
using Unity.UIWidgets.painting;
using Unity.UIWidgets.rendering;
using Unity.UIWidgets.widgets;
public abstract class SliverVariableSizeBoxAdaptorWidget : SliverWithKeepAliveWidget
{
public SliverVariableSizeBoxAdaptorWidget(
SliverChildDelegate Delegate,
Key key = null
) : base(key: key)
{
this.Delegate = Delegate;
}
public readonly SliverChildDelegate Delegate;
public override Element createElement()
{
return new SliverVariableSizeBoxAdaptorElement(this);
}
public abstract override RenderObject createRenderObject(BuildContext context);
public float? estimateMaxScrollOffset(
SliverConstraints constraints,
int firstIndex,
int lastIndex,
float leadingScrollOffset,
float trailingScrollOffset
)
{
D.assert(lastIndex >= firstIndex);
return Delegate.estimateMaxScrollOffset(
firstIndex,
lastIndex,
leadingScrollOffset,
trailingScrollOffset
);
}
public override void debugFillProperties(DiagnosticPropertiesBuilder properties)
{
base.debugFillProperties(properties);
properties.add(
new DiagnosticsProperty<SliverChildDelegate>("delegate", Delegate)
);
}
}
public class SliverVariableSizeBoxAdaptorElement : RenderObjectElement
, RenderSliverVariableSizeBoxChildManager
{
public SliverVariableSizeBoxAdaptorElement(SliverVariableSizeBoxAdaptorWidget widget)
: base(widget)
{
}
public override RenderObjectWidget widget
{
get { return base.widget as SliverVariableSizeBoxAdaptorWidget; }
}
public override RenderObject renderObject
{
get { return base.renderObject as RenderSliverVariableSizeBoxAdaptor; }
}
public override void update(Widget newWidgetx)
{
SliverVariableSizeBoxAdaptorWidget newWidget = newWidgetx as SliverVariableSizeBoxAdaptorWidget;
SliverVariableSizeBoxAdaptorWidget oldWidget = widget as SliverVariableSizeBoxAdaptorWidget;
base.update(newWidget);
SliverChildDelegate newDelegate = newWidget.Delegate;
SliverChildDelegate oldDelegate = oldWidget.Delegate;
if (newDelegate != oldDelegate &&
(newDelegate.GetType() != oldDelegate.GetType() ||
newDelegate.shouldRebuild(oldDelegate)))
{
performRebuild();
}
}
// We inflate widgets at two different times:
// 1. When we ourselves are told to rebuild (see performRebuild).
// 2. When our render object needs a child (see createChild).
// In both cases, we cache the results of calling into our delegate to get the widget,
// so that if we do case 2 later, we don't call the builder again.
// Any time we do case 1, though, we reset the cache.
private readonly Dictionary<int, Widget> _childWidgets = new Dictionary<int, Widget>();
readonly SplayTree<int, Element> _childElements =
new SplayTree<int, Element>();
protected override void performRebuild()
{
_childWidgets.Clear(); // Reset the cache, as described above.
base.performRebuild();
D.assert(_currentlyUpdatingChildIndex == null);
try
{
int firstIndex;
int lastIndex;
if (_childElements.isEmpty())
{
firstIndex = 0;
lastIndex = 0;
}
else if (_didUnderflow)
{
firstIndex = _childElements.firstKey();
lastIndex = _childElements.lastKey() + 1;
}
else
{
firstIndex = _childElements.firstKey();
lastIndex = _childElements.lastKey();
}
for (int index = firstIndex; index <= lastIndex; ++index)
{
_currentlyUpdatingChildIndex = index;
Element newChild =
updateChild(_childElements[index], _build(index), index);
if (newChild != null)
{
_childElements[index] = newChild;
}
else
{
_childElements.Remove(index);
}
}
}
finally
{
_currentlyUpdatingChildIndex = null;
}
}
Widget _build(int index)
{
return _childWidgets.putIfAbsent(
index, () => ((SliverVariableSizeBoxAdaptorWidget) widget).Delegate.build(this, index));
}
public void createChild(int index)
{
D.assert(_currentlyUpdatingChildIndex == null);
owner.buildScope(this, () =>
{
Element newChild;
try
{
_currentlyUpdatingChildIndex = index;
newChild = updateChild(_childElements.getOrDefault(index, null), _build(index), index);
}
finally
{
_currentlyUpdatingChildIndex = null;
}
if (newChild != null)
{
_childElements[index] = newChild;
}
else
{
_childElements.Remove(index);
}
});
}
protected override Element updateChild(Element child, Widget newWidget, object newSlot)
{
Element newChild = base.updateChild(child, newWidget, newSlot);
var oldParentData = child?.renderObject?.parentData
as SliverVariableSizeBoxAdaptorParentData;
var newParentData = newChild?.renderObject?.parentData
as SliverVariableSizeBoxAdaptorParentData;
// set keepAlive to true in order to populate the cache
if (newParentData != null)
{
newParentData.keepAlive = true;
}
// Preserve the old layoutOffset if the renderObject was swapped out.
if (oldParentData != newParentData &&
oldParentData != null &&
newParentData != null)
{
newParentData.layoutOffset = oldParentData.layoutOffset;
}
return newChild;
}
public override void forgetChild(Element child)
{
D.assert(child.slot != null);
D.assert(_childElements.ContainsKey((int) child.slot));
_childElements.Remove((int) child.slot);
base.forgetChild(child);
}
public void removeChild(RenderBox child)
{
int index = ((RenderSliverVariableSizeBoxAdaptor) renderObject).indexOf(child);
D.assert(_currentlyUpdatingChildIndex == null);
D.assert(index >= 0);
owner.buildScope(this, () =>
{
D.assert(_childElements.ContainsKey(index));
try
{
_currentlyUpdatingChildIndex = index;
Element result = updateChild(_childElements[index], null, index);
D.assert(result == null);
}
finally
{
_currentlyUpdatingChildIndex = null;
}
_childElements.Remove(index);
D.assert(!_childElements.ContainsKey(index));
});
}
float? _extrapolateMaxScrollOffset(
int? firstIndex,
int? lastIndex,
float? leadingScrollOffset,
float? trailingScrollOffset
)
{
int? childCount = ((SliverVariableSizeBoxAdaptorWidget) widget).Delegate.estimatedChildCount;
if (childCount == null)
{
return float.PositiveInfinity;
}
if (lastIndex == childCount - 1)
{
return trailingScrollOffset;
}
int? reifiedCount = lastIndex - firstIndex + 1;
float? averageExtent =
(trailingScrollOffset - leadingScrollOffset) / reifiedCount;
int? remainingCount = childCount - lastIndex - 1;
return trailingScrollOffset + averageExtent * remainingCount;
}
public float estimateMaxScrollOffset(
SliverConstraints constraints,
int? firstIndex = null,
int? lastIndex = null,
float? leadingScrollOffset = null,
float? trailingScrollOffset = null
)
{
return ((SliverVariableSizeBoxAdaptorWidget) widget).estimateMaxScrollOffset(
constraints,
firstIndex.Value,
lastIndex.Value,
leadingScrollOffset.Value,
trailingScrollOffset.Value
) ??
_extrapolateMaxScrollOffset(
firstIndex,
lastIndex,
leadingScrollOffset,
trailingScrollOffset
).Value;
}
public int childCount
{
get { return ((SliverVariableSizeBoxAdaptorWidget) widget).Delegate.estimatedChildCount ?? 0; }
}
public void didStartLayout()
{
D.assert(debugAssertChildListLocked());
}
public void didFinishLayout()
{
D.assert(debugAssertChildListLocked());
int firstIndex = _childElements.firstKey();
int lastIndex = _childElements.lastKey();
((SliverVariableSizeBoxAdaptorWidget) widget).Delegate.didFinishLayout(firstIndex, lastIndex);
}
int? _currentlyUpdatingChildIndex;
public bool debugAssertChildListLocked()
{
D.assert(_currentlyUpdatingChildIndex == null);
return true;
}
public void didAdoptChild(RenderBox child)
{
D.assert(_currentlyUpdatingChildIndex != null);
var childParentData =
child.parentData as SliverVariableSizeBoxAdaptorParentData;
childParentData.index = _currentlyUpdatingChildIndex.Value;
}
bool _didUnderflow = false;
public void setDidUnderflow(bool value)
{
_didUnderflow = value;
}
protected override void insertChildRenderObject(RenderObject childObject, object o)
{
var child = childObject as RenderBox;
int slot = (int) o;
D.assert(_currentlyUpdatingChildIndex == slot);
D.assert(((RenderSliverVariableSizeBoxAdaptor) renderObject).debugValidateChild(child));
((RenderSliverVariableSizeBoxAdaptor) renderObject)[_currentlyUpdatingChildIndex.Value] = child;
D.assert(() =>
{
var childParentData =
child.parentData as SliverVariableSizeBoxAdaptorParentData;
D.assert(slot == childParentData.index);
return true;
});
}
protected override void moveChildRenderObject(RenderObject child, object slot)
{
D.assert(false);
}
protected override void removeChildRenderObject(RenderObject child)
{
D.assert(_currentlyUpdatingChildIndex != null);
((RenderSliverVariableSizeBoxAdaptor) renderObject).remove(_currentlyUpdatingChildIndex.Value);
}
public override void visitChildren(ElementVisitor visitor)
{
// The toList() is to make a copy so that the underlying list can be modified by
// the visitor:
_childElements.Values.ToList().ForEach(v => visitor(v));
}
public override void debugVisitOnstageChildren(ElementVisitor visitor)
{
_childElements.Values.Where((Element child) =>
{
var parentData =
child.renderObject.parentData as SliverMultiBoxAdaptorParentData;
float itemExtent = 0;
SliverConstraints sliverConstraints = (SliverConstraints) renderObject.constraints;
switch (sliverConstraints.axis)
{
case Axis.horizontal:
itemExtent = child.renderObject.paintBounds.width;
break;
case Axis.vertical:
itemExtent = child.renderObject.paintBounds.height;
break;
}
return parentData.layoutOffset <
sliverConstraints.scrollOffset +
sliverConstraints.remainingPaintExtent &&
parentData.layoutOffset + itemExtent >
sliverConstraints.scrollOffset;
}).ToList().ForEach(v => visitor(v));
}
}
public class SliverStaggeredGrid : SliverVariableSizeBoxAdaptorWidget
{
public SliverStaggeredGrid(
SliverChildDelegate Delegate,
SliverStaggeredGridDelegate gridDelegate,
Key key = null
) : base(key: key, Delegate: Delegate)
{
this.gridDelegate = gridDelegate;
}
public static SliverStaggeredGrid count(
int crossAxisCount,
Key key = null,
float mainAxisSpacing = 0.0f,
float crossAxisSpacing = 0.0f,
List<Widget> children = null,
List<StaggeredTile> staggeredTiles = null
)
{
staggeredTiles = staggeredTiles ?? new List<StaggeredTile>();
children = children ?? new List<Widget>();
var gridDelegate = new SliverStaggeredGridDelegateWithFixedCrossAxisCount(
crossAxisCount: crossAxisCount,
mainAxisSpacing: mainAxisSpacing,
crossAxisSpacing: crossAxisSpacing,
staggeredTileBuilder: (i) => staggeredTiles[i],
staggeredTileCount: staggeredTiles.Count
);
return new SliverStaggeredGrid(
Delegate: new SliverChildListDelegate(
children
),
gridDelegate: gridDelegate,
key: key
);
}
public static SliverStaggeredGrid countBuilder(
int crossAxisCount,
GridUtil.IndexedStaggeredTileBuilder staggeredTileBuilder,
IndexedWidgetBuilder itemBuilder,
int itemCount,
Key key = null,
float mainAxisSpacing = 0,
float crossAxisSpacing = 0
)
{
var gridDelegate = new SliverStaggeredGridDelegateWithFixedCrossAxisCount(
crossAxisCount: crossAxisCount,
mainAxisSpacing: mainAxisSpacing,
crossAxisSpacing: crossAxisSpacing,
staggeredTileBuilder: staggeredTileBuilder,
staggeredTileCount: itemCount
);
return new SliverStaggeredGrid(
Delegate: new SliverChildBuilderDelegate(
itemBuilder,
childCount: itemCount
),
gridDelegate: gridDelegate,
key: key
);
}
public static SliverStaggeredGrid extent(
float maxCrossAxisExtent,
Key key = null,
float mainAxisSpacing = 0,
float crossAxisSpacing = 0,
List<Widget> children = null, //const <Widget>[],
List<StaggeredTile> staggeredTiles = null // = const <StaggeredTile>[],
)
{
children = new List<Widget>();
staggeredTiles = new List<StaggeredTile>();
var gridDelegate = new SliverStaggeredGridDelegateWithMaxCrossAxisExtent(
maxCrossAxisExtent: maxCrossAxisExtent,
mainAxisSpacing: mainAxisSpacing,
crossAxisSpacing: crossAxisSpacing,
staggeredTileBuilder: (i) => staggeredTiles[i],
staggeredTileCount: staggeredTiles.Count
);
return new SliverStaggeredGrid(
key: key,
Delegate: new SliverChildListDelegate(
children
),
gridDelegate: gridDelegate
);
}
public static SliverStaggeredGrid extentBuilder(
float maxCrossAxisExtent,
GridUtil.IndexedStaggeredTileBuilder staggeredTileBuilder,
IndexedWidgetBuilder itemBuilder,
int itemCount,
Key key = null,
float mainAxisSpacing = 0,
float crossAxisSpacing = 0
)
{
var gridDelegate = new SliverStaggeredGridDelegateWithMaxCrossAxisExtent(
maxCrossAxisExtent: maxCrossAxisExtent,
mainAxisSpacing: mainAxisSpacing,
crossAxisSpacing: crossAxisSpacing,
staggeredTileBuilder: staggeredTileBuilder,
staggeredTileCount: itemCount
);
return new SliverStaggeredGrid(
key: key,
Delegate: new SliverChildBuilderDelegate(
itemBuilder,
childCount: itemCount
),
gridDelegate: gridDelegate
);
}
public readonly SliverStaggeredGridDelegate gridDelegate;
public override RenderObject createRenderObject(BuildContext context)
{
var element = context as SliverVariableSizeBoxAdaptorElement;
return new RenderSliverStaggeredGrid(
childManager: element, gridDelegate: gridDelegate);
}
public override void updateRenderObject(BuildContext context, RenderObject o)
{
var renderObject = o as RenderSliverStaggeredGrid;
renderObject.gridDelegate = gridDelegate;
}
}