您最多选择25个主题
主题必须以中文或者字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符
299 行
11 KiB
299 行
11 KiB
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using UIWidgets.foundation;
|
|
using UIWidgets.painting;
|
|
using UIWidgets.ui;
|
|
using UnityEngine;
|
|
|
|
namespace UIWidgets.rendering {
|
|
public interface RenderSliverBoxChildManager {
|
|
void createChild(int index, RenderBox after = null);
|
|
|
|
void removeChild(RenderBox child);
|
|
|
|
double estimateMaxScrollOffset(
|
|
SliverConstraints constraints,
|
|
int firstIndex = 0,
|
|
int lastIndex = 0,
|
|
double leadingScrollOffset = 0,
|
|
double trailingScrollOffset = 0);
|
|
|
|
int childCount { get; }
|
|
|
|
void didAdoptChild(RenderBox child);
|
|
|
|
void setDidUnderflow(bool value);
|
|
|
|
void didStartLayout();
|
|
|
|
void didFinishLayout();
|
|
}
|
|
|
|
public class SliverMultiBoxAdaptorParentData : ContainerParentDataMixinSliverLogicalParentData<RenderBox> {
|
|
public int index;
|
|
|
|
public bool keepAlive = false;
|
|
|
|
public bool _keptAlive = false;
|
|
}
|
|
|
|
public abstract class RenderSliverMultiBoxAdaptor
|
|
: ContainerRenderObjectMixinRenderSliver<RenderBox, SliverMultiBoxAdaptorParentData> {
|
|
public RenderSliverMultiBoxAdaptor(
|
|
RenderSliverBoxChildManager childManager = null
|
|
) {
|
|
this._childManager = childManager;
|
|
}
|
|
|
|
public override void setupParentData(RenderObject child) {
|
|
if (!(child.parentData is SliverMultiBoxAdaptorParentData)) {
|
|
child.parentData = new SliverMultiBoxAdaptorParentData();
|
|
}
|
|
}
|
|
|
|
public RenderSliverBoxChildManager childManager {
|
|
get { return this._childManager; }
|
|
}
|
|
|
|
public RenderSliverBoxChildManager _childManager;
|
|
|
|
public readonly Dictionary<int, RenderBox> _keepAliveBucket = new Dictionary<int, RenderBox>();
|
|
|
|
public override void adoptChild(AbstractNode childNode) {
|
|
base.adoptChild(childNode);
|
|
var child = (RenderBox) childNode;
|
|
var childParentData = (SliverMultiBoxAdaptorParentData) child.parentData;
|
|
if (!childParentData._keptAlive) {
|
|
this.childManager.didAdoptChild(child);
|
|
}
|
|
}
|
|
|
|
public override void insert(RenderBox child, RenderBox after = null) {
|
|
base.insert(child, after: after);
|
|
}
|
|
|
|
public override void remove(RenderBox child) {
|
|
var childParentData = (SliverMultiBoxAdaptorParentData) child.parentData;
|
|
if (!childParentData._keptAlive) {
|
|
base.remove(child);
|
|
return;
|
|
}
|
|
|
|
this._keepAliveBucket.Remove(childParentData.index);
|
|
this.dropChild(child);
|
|
}
|
|
|
|
public override void removeAll() {
|
|
base.removeAll();
|
|
|
|
foreach (var child in this._keepAliveBucket.Values) {
|
|
this.dropChild(child);
|
|
}
|
|
|
|
this._keepAliveBucket.Clear();
|
|
}
|
|
|
|
void _createOrObtainChild(int index, RenderBox after = null) {
|
|
this.invokeLayoutCallback<SliverConstraints>((SliverConstraints constraints) => {
|
|
if (this._keepAliveBucket.ContainsKey(index)) {
|
|
RenderBox child = this._keepAliveBucket[index];
|
|
this._keepAliveBucket.Remove(index);
|
|
var childParentData = (SliverMultiBoxAdaptorParentData) child.parentData;
|
|
this.dropChild(child);
|
|
child.parentData = childParentData;
|
|
this.insert(child, after: after);
|
|
childParentData._keptAlive = false;
|
|
} else {
|
|
this._childManager.createChild(index, after: after);
|
|
}
|
|
});
|
|
}
|
|
|
|
public void _destroyOrCacheChild(RenderBox child) {
|
|
var childParentData = (SliverMultiBoxAdaptorParentData) child.parentData;
|
|
if (childParentData.keepAlive) {
|
|
this.remove(child);
|
|
this._keepAliveBucket[childParentData.index] = child;
|
|
child.parentData = childParentData;
|
|
base.adoptChild(child);
|
|
childParentData._keptAlive = true;
|
|
} else {
|
|
this._childManager.removeChild(child);
|
|
}
|
|
}
|
|
|
|
public override void attach(object owner) {
|
|
base.attach(owner);
|
|
foreach (RenderBox child in this._keepAliveBucket.Values) {
|
|
child.attach(owner);
|
|
}
|
|
}
|
|
|
|
public override void detach() {
|
|
base.detach();
|
|
foreach (RenderBox child in this._keepAliveBucket.Values) {
|
|
child.detach();
|
|
}
|
|
}
|
|
|
|
public override void redepthChildren() {
|
|
base.redepthChildren();
|
|
foreach (var child in this._keepAliveBucket.Values) {
|
|
this.redepthChild(child);
|
|
}
|
|
}
|
|
|
|
public override void visitChildren(RenderObjectVisitor visitor) {
|
|
base.visitChildren(visitor);
|
|
|
|
foreach (var child in this._keepAliveBucket.Values) {
|
|
visitor(child);
|
|
}
|
|
}
|
|
|
|
public bool addInitialChild(int index = 0, double layoutOffset = 0.0) {
|
|
this._createOrObtainChild(index, after: null);
|
|
if (this.firstChild != null) {
|
|
var firstChildParentData = (SliverMultiBoxAdaptorParentData) this.firstChild.parentData;
|
|
firstChildParentData.layoutOffset = layoutOffset;
|
|
return true;
|
|
}
|
|
|
|
this.childManager.setDidUnderflow(true);
|
|
return false;
|
|
}
|
|
|
|
public RenderBox insertAndLayoutLeadingChild(BoxConstraints childConstraints, bool parentUsesSize = false) {
|
|
int index = this.indexOf(this.firstChild) - 1;
|
|
this._createOrObtainChild(index, after: null);
|
|
if (this.indexOf(this.firstChild) == index) {
|
|
this.firstChild.layout(childConstraints, parentUsesSize: parentUsesSize);
|
|
return this.firstChild;
|
|
}
|
|
|
|
this.childManager.setDidUnderflow(true);
|
|
return null;
|
|
}
|
|
|
|
public RenderBox insertAndLayoutChild(
|
|
BoxConstraints childConstraints,
|
|
RenderBox after = null,
|
|
bool parentUsesSize = false
|
|
) {
|
|
int index = this.indexOf(after) + 1;
|
|
this._createOrObtainChild(index, after: after);
|
|
RenderBox child = this.childAfter(after);
|
|
if (child != null && this.indexOf(child) == index) {
|
|
child.layout(childConstraints, parentUsesSize: parentUsesSize);
|
|
return child;
|
|
}
|
|
|
|
this.childManager.setDidUnderflow(true);
|
|
return null;
|
|
}
|
|
|
|
public void collectGarbage(int leadingGarbage, int trailingGarbage) {
|
|
this.invokeLayoutCallback<SliverConstraints>((SliverConstraints constraints) => {
|
|
while (leadingGarbage > 0) {
|
|
this._destroyOrCacheChild(this.firstChild);
|
|
leadingGarbage -= 1;
|
|
}
|
|
|
|
while (trailingGarbage > 0) {
|
|
this._destroyOrCacheChild(this.lastChild);
|
|
trailingGarbage -= 1;
|
|
}
|
|
|
|
this._keepAliveBucket.Values.Where((RenderBox child) => {
|
|
var childParentData = (SliverMultiBoxAdaptorParentData) child.parentData;
|
|
return !childParentData.keepAlive;
|
|
}).ToList().ForEach(this._childManager.removeChild);
|
|
});
|
|
}
|
|
|
|
public int indexOf(RenderBox child) {
|
|
var childParentData = (SliverMultiBoxAdaptorParentData) child.parentData;
|
|
return childParentData.index;
|
|
}
|
|
|
|
public double paintExtentOf(RenderBox child) {
|
|
switch (this.constraints.axis) {
|
|
case Axis.horizontal:
|
|
return child.size.width;
|
|
case Axis.vertical:
|
|
return child.size.height;
|
|
}
|
|
|
|
return 0.0;
|
|
}
|
|
|
|
public override double childMainAxisPosition(RenderObject child) {
|
|
return this.childScrollOffset(child) - this.constraints.scrollOffset;
|
|
}
|
|
|
|
public override double childScrollOffset(RenderObject child) {
|
|
var childParentData = (SliverMultiBoxAdaptorParentData) child.parentData;
|
|
return childParentData.layoutOffset;
|
|
}
|
|
|
|
public override void applyPaintTransform(RenderObject child, ref Matrix4x4 transform) {
|
|
this.applyPaintTransformForBoxChild((RenderBox) child, ref transform);
|
|
}
|
|
|
|
public override void paint(PaintingContext context, Offset offset) {
|
|
if (this.firstChild == null) {
|
|
return;
|
|
}
|
|
|
|
Offset mainAxisUnit = null, crossAxisUnit = null, originOffset = null;
|
|
bool addExtent = false;
|
|
switch (GrowthDirectionUtils.applyGrowthDirectionToAxisDirection(this.constraints.axisDirection,
|
|
this.constraints.growthDirection)) {
|
|
case AxisDirection.up:
|
|
mainAxisUnit = new Offset(0.0, -1.0);
|
|
crossAxisUnit = new Offset(1.0, 0.0);
|
|
originOffset = offset + new Offset(0.0, this.geometry.paintExtent);
|
|
addExtent = true;
|
|
break;
|
|
case AxisDirection.right:
|
|
mainAxisUnit = new Offset(1.0, 0.0);
|
|
crossAxisUnit = new Offset(0.0, 1.0);
|
|
originOffset = offset;
|
|
addExtent = false;
|
|
break;
|
|
case AxisDirection.down:
|
|
mainAxisUnit = new Offset(0.0, 1.0);
|
|
crossAxisUnit = new Offset(1.0, 0.0);
|
|
originOffset = offset;
|
|
addExtent = false;
|
|
break;
|
|
case AxisDirection.left:
|
|
mainAxisUnit = new Offset(-1.0, 0.0);
|
|
crossAxisUnit = new Offset(0.0, 1.0);
|
|
originOffset = offset + new Offset(this.geometry.paintExtent, 0.0);
|
|
addExtent = true;
|
|
break;
|
|
}
|
|
|
|
RenderBox child = this.firstChild;
|
|
while (child != null) {
|
|
double mainAxisDelta = this.childMainAxisPosition(child);
|
|
double crossAxisDelta = this.childCrossAxisPosition(child);
|
|
Offset childOffset = new Offset(
|
|
originOffset.dx + mainAxisUnit.dx * mainAxisDelta + crossAxisUnit.dx * crossAxisDelta,
|
|
originOffset.dy + mainAxisUnit.dy * mainAxisDelta + crossAxisUnit.dy * crossAxisDelta
|
|
);
|
|
if (addExtent) {
|
|
childOffset += mainAxisUnit * this.paintExtentOf(child);
|
|
}
|
|
|
|
if (mainAxisDelta < this.constraints.remainingPaintExtent &&
|
|
mainAxisDelta + this.paintExtentOf(child) > 0) {
|
|
context.paintChild(child, childOffset);
|
|
}
|
|
|
|
child = this.childAfter(child);
|
|
}
|
|
}
|
|
}
|
|
}
|