maui icon indicating copy to clipboard operation
maui copied to clipboard

Proposal: Adopt DensityValue in Grid to Enable Precise Pixel-Aware Layout

Open PureWeen opened this issue 7 months ago • 0 comments

Adopt DensityValue in Grid to Enable Precise Pixel-Aware Layout


Summary

This proposal introduces a new DensityValue struct to the .NET MAUI Grid layout engine to improve layout precision across density-independent units (dp) and ensure pixel-aligned rendering. It addresses layout inconsistencies caused by fractional pixel results, especially in high-DPI environments.


Problem Statement

In high-DPI environments, evenly dividing space in dp often results in fractional pixel values that don’t map cleanly to integers. For example:

  • A container with a width of 293.4dp at a density of 2.625 results in 770.175px.
  • Dividing this across 3 columns gives 256.725px per column.
  • Independent rounding can lead to 256 + 256 + 256 = 768, causing layout gaps or overflow.

Android mitigates this by accumulating rounding error and correcting it in the final element. MAUI Grid currently lacks this behavior, leading to:

  • Overlapping content
  • Jittery rendering
  • Clipped visuals

This is especially problematic with * (star) sizing, where users expect equal visual distribution.


Proposal

Introduce a DensityValue struct that tracks:

  • The original logical unit (dp)
  • The corresponding physical unit (px), based on current display density

This allows the Grid to:

  • Perform layout in dp for consistency
  • Internally track exact pixel dimensions
  • Accumulate and resolve rounding discrepancies (e.g., assign remainder pixels to the last column/row)
  • Avoid layout drift from naive float division

Benefits

  • More accurate star-based layouts
  • Eliminates layout jitter from float rounding
  • Aligns with native Android/iOS layout behavior
  • Enables future support for sub-pixel rendering or layout debugging

Implementation Details

  • Introduce a DensityValue struct with methods to resolve dp to px
  • Replace direct use of double/float in Grid layout calculations with DensityValue
  • Accumulate pixel widths and apply final rounding corrections at the row/column level
  • Initially keep the struct internal; consider public exposure later

Example Struct

struct DensityValue
{
    public double Dp { get; }
    public double Density { get; }

    public double RawPx => Dp * Density;

    private const double Epsilon = 0.00001;
}

Sample Scenarios

Scenario 1: 293.4dp Across 3 Columns (Density: 2.625)

  • Total px: 770.175
  • Ideal per column: 256.725px

Allocation:

  • Column 1: 256px
  • Column 2: 256px
  • Column 3: 258px ← absorbs rounding error
  • Total: 770px (0.175px under)

Scenario 2: 290dp Across 3 Columns (Density: 3.0)

  • Total px: 870
  • Ideal per column: 290px

Allocation:

  • Column 1: 290px
  • Column 2: 290px
  • Column 3: 290px
  • Total: 870px — perfect match

Scenario 3: 300dp Across 4 Columns (Density: 2.625)

  • Total px: 787.5
  • Ideal per column: 196.875px

Allocation:

  • Column 1: 196px
  • Column 2: 196px
  • Column 3: 196px
  • Column 4: 199px ← absorbs rounding error
  • Total: 787px (0.5px under)

Conclusion

A centralized mechanism like DensityValue ensures intentional, consistent handling of rounding errors, improving layout fidelity and aligning with platform-native expectations.

PureWeen avatar Jun 16 '25 22:06 PureWeen