public override void LayoutSubviews() { var oldSize = Frame.Size; #if ENABLE_DEBUG_LOG string debugIndent = String.Concat(Enumerable.Repeat(" ", numSuperviews(this))); LogLine($"{debugIndent}LayoutSubviews {GetHashCode()} {this.GetType()}"); #else const string debugIndent = ""; #endif base.LayoutSubviews(); this.UpdateLayout(); if (CurrentLayout == null) { return; } // Allow streched cells that are in an auto sized column or row only if there is at // least one non-stretched cell that starts that same column/row foreach (var cell in this.CurrentLayout.Cells) { if (cell.Position.Horizontal == Layout.Alignment.Stretched && this.CurrentLayout.ColumnDefinitions[cell.Position.Column].SizeType == Layout.SizeType.Auto && !this.CurrentLayout.Cells.Any(c => c.Position.Column == cell.Position.Column && c.Position.Horizontal != Layout.Alignment.Stretched)) { throw new Exception($"Grid {ID}: Stretched horizontal cell alignment on row {cell.Position.Row}, col {cell.Position.Column} cannot be used in an auto sized column when there is no other cell in that column that is not stretched"); } if (cell.Position.Vertical == Layout.Alignment.Stretched && this.CurrentLayout.RowDefinitions[cell.Position.Row].SizeType == Layout.SizeType.Auto && !this.CurrentLayout.Cells.Any(c => c.Position.Row == cell.Position.Row && c.Position.Vertical != Layout.Alignment.Stretched)) { throw new Exception($"Grid {ID}: Stretched vertical cell alignment on row {cell.Position.Row}, col {cell.Position.Column} cannot be used in an auto sized row when there is no other cell in that column that is not stretched"); } } #if ENABLE_DEBUG_LOG LogLine($"{debugIndent}Cells at start of layout:"); foreach (var cell in this.CurrentLayout.Cells) { LogLine($"{debugIndent} {cell}"); } #endif var horizontallyStretchedCells = this.CurrentLayout.Cells.Where(c => c.IncludeInAutoWidthSizeCalcs && c.View != null && c.Position.Horizontal == Layout.Alignment.Stretched); if (horizontallyStretchedCells.Any()) { LogLine($"{debugIndent} Setting width of horizontally stretched cells"); var widths1 = this.CurrentLayout.CalculateAbsoluteColumnWidth(this).Item2; foreach (var cell in horizontallyStretchedCells) { nfloat w = CalcSpanWidth(cell, widths1); LogLine($"{debugIndent} Setting cell.View Width to {w}"); nfloat width = w - cell.Position.Margin.Width(); if (RoundLayout) { width = width.RoundToScale(); } cell.View.SetWidth(width); LogLine($"{debugIndent} Before LayoutSubviews {cell.DebugLabel}"); cell.View.LayoutSubviews(); LogLine($"{debugIndent} After LayoutSubviews cell.View Size={cell.View.Frame.Size} {cell.DebugLabel}"); } } var verticallyStretchedCells = this.CurrentLayout.Cells.Where(c => c.IncludeInAutoWidthSizeCalcs && c.View != null && c.Position.Vertical == Layout.Alignment.Stretched); if (verticallyStretchedCells.Any()) { LogLine($"{debugIndent} Setting height of vertically stretched cells"); var heights1 = this.CurrentLayout.CalculateAbsoluteRowHeight(this).Item2; foreach (var cell in verticallyStretchedCells) { nfloat h = CalcSpanHeight(cell, heights1); LogLine($"{debugIndent} Setting cell.View Height to {h}"); nfloat height = h - cell.Position.Margin.Height(); if (RoundLayout) { height = height.RoundToScale(); } cell.View.SetHeight(height); LogLine($"{debugIndent} Before LayoutSubviews {cell.DebugLabel}"); cell.View.LayoutSubviews(); LogLine($"{debugIndent} After LayoutSubviews cell.View Size={cell.View.Frame.Size} {cell.DebugLabel}"); } } // Calculate row sizes var heights = this.CurrentLayout.CalculateAbsoluteRowHeight(this); nfloat gridHeight = heights.Item1; nfloat[] absoluteRowHeight = heights.Item2; LogLine($"{debugIndent} AutoHeight={AutoHeight}, gridHeight={gridHeight}, Frame.Height={Frame.Height}"); // Calculate column sizes var widths = this.CurrentLayout.CalculateAbsoluteColumnWidth(this); nfloat gridWidth = widths.Item1; nfloat[] absoluteColumnWidth = widths.Item2; LogLine($"{debugIndent} AutoWidth={AutoWidth} gridWidth={gridWidth}, Frame.Width={Frame.Width}"); var newGridFrame = new CGRect(Frame.Location, new CGSize(gridWidth, gridHeight)); LogLine($"{debugIndent} newGridFrame={newGridFrame}, old Frame={Frame}"); Frame = newGridFrame; LogLine($"{debugIndent} RowDefinitions = [{string.Join(",", this.CurrentLayout.RowDefinitions.Select(r => r.Size))}]"); LogLine($"{debugIndent} absoluteRowHeight = [{string.Join(",", absoluteRowHeight)}]"); LogLine($"{debugIndent} ColumnDefinitions = [{string.Join(",", this.CurrentLayout.ColumnDefinitions.Select(r => r.Size))}]"); LogLine($"{debugIndent} absoluteColumnWidth = [{string.Join(",", absoluteColumnWidth)}]"); // Calculate cell positions var positions = CalcCellAbsolutePositions(absoluteColumnWidth, absoluteRowHeight); // Layout subviews foreach (var cell in this.CurrentLayout.Cells) { LogLine(); LogLine($"{debugIndent} Laying out col {cell.Position.Column}, row {cell.Position.Row}, {cell.DebugLabel}"); if (!cell.IncludeInAutoWidthSizeCalcs && !cell.IncludeInAutoHeightSizeCalcs) { LogLine($"{debugIndent} skipping: View.Hidden=true and IncludeInAutoWidthSizeCalcs,IncludeInAutoHeightSizeCalcs false"); continue; } if (cell.Position.Row >= this.CurrentLayout.RowDefinitions.Count()) { throw new Exception($"Grid {ID}: a cell is defined at row {cell.Position.Row}, col {cell.Position.Column} but there are only {this.CurrentLayout.RowDefinitions.Count()} rows defined in the grid"); } if (cell.Position.Column >= this.CurrentLayout.ColumnDefinitions.Count()) { throw new Exception($"Grid {ID}: a cell is defined at row {cell.Position.Row}, col {cell.Position.Column} but there are only {this.CurrentLayout.ColumnDefinitions.Count()} columns defined in the grid"); } cell.View?.LayoutSubviews(); var position = positions[cell.Position.Column, cell.Position.Row]; var cellSize = GetCellAbsoluteSize(absoluteColumnWidth, absoluteRowHeight, cell.Position); var viewSize = cell.AutoSizeSize; LogLine($"{debugIndent} position = {position}"); LogLine($"{debugIndent} cellSize = {cellSize}"); LogLine($"{debugIndent} viewSize = {viewSize}"); if (viewSize.Width == 0 && viewSize.Height == 0) { viewSize = cell.InitialSize; LogLine($"{debugIndent} viewSize changed to cell.InitialSize = {viewSize}"); } LogLine($"{debugIndent} Alignment: Vertical={cell.Position.Vertical}, Horizontal={cell.Position.Horizontal}"); switch (cell.Position.Vertical) { case Layout.Alignment.Stretched: // Honor Margin.Top and Bottom position.Y += cell.Position.Margin.Top; cellSize.Height -= cell.Position.Margin.Height(); break; case Layout.Alignment.Center: // Honor Margin.Left and Right position.Y += (cellSize.Height / 2f) - (viewSize.Height / 2f) + cell.Position.Margin.Top / 2f - cell.Position.Margin.Bottom / 2f; cellSize.Height = viewSize.Height; break; case Layout.Alignment.Start: // Honor Margin.Top position.Y += cell.Position.Margin.Top; cellSize.Height = viewSize.Height; break; case Layout.Alignment.End: // Honor Margin.Bottom position.Y += cellSize.Height - viewSize.Height - cell.Position.Margin.Bottom; cellSize.Height = viewSize.Height; break; default: break; } switch (cell.Position.Horizontal) { case Layout.Alignment.Stretched: // Honor Margin.Left and Right position.X += cell.Position.Margin.Left; cellSize.Width -= cell.Position.Margin.Width(); break; case Layout.Alignment.Center: // Honor Margin.Left and Right position.X += (cellSize.Width / 2f) - (viewSize.Width / 2f) + cell.Position.Margin.Left / 2f - cell.Position.Margin.Right / 2f; cellSize.Width = viewSize.Width; break; case Layout.Alignment.Start: // Honor Margin.Left cellSize.Width = viewSize.Width; position.X += cell.Position.Margin.Left; break; case Layout.Alignment.End: // Honor Margin.Right position.X += cellSize.Width - viewSize.Width - cell.Position.Margin.Right; cellSize.Width = viewSize.Width; break; default: break; } if (cell.Position.NoResize || cell.Position.NoPosition) { cellSize = cell.AutoSizeSize; } if (cell.Position.NoPosition) { position = cell.View.Frame.Location; } var newFrame = new CGRect(position, cellSize); Log($"{debugIndent} newFrame={newFrame}, cell.View.Frame={cell.View?.Frame}"); if (newFrame != cell.View?.Frame) { Log(": UPDATE"); SetCellFrame(cell, newFrame); } LogLine(); Log($"{debugIndent} Finished {cell.DebugLabel}"); } LogLine(); OnLayoutCompleted(oldSize, Frame.Size); }