/// <summary> /// Overridden to provide measurement support for this native view /// </summary> /// <param name="parentWidth">Parent width.</param> /// <param name="parentHeight">Parent height.</param> protected override void onMeasure(nfloat parentWidth, nfloat parentHeight) { // Resolve width for absolute and parent ratio nfloat width = LayoutParameters.TryResolveWidth(this, parentWidth, parentHeight); nfloat height = LayoutParameters.TryResolveHeight(this, parentWidth, parentHeight); // Do we need to measure our content? CGSize sizeMeasured = CGSize.Empty; if (width == nfloat.MaxValue || height == nfloat.MaxValue) { CGSize sizeToFit = new CGSize(width, height); //sizeMeasured = Measurer!=null ? Measurer(_view, sizeToFit) : _view.SizeThatFits(sizeToFit); var size = _view.SizeThatFits(sizeToFit); if (LayoutParameters.MaxWidth != 0 && size.Width > LayoutParameters.MaxWidth) { size = _view.SizeThatFits(new CGSize(LayoutParameters.MaxWidth, height)); } sizeMeasured = Measurer != null?Measurer(_view, sizeToFit) : size; } // Set the measured size SetMeasuredSize(LayoutParameters.ResolveSize(new CGSize(width, height), sizeMeasured)); }
// Do measurement when in horizontal orientation private void MeasureHorizontal(nfloat parentWidth, nfloat parentHeight) { // Work out our height nfloat layoutWidth = LayoutParameters.TryResolveWidth(this, parentWidth, parentHeight); nfloat layoutHeight = LayoutParameters.TryResolveHeight(this, parentWidth, parentHeight); // Work out the total fixed size int visibleViewCount = 0; var paddings = Padding.TotalWidth(); _rows = new List <WrapRow>(); _goneViews = new List <View>(); var row = new WrapRow(); _rows.Add(row); Func <nfloat> spacing = () => visibleViewCount == 0 ? 0 : Spacing; foreach (var v in SubViews) { if (v.Gone) { _goneViews.Add(v); continue; } v.Measure(parentWidth - paddings - v.LayoutParameters.Margins.TotalWidth(), adjustLayoutHeight(layoutHeight, v)); var width = v.GetMeasuredSize().Width + v.LayoutParameters.Margins.TotalWidth(); if (row.Width + width + spacing() > parentWidth) { visibleViewCount = 0; var newRow = new WrapRow(); newRow.YPosition = row.YPosition + row.Height; row = newRow; _rows.Add(row); } row.Width += v.GetMeasuredSize().Width + v.LayoutParameters.Margins.TotalWidth() + spacing(); row.Height = NMath.Max(row.Height, v.GetMeasuredSize().Height); visibleViewCount++; layoutWidth = NMath.Max(layoutWidth, row.Width); row.Views.Add(v); } layoutHeight = row.YPosition + row.Height; CGSize sizeMeasured = CGSize.Empty; layoutHeight += Padding.TotalHeight(); layoutWidth += Padding.TotalWidth(); // And finally, set our measure dimensions SetMeasuredSize(LayoutParameters.ResolveSize(new CGSize(layoutWidth, layoutHeight), sizeMeasured)); }
/// <summary> /// Overridden to provide measurement support for this native view /// </summary> /// <param name="parentWidth">Parent width.</param> /// <param name="parentHeight">Parent height.</param> protected override void onMeasure(float parentWidth, float parentHeight) { // Resolve width for absolute and parent ratio float width = LayoutParameters.TryResolveWidth(this, parentWidth); float height = LayoutParameters.TryResolveHeight(this, parentHeight); // Do we need to measure our content? SizeF sizeMeasured = SizeF.Empty; if (_view != null && (width == float.MaxValue || height == float.MaxValue)) { SizeF sizeToFit = new SizeF(width, height); sizeMeasured = Measurer != null?Measurer(_view, sizeToFit) : _view.SizeThatFits(sizeToFit); } // Set the measured size SetMeasuredSize(LayoutParameters.ResolveSize(new SizeF(width, height), sizeMeasured)); }
// 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)); }
protected override void onMeasure(float parentWidth, float parentHeight) { var unresolved = new List <View>(); var width = LayoutParameters.TryResolveWidth(this, parentWidth); var height = LayoutParameters.TryResolveHeight(this, parentHeight); // Remove padding if (width != float.MaxValue) { width -= Padding.TotalWidth(); } if (height != float.MaxValue) { height -= Padding.TotalHeight(); } // Measure all subviews where both dimensions can be resolved bool haveResolvedSize = false; float maxWidth = 0, maxHeight = 0; foreach (var v in SubViews.Where(x => !x.Gone)) { // Try to resolve subview width var subViewWidth = float.MaxValue; if (v.LayoutParameters.WidthUnits == Units.ParentRatio) { if (width == float.MaxValue) { unresolved.Add(v); continue; } else { subViewWidth = width - v.LayoutParameters.Margins.TotalWidth(); } } // Try to resolve subview height var subViewHeight = float.MaxValue; if (v.LayoutParameters.HeightUnits == Units.ParentRatio) { if (height == float.MaxValue) { unresolved.Add(v); continue; } else { subViewHeight = height - v.LayoutParameters.Margins.TotalHeight(); } } // Measure it v.Measure(subViewWidth, subViewHeight); if (!haveResolvedSize) { maxWidth = v.GetMeasuredSize().Width + v.LayoutParameters.Margins.TotalWidth(); maxHeight = v.GetMeasuredSize().Height + v.LayoutParameters.Margins.TotalHeight(); haveResolvedSize = true; } else { maxWidth = Math.Max(maxWidth, v.GetMeasuredSize().Width + v.LayoutParameters.Margins.TotalWidth()); maxHeight = Math.Max(maxHeight, v.GetMeasuredSize().Height + v.LayoutParameters.Margins.TotalHeight()); } } // Now resolve the unresolved subviews by either using the dimensions of the view // that were resolved, or none were, use their natural size foreach (var v in unresolved) { var subViewWidth = float.MaxValue; if (v.LayoutParameters.WidthUnits == Units.ParentRatio && haveResolvedSize) { subViewWidth = maxWidth - v.LayoutParameters.Margins.TotalWidth(); } var subViewHeight = float.MaxValue; if (v.LayoutParameters.HeightUnits == Units.ParentRatio && haveResolvedSize) { subViewHeight = maxHeight - v.LayoutParameters.Margins.TotalHeight(); } // Measure it v.Measure(subViewWidth, subViewHeight); } SizeF sizeMeasured = SizeF.Empty; if (width == float.MaxValue) { sizeMeasured.Width = SubViews.Max(x => x.GetMeasuredSize().Width + x.LayoutParameters.Margins.TotalWidth()) + Padding.TotalWidth(); } if (height == float.MaxValue) { sizeMeasured.Height = SubViews.Max(x => x.GetMeasuredSize().Height + x.LayoutParameters.Margins.TotalHeight()) + Padding.TotalHeight(); } // Done! SetMeasuredSize(LayoutParameters.ResolveSize(new SizeF(width, height), sizeMeasured)); }
// Do measurement when in horizontal orientation private void MeasureHorizontal(nfloat parentWidth, nfloat parentHeight) { // Work out our height nfloat layoutWidth = LayoutParameters.TryResolveWidth(this, parentWidth, parentHeight); nfloat layoutHeight = LayoutParameters.TryResolveHeight(this, parentWidth, parentHeight); // Work out the total fixed size var paddings = Padding.TotalWidth(); _goneViews = new List <View>(); _arrangedViews = new View[RowDefinitions.Count, ColumnDefinitions.Count]; var columnWidthFillParentSubviews = new List <View>(); //calculating columns var minWidth = (nfloat)ColumnDefinitions.Sum(x => x.MinWidth); foreach (var v in SubViews.Where(x => !x.Gone)) { _arrangedViews[v.Row, v.Column] = v; var columnDefinition = ColumnDefinitions[v.Column]; var rowDefinition = RowDefinitions[v.Column]; nfloat width; if (columnDefinition.Width > 0) { width = columnDefinition.Width; } else if (columnDefinition.MaxWidth > 0) { width = columnDefinition.MaxWidth; } else { width = parentWidth - paddings; } nfloat height; if (rowDefinition.Height > 0) { height = rowDefinition.Height; } else { height = adjustLayoutHeight(layoutHeight, v); } if (v.LayoutParameters.WidthUnits != Units.ParentRatio) { v.Measure(width - v.LayoutParameters.Margins.TotalWidth(), height); } else { v._measuredSize = new CGSize(0, 0); v._measuredSizeValid = true; columnWidthFillParentSubviews.Add(v); } } { nfloat totalWeight = 0; nfloat totalWidth = 0; var columnId = -1; foreach (var column in ColumnDefinitions) { columnId++; column.CalculatedWidth = 0; if (column.Width > 0) { column.CalculatedWidth = column.Width; } else if (column.Width == AutoSize.WrapContent) { for (int rowId = 0; rowId < RowDefinitions.Count; rowId++) { var v = _arrangedViews[rowId, columnId]; if (v != null) { column.CalculatedWidth = NMath.Max(column.CalculatedWidth, v.GetMeasuredSize().Width + v.LayoutParameters.Margins.TotalWidth()); } } } else if (column.Width == AutoSize.FillParent) { totalWeight += column.Weight; } totalWidth += column.CalculatedWidth; } var room = layoutWidth - totalWidth; foreach (var column in ColumnDefinitions.Where(x => x.Width == AutoSize.FillParent)) { columnId++; column.CalculatedWidth = room * column.Weight / totalWeight; } } { var totalWeight = 0; var totalHeight = 0; var rowId = -1; foreach (var row in RowDefinitions) { rowId++; if (row.Height > 0) { row.CalculatedHeight = row.Height; continue; } if (row.Height == AutoSize.WrapContent) { row.CalculatedHeight = 0; for (int columnId = 0; columnId < ColumnDefinitions.Count; columnId++) { var v = _arrangedViews[rowId, columnId]; if (v != null) { row.CalculatedHeight = NMath.Max(row.CalculatedHeight, v.GetMeasuredSize().Height); } } } } var room = layoutHeight - totalHeight; foreach (var row in RowDefinitions.Where(x => x.Height == AutoSize.FillParent)) { row.CalculatedHeight = room * row.Weight / totalWeight; } } CGSize sizeMeasured = CGSize.Empty; foreach (var item in ColumnDefinitions) { sizeMeasured.Width += item.CalculatedWidth; } sizeMeasured.Width += ColSpacing * (ColumnDefinitions.Count - 1); foreach (var item in RowDefinitions) { sizeMeasured.Height += item.CalculatedHeight; } sizeMeasured.Height += RowSpacing * (RowDefinitions.Count - 1); foreach (var v in columnWidthFillParentSubviews) { v.Measure(ColumnDefinitions[v.Column].CalculatedWidth, RowDefinitions[v.Row].CalculatedHeight); } // And finally, set our measure dimensions SetMeasuredSize(LayoutParameters.ResolveSize(new CGSize(layoutWidth, layoutHeight), sizeMeasured)); }