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

427 行
14 KiB

using System.Collections.Generic;
using System.Linq;
using Unity.UIWidgets.foundation;
using Unity.UIWidgets.gestures;
using Unity.UIWidgets.painting;
using Unity.UIWidgets.rendering;
using Unity.UIWidgets.ui;
public interface RenderSliverVariableSizeBoxChildManager
{
void createChild(int index);
void removeChild(RenderBox child);
float estimateMaxScrollOffset(
SliverConstraints constraints,
int? firstIndex = null,
int? lastIndex = null,
float? leadingScrollOffset = null,
float? trailingScrollOffset = null
);
int childCount { get; }
void didAdoptChild(RenderBox child);
// ignore: avoid_positional_boolean_parameters
void setDidUnderflow(bool value);
void didStartLayout();
void didFinishLayout();
bool debugAssertChildListLocked();
}
public class SliverVariableSizeBoxAdaptorParentData : SliverMultiBoxAdaptorParentData
{
public float crossAxisOffset;
internal bool _keptAlive = false;
public override string ToString() => $"crossAxisOffset={crossAxisOffset}; {base.ToString()}";
}
public abstract class RenderSliverVariableSizeBoxAdaptor : TileContainerRenderObjectMixinRenderSliver<RenderBox,
SliverVariableSizeBoxAdaptorParentData>
{
public RenderSliverVariableSizeBoxAdaptor(RenderSliverVariableSizeBoxChildManager childManager)
{
_childManager = childManager;
}
public override void setupParentData(RenderObject child)
{
if (!(child.parentData is SliverVariableSizeBoxAdaptorParentData))
{
child.parentData = new SliverVariableSizeBoxAdaptorParentData();
}
}
protected RenderSliverVariableSizeBoxChildManager childManager
{
get => _childManager;
}
public readonly RenderSliverVariableSizeBoxChildManager _childManager;
public readonly Dictionary<int, RenderBox> _keepAliveBucket = new Dictionary<int, RenderBox>();
protected override void adoptChild(AbstractNodeMixinDiagnosticableTree childNode)
{
var child = childNode as RenderObject;
base.adoptChild(child);
var childParentData =
child?.parentData as SliverVariableSizeBoxAdaptorParentData;
if (childParentData?.keepAlive != null && (bool) !childParentData?.keepAlive)
{
childManager.didAdoptChild(child as RenderBox);
}
}
bool _debugAssertChildListLocked() =>
childManager.debugAssertChildListLocked();
public override void remove(int index)
{
RenderBox child = this[index];
// if child is null, it means this element was cached - drop the cached element
if (child == null)
{
RenderBox cachedChild = _keepAliveBucket[index];
if (cachedChild != null)
{
dropChild(cachedChild);
_keepAliveBucket.Remove(index);
}
return;
}
var childParentData =
child.parentData as SliverVariableSizeBoxAdaptorParentData;
if (childParentData?._keptAlive != null && (bool) !childParentData?._keptAlive)
{
base.remove(index);
return;
}
D.assert(childParentData != null &&
(childParentData.index != null && (_keepAliveBucket[childParentData.index] == child)));
_keepAliveBucket.Remove(childParentData.index);
dropChild(child);
}
public override void removeAll()
{
base.removeAll();
_keepAliveBucket.Values.ToList().ForEach(dropChild);
_keepAliveBucket.Clear();
}
void _createOrObtainChild(int index)
{
invokeLayoutCallback<SliverConstraints>((SliverConstraints constraints) =>
{
D.assert(constraints == this.constraints);
if (_keepAliveBucket.ContainsKey(index))
{
RenderBox child = _keepAliveBucket[index];
_keepAliveBucket.Remove(index);
var childParentData =
child.parentData as SliverVariableSizeBoxAdaptorParentData;
D.assert(childParentData._keptAlive);
dropChild(child);
child.parentData = childParentData;
this[index] = child;
childParentData._keptAlive = false;
}
else
{
_childManager.createChild(index);
}
});
}
void _destroyOrCacheChild(int index)
{
RenderBox child = this[index];
var childParentData =
child.parentData as SliverVariableSizeBoxAdaptorParentData;
if (childParentData.keepAlive)
{
D.assert(!childParentData._keptAlive);
remove(index);
_keepAliveBucket[childParentData.index] = child;
child.parentData = childParentData;
base.adoptChild(child);
childParentData._keptAlive = true;
}
else
{
D.assert(child.parent == this);
_childManager.removeChild(child);
D.assert(child.parent == null);
}
}
public override void attach(object o)
{
base.attach(owner);
if (o is PipelineOwner)
{
_keepAliveBucket.Values.ToList().ForEach((child) => child.attach(owner));
}
}
public override void detach()
{
base.detach();
_keepAliveBucket.Values.ToList().ForEach((child) => child.detach());
}
public override void redepthChildren()
{
base.redepthChildren();
_keepAliveBucket.Values.ToList().ForEach(redepthChild);
}
public override void visitChildren(RenderObjectVisitor visitor)
{
base.visitChildren(visitor);
_keepAliveBucket.Values.ToList().ForEach(a => visitor(a));
}
public bool addChild(int index)
{
D.assert(_debugAssertChildListLocked());
_createOrObtainChild(index);
var child = this[index];
if (child != null)
{
D.assert(indexOf(child) == index);
return true;
}
childManager.setDidUnderflow(true);
return false;
}
public RenderBox addAndLayoutChild(
int index,
BoxConstraints childConstraints,
bool parentUsesSize = false
)
{
D.assert(_debugAssertChildListLocked());
_createOrObtainChild(index);
var child = this[index];
if (child != null)
{
D.assert(indexOf(child) == index);
child.layout(childConstraints, parentUsesSize: parentUsesSize);
return child;
}
childManager.setDidUnderflow(true);
return null;
}
protected void collectGarbage(HashSet<int> visibleIndices)
{
D.assert(_debugAssertChildListLocked());
D.assert(childCount >= visibleIndices.Count);
invokeLayoutCallback<SliverConstraints>((SliverConstraints constraints) =>
{
// We destroy only those which are not visible.
indices.Except(visibleIndices).ToList().ForEach(_destroyOrCacheChild);
// Ask the child manager to remove the children that are no longer being
// kept alive. (This should cause _keepAliveBucket to change, so we have
// to prepare our list ahead of time.)
_keepAliveBucket.Values
.Where((RenderBox child) =>
{
var childParentData =
child.parentData as SliverVariableSizeBoxAdaptorParentData;
return childParentData != null && !childParentData.keepAlive;
})
.ToList()
.ForEach(_childManager.removeChild);
D.assert(!_keepAliveBucket.Values.Where((RenderBox child) =>
{
return child.parentData is SliverVariableSizeBoxAdaptorParentData childParentData &&
!childParentData.keepAlive;
}).Any());
});
}
public int indexOf(RenderBox child)
{
var childParentData =
child.parentData as SliverVariableSizeBoxAdaptorParentData;
D.assert(childParentData?.index != null);
return childParentData.index;
}
protected float paintExtentOf(RenderBox child)
{
D.assert(child.hasSize);
switch (constraints.axis)
{
case Axis.horizontal:
return child.size.width;
case Axis.vertical:
return child.size.height;
default:
return 0;
}
}
protected override bool hitTestChildren(SliverHitTestResult result,
float mainAxisPosition, float crossAxisPosition)
{
foreach (var child in children)
{
if (this.hitTestBoxChild(
new BoxHitTestResult(result),
child,
mainAxisPosition: mainAxisPosition,
crossAxisPosition: crossAxisPosition)
)
{
return true;
}
}
return false;
}
public override float? childMainAxisPosition(RenderObject child)
{
return childScrollOffset(child) - constraints.scrollOffset;
}
public override float? childCrossAxisPosition(RenderObject child)
{
var childParentData =
child.parentData as SliverVariableSizeBoxAdaptorParentData;
return childParentData.crossAxisOffset;
}
public override float? childScrollOffset(RenderObject child)
{
D.assert(child.parent == this);
var childParentData =
child.parentData as SliverVariableSizeBoxAdaptorParentData;
D.assert(childParentData != null && childParentData.layoutOffset != null);
return childParentData.layoutOffset;
}
public override void applyPaintTransform(RenderObject child, Matrix4 transform)
{
this.applyPaintTransformForBoxChild(child as RenderBox, transform);
}
public override void paint(PaintingContext context, Offset offset)
{
if (childCount == 0)
{
return;
}
// offset is to the top-left corner, regardless of our axis direction.
// originOffset gives us the delta from the real origin to the origin in the axis direction.
Offset mainAxisUnit = new Offset(0, 0);
Offset crossAxisUnit = new Offset(0, 0);
Offset originOffset = new Offset(0, 0);
bool? addExtent = null;
switch (GrowthDirectionUtils.applyGrowthDirectionToAxisDirection(
constraints.axisDirection, constraints.growthDirection))
{
case AxisDirection.up:
mainAxisUnit = new Offset (0, -1);
crossAxisUnit = new Offset (1, 0);
originOffset = offset + new Offset(0, geometry.paintExtent);
addExtent = true;
break;
case AxisDirection.right:
mainAxisUnit = new Offset (1, 0);
crossAxisUnit = new Offset (0, 1);
originOffset = offset;
addExtent = false;
break;
case AxisDirection.down:
mainAxisUnit = new Offset (0, 1);
crossAxisUnit = new Offset (1, 0);
originOffset = offset;
addExtent = false;
break;
case AxisDirection.left:
mainAxisUnit = new Offset (-1, 0);
crossAxisUnit = new Offset (0, 1);
originOffset = offset + new Offset(geometry.paintExtent, 0);
addExtent = true;
break;
}
foreach (var child in children) {
float? mainAxisDelta = childMainAxisPosition(child);
float? crossAxisDelta = childCrossAxisPosition(child);
Offset childOffset = new Offset(
(float) (originOffset.dx +
mainAxisUnit.dx * mainAxisDelta +
crossAxisUnit.dx * crossAxisDelta),
(float) (originOffset.dy +
mainAxisUnit.dy * mainAxisDelta +
crossAxisUnit.dy * crossAxisDelta)
);
if (addExtent.Value)
{
childOffset += mainAxisUnit * paintExtentOf(child);
}
context.paintChild(child, childOffset);
}
}
public override void debugFillProperties(DiagnosticPropertiesBuilder properties)
{
base.debugFillProperties(properties);
properties.add(DiagnosticsNode.message(childCount > 0
? $"currently live children: ${string.Join(", ", indices)}"
: "no children current live"));
}
public override List<DiagnosticsNode> debugDescribeChildren()
{
List<DiagnosticsNode>
childList = new List<DiagnosticsNode>();
if (childCount > 0)
{
foreach (var child in
children) {
var childParentData =
child.parentData as SliverVariableSizeBoxAdaptorParentData;
childList.Add(child.toDiagnosticsNode(
name: $"child with index {childParentData.index}"));
}
}
if (_keepAliveBucket.isNotEmpty())
{
List<int> indices = _keepAliveBucket.Keys.ToList();
indices.Sort();
foreach (var index in indices) {
childList.Add(_keepAliveBucket[index].toDiagnosticsNode(
name: $"child with index {index} (kept alive offstage)",
style: DiagnosticsTreeStyle.offstage
));
}
}
return childList;
}
}