// Do measurement when in vertical orientation private void MeasureVertical(nfloat parentWidth, nfloat parentHeight) { // Work out our width var width = LayoutParameters.TryResolveWidth(this, parentWidth, parentHeight); var height = LayoutParameters.TryResolveHeight(this, parentWidth, parentHeight); // Allow room for padding if (width != nfloat.MaxValue) { width -= Padding.TotalWidth(); } // Work out the total fixed size nfloat totalFixedSize = 0; double totalWeight = 0; int visibleViewCount = 0; foreach (var v in SubViews.Where(x => !x.Gone)) { if (v.LayoutParameters.HeightUnits == Units.ParentRatio) { // We'll deal with this later // For now, lets just total up the specified weights totalWeight += v.LayoutParameters.Weight; } else { // Lay it out v.Measure(adjustLayoutWidth(width, v), nfloat.MaxValue); totalFixedSize += v.GetMeasuredSize().Height; } // Include margins totalFixedSize += v.LayoutParameters.Margins.TotalHeight(); visibleViewCount++; } // Also need to include our own padding totalFixedSize += Padding.TotalHeight(); // And spacing between controls if (visibleViewCount > 1) { totalFixedSize += (visibleViewCount - 1) * Spacing; } nfloat totalVariableSize = 0; if (LayoutParameters.HeightUnits == Units.ContentRatio || height == nfloat.MaxValue) { // This is a weird case: we have a height of wrap content, but child items that want to fill parent too. // Temporarily switch those items to wrap content and use their natural size foreach (var v in SubViews.Where(x => !x.Gone && x.LayoutParameters.HeightUnits == Units.ParentRatio)) { v.Measure(adjustLayoutWidth(width, v), nfloat.MaxValue); totalVariableSize += v.GetMeasuredSize().Height; } } else { // If we've had an explicit weight passed to us, ignore the calculated total weight and use it instead if (_totalWeight != 0) { totalWeight = _totalWeight; } // Work out how much room we've got to share around nfloat room = height - totalFixedSize; // Layout the fill parent items foreach (var v in SubViews.Where(x => !x.Gone && x.LayoutParameters.HeightUnits == Units.ParentRatio)) { // Work out size if (room < 0) { room = 0; } nfloat size = (nfloat)(totalWeight == 0 ? room : room * v.LayoutParameters.Weight / totalWeight); // Measure it v.Measure(adjustLayoutWidth(width, v), size); // Update total size totalVariableSize += v.GetMeasuredSize().Height; // Adjust the weighting calculation in case the view didn't accept our measurement room -= v.GetMeasuredSize().Height; totalWeight -= v.LayoutParameters.Weight; } } CGSize sizeMeasured = CGSize.Empty; if (width == nfloat.MaxValue) { // Work out the maximum width of all children that aren't fill parent sizeMeasured.Width = 0; foreach (var v in SubViews.Where(x => !x.Gone && x.LayoutParameters.WidthUnits != Units.ParentRatio)) { nfloat totalChildWidth = v.GetMeasuredSize().Width + v.LayoutParameters.Margins.TotalWidth(); if (totalChildWidth > sizeMeasured.Width) { sizeMeasured.Width = totalChildWidth; } } // Set the width of all children that are fill parent foreach (var v in SubViews.Where(x => !x.Gone && x.LayoutParameters.WidthUnits == Units.ParentRatio)) { v.Measure(sizeMeasured.Width, v.GetMeasuredSize().Height); } sizeMeasured.Width += Padding.TotalWidth(); } else { width += Padding.TotalWidth(); } if (height == nfloat.MaxValue) { height = totalFixedSize + totalVariableSize; } if (LayoutParameters.ParentIsScorllView(this)) { height = totalFixedSize + totalVariableSize; if (LayoutParameters.HeightUnits == Units.ParentRatio) { height = height < parentHeight ? parentHeight : height; } } // And finally, set our measure dimensions SetMeasuredSize(LayoutParameters.ResolveSize(new CGSize(width, height), sizeMeasured)); }