protected override void performLayout()
        {
            this.childManager.didStartLayout();
            this.childManager.setDidUnderflow(false);

            float scrollOffset = this.constraints.scrollOffset + this.constraints.cacheOrigin;

            D.assert(scrollOffset >= 0.0f);
            float remainingExtent = this.constraints.remainingCacheExtent;

            D.assert(remainingExtent >= 0.0f);
            float targetEndScrollOffset = scrollOffset + remainingExtent;

            SliverGridLayout layout = this._gridDelegate.getLayout(this.constraints);

            int firstIndex      = layout.getMinChildIndexForScrollOffset(scrollOffset);
            int?targetLastIndex = targetEndScrollOffset.isFinite()
                ? (int?)layout.getMaxChildIndexForScrollOffset(targetEndScrollOffset)
                : null;

            if (this.firstChild != null)
            {
                int oldFirstIndex   = this.indexOf(this.firstChild);
                int oldLastIndex    = this.indexOf(this.lastChild);
                int leadingGarbage  = (firstIndex - oldFirstIndex).clamp(0, this.childCount);
                int trailingGarbage = targetLastIndex == null
                    ? 0
                    : ((oldLastIndex - targetLastIndex) ?? 0).clamp(0, this.childCount);
                this.collectGarbage(leadingGarbage, trailingGarbage);
            }
            else
            {
                this.collectGarbage(0, 0);
            }

            SliverGridGeometry firstChildGridGeometry = layout.getGeometryForChildIndex(firstIndex);
            float?leadingScrollOffset  = firstChildGridGeometry.scrollOffset;
            float?trailingScrollOffset = firstChildGridGeometry.trailingScrollOffset;

            if (this.firstChild == null)
            {
                if (!this.addInitialChild(index: firstIndex,
                                          layoutOffset: firstChildGridGeometry.scrollOffset ?? 0.0f))
                {
                    float max = layout.computeMaxScrollOffset(this.childManager.childCount ?? 0);
                    this.geometry = new SliverGeometry(
                        scrollExtent: max,
                        maxPaintExtent: max
                        );
                    this.childManager.didFinishLayout();
                    return;
                }
            }

            RenderBox trailingChildWithLayout = null;

            for (int index = this.indexOf(this.firstChild) - 1; index >= firstIndex; --index)
            {
                SliverGridGeometry gridGeometry = layout.getGeometryForChildIndex(index);
                RenderBox          child        = this.insertAndLayoutLeadingChild(
                    gridGeometry.getBoxConstraints(this.constraints)
                    );
                SliverGridParentData childParentData = child.parentData as SliverGridParentData;
                childParentData.layoutOffset    = gridGeometry.scrollOffset ?? 0.0f;
                childParentData.crossAxisOffset = gridGeometry.crossAxisOffset ?? 0.0f;
                D.assert(childParentData.index == index);
                trailingChildWithLayout = trailingChildWithLayout ?? child;
                trailingScrollOffset    =
                    Mathf.Max(trailingScrollOffset ?? 0.0f, gridGeometry.trailingScrollOffset ?? 0.0f);
            }

            if (trailingChildWithLayout == null)
            {
                this.firstChild.layout(firstChildGridGeometry.getBoxConstraints(this.constraints));
                SliverGridParentData childParentData = this.firstChild.parentData as SliverGridParentData;
                childParentData.layoutOffset    = firstChildGridGeometry.scrollOffset ?? 0.0f;
                childParentData.crossAxisOffset = firstChildGridGeometry.crossAxisOffset ?? 0.0f;
                trailingChildWithLayout         = this.firstChild;
            }

            for (int index = this.indexOf(trailingChildWithLayout) + 1;
                 targetLastIndex == null || index <= targetLastIndex;
                 ++index)
            {
                SliverGridGeometry gridGeometry     = layout.getGeometryForChildIndex(index);
                BoxConstraints     childConstraints = gridGeometry.getBoxConstraints(this.constraints);
                RenderBox          child            = this.childAfter(trailingChildWithLayout);
                if (child == null)
                {
                    child = this.insertAndLayoutChild(childConstraints, after: trailingChildWithLayout);
                    if (child == null)
                    {
                        break;
                    }
                }
                else
                {
                    child.layout(childConstraints);
                }

                trailingChildWithLayout = child;
                D.assert(child != null);
                SliverGridParentData childParentData = child.parentData as SliverGridParentData;
                childParentData.layoutOffset    = gridGeometry.scrollOffset ?? 0.0f;
                childParentData.crossAxisOffset = gridGeometry.crossAxisOffset ?? 0.0f;
                D.assert(childParentData.index == index);
                trailingScrollOffset =
                    Mathf.Max(trailingScrollOffset ?? 0.0f, gridGeometry.trailingScrollOffset ?? 0.0f);
            }

            int lastIndex = this.indexOf(this.lastChild);

            D.assert(this.childScrollOffset(this.firstChild) <= scrollOffset);
            D.assert(this.debugAssertChildListIsNonEmptyAndContiguous());
            D.assert(this.indexOf(this.firstChild) == firstIndex);
            D.assert(targetLastIndex == null || lastIndex <= targetLastIndex);

            float estimatedTotalExtent = this.childManager.estimateMaxScrollOffset(this.constraints,
                                                                                   firstIndex: firstIndex,
                                                                                   lastIndex: lastIndex,
                                                                                   leadingScrollOffset: leadingScrollOffset ?? 0.0f,
                                                                                   trailingScrollOffset: trailingScrollOffset ?? 0.0f
                                                                                   );

            float paintExtent = this.calculatePaintOffset(this.constraints,
                                                          from: leadingScrollOffset ?? 0.0f,
                                                          to: trailingScrollOffset ?? 0.0f
                                                          );
            float cacheExtent = this.calculateCacheOffset(this.constraints,
                                                          from: leadingScrollOffset ?? 0.0f,
                                                          to: trailingScrollOffset ?? 0.0f
                                                          );

            this.geometry = new SliverGeometry(
                scrollExtent: estimatedTotalExtent,
                paintExtent: paintExtent,
                maxPaintExtent: estimatedTotalExtent,
                cacheExtent: cacheExtent,
                hasVisualOverflow: true
                );

            if (estimatedTotalExtent == trailingScrollOffset)
            {
                this.childManager.setDidUnderflow(true);
            }

            this.childManager.didFinishLayout();
        }
        public override float childCrossAxisPosition(RenderObject child)
        {
            SliverGridParentData childParentData = (SliverGridParentData)child.parentData;

            return(childParentData.crossAxisOffset);
        }