More fixes

This commit is contained in:
2026-01-17 05:22:37 +00:00
parent f62d4aa5f2
commit 7d2ac327a3
58 changed files with 754 additions and 666 deletions

View File

@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Microsoft.Maui.Graphics;
using SkiaSharp;
namespace Microsoft.Maui.Platform;
@@ -64,8 +65,8 @@ public static class LinuxDialogService
{
foreach (var dialog in _activeDialogs)
{
dialog.Measure(new SKSize(bounds.Width, bounds.Height));
dialog.Arrange(bounds);
dialog.Measure(new Size(bounds.Width, bounds.Height));
dialog.Arrange(new Rect(bounds.Left, bounds.Top, bounds.Width, bounds.Height));
dialog.Draw(canvas);
}
}

View File

@@ -284,11 +284,11 @@ public class SkiaActivityIndicator : SkiaView
#region Layout
protected override SKSize MeasureOverride(SKSize availableSize)
protected override Size MeasureOverride(Size availableSize)
{
var size = (float)Size;
var strokeWidth = (float)StrokeWidth;
return new SKSize(size + strokeWidth * 2, size + strokeWidth * 2);
return new Size(size + strokeWidth * 2, size + strokeWidth * 2);
}
#endregion

View File

@@ -311,7 +311,7 @@ public class SkiaAlertDialog : SkiaView
_tcs.TrySetResult(result);
}
protected override SKSize MeasureOverride(SKSize availableSize)
protected override Size MeasureOverride(Size availableSize)
{
// Dialog takes full screen for the overlay
return availableSize;

View File

@@ -423,7 +423,7 @@ public class SkiaBorder : SkiaLayoutView
protected override SKRect GetContentBounds()
{
return GetContentBounds(Bounds);
return GetContentBounds(new SKRect((float)Bounds.Left, (float)Bounds.Top, (float)Bounds.Right, (float)Bounds.Bottom));
}
protected new SKRect GetContentBounds(SKRect bounds)
@@ -437,7 +437,7 @@ public class SkiaBorder : SkiaLayoutView
bounds.Bottom - (float)padding.Bottom - strokeThickness);
}
protected override SKSize MeasureOverride(SKSize availableSize)
protected override Size MeasureOverride(Size availableSize)
{
float strokeThickness = (float)StrokeThickness;
var padding = BorderPadding;
@@ -445,43 +445,43 @@ public class SkiaBorder : SkiaLayoutView
float paddingHeight = (float)(padding.Top + padding.Bottom) + strokeThickness * 2f;
// Respect explicit size requests
var requestedWidth = WidthRequest >= 0.0 ? (float)WidthRequest : availableSize.Width;
var requestedHeight = HeightRequest >= 0.0 ? (float)HeightRequest : availableSize.Height;
var requestedWidth = WidthRequest >= 0.0 ? (float)WidthRequest : (float)availableSize.Width;
var requestedHeight = HeightRequest >= 0.0 ? (float)HeightRequest : (float)availableSize.Height;
var childAvailable = new SKSize(
var childAvailable = new Size(
Math.Max(0f, requestedWidth - paddingWidth),
Math.Max(0f, requestedHeight - paddingHeight));
var maxChildSize = SKSize.Empty;
var maxChildSize = Size.Zero;
foreach (var child in Children)
{
var childSize = child.Measure(childAvailable);
maxChildSize = new SKSize(
maxChildSize = new Size(
Math.Max(maxChildSize.Width, childSize.Width),
Math.Max(maxChildSize.Height, childSize.Height));
}
// Use requested size if set, otherwise use child size + padding
var width = WidthRequest >= 0.0 ? (float)WidthRequest : maxChildSize.Width + paddingWidth;
var height = HeightRequest >= 0.0 ? (float)HeightRequest : maxChildSize.Height + paddingHeight;
var width = WidthRequest >= 0.0 ? (float)WidthRequest : (float)maxChildSize.Width + paddingWidth;
var height = HeightRequest >= 0.0 ? (float)HeightRequest : (float)maxChildSize.Height + paddingHeight;
return new SKSize(width, height);
return new Size(width, height);
}
protected override SKRect ArrangeOverride(SKRect bounds)
protected override Rect ArrangeOverride(Rect bounds)
{
var contentBounds = GetContentBounds(bounds);
var contentBounds = GetContentBounds(new SKRect((float)bounds.Left, (float)bounds.Top, (float)bounds.Right, (float)bounds.Bottom));
foreach (var child in Children)
{
// Apply child's margin
var margin = child.Margin;
var marginedBounds = new SKRect(
contentBounds.Left + (float)margin.Left,
contentBounds.Top + (float)margin.Top,
contentBounds.Right - (float)margin.Right,
contentBounds.Bottom - (float)margin.Bottom);
var marginedBounds = new Rect(
contentBounds.Left + margin.Left,
contentBounds.Top + margin.Top,
contentBounds.Width - margin.Left - margin.Right,
contentBounds.Height - margin.Top - margin.Bottom);
child.Arrange(marginedBounds);
}
@@ -515,7 +515,7 @@ public class SkiaBorder : SkiaLayoutView
if (IsVisible && IsEnabled)
{
var bounds = Bounds;
if (bounds.Contains(new SKPoint(x, y)))
if (bounds.Contains(x, y))
{
if (HasTapGestureRecognizers())
{

View File

@@ -103,19 +103,19 @@ public class SkiaBoxView : SkiaView
#region Measurement
protected override SKSize MeasureOverride(SKSize availableSize)
protected override Size MeasureOverride(Size availableSize)
{
// BoxView uses explicit size or a default size when in unbounded context
var width = WidthRequest >= 0 ? (float)WidthRequest :
(float.IsInfinity(availableSize.Width) ? 40f : availableSize.Width);
var height = HeightRequest >= 0 ? (float)HeightRequest :
(float.IsInfinity(availableSize.Height) ? 40f : availableSize.Height);
var width = WidthRequest >= 0 ? WidthRequest :
(double.IsInfinity(availableSize.Width) ? 40.0 : availableSize.Width);
var height = HeightRequest >= 0 ? HeightRequest :
(double.IsInfinity(availableSize.Height) ? 40.0 : availableSize.Height);
// Ensure no NaN values
if (float.IsNaN(width)) width = 40f;
if (float.IsNaN(height)) height = 40f;
if (double.IsNaN(width)) width = 40.0;
if (double.IsNaN(height)) height = 40.0;
return new SKSize(width, height);
return new Size(width, height);
}
#endregion

View File

@@ -940,7 +940,7 @@ public class SkiaButton : SkiaView, IButtonController
#region Measurement
protected override SKSize MeasureOverride(SKSize availableSize)
protected override Size MeasureOverride(Size availableSize)
{
var padding = Padding;
float paddingH = (float)(padding.Left + padding.Right);
@@ -1037,7 +1037,7 @@ public class SkiaButton : SkiaView, IButtonController
height = (float)HeightRequest;
}
return new SKSize(Math.Max(width, 44f), Math.Max(height, 30f));
return new Size(Math.Max(width, 44f), Math.Max(height, 30f));
}
#endregion

View File

@@ -204,39 +204,39 @@ public class SkiaCarouselView : SkiaLayoutView
private float GetOffsetForPosition(int position)
{
float itemWidth = Bounds.Width - (float)PeekAreaInsets * 2;
float itemWidth = (float)Bounds.Width - (float)PeekAreaInsets * 2;
return position * (itemWidth + (float)ItemSpacing);
}
private int GetPositionForOffset(float offset)
{
float itemWidth = Bounds.Width - (float)PeekAreaInsets * 2;
float itemWidth = (float)Bounds.Width - (float)PeekAreaInsets * 2;
if (itemWidth <= 0) return 0;
return Math.Clamp((int)Math.Round(offset / (itemWidth + (float)ItemSpacing)), 0, Math.Max(0, _items.Count - 1));
}
protected override SKSize MeasureOverride(SKSize availableSize)
protected override Size MeasureOverride(Size availableSize)
{
float itemWidth = availableSize.Width - (float)PeekAreaInsets * 2;
float itemHeight = availableSize.Height - (ShowIndicators ? 30 : 0);
float itemWidth = (float)availableSize.Width - (float)PeekAreaInsets * 2;
float itemHeight = (float)availableSize.Height - (ShowIndicators ? 30 : 0);
foreach (var item in _items)
{
item.Measure(new SKSize(itemWidth, itemHeight));
item.Measure(new Size(itemWidth, itemHeight));
}
return availableSize;
}
protected override SKRect ArrangeOverride(SKRect bounds)
protected override Rect ArrangeOverride(Rect bounds)
{
float itemWidth = bounds.Width - (float)PeekAreaInsets * 2;
float itemHeight = bounds.Height - (ShowIndicators ? 30 : 0);
float itemWidth = (float)bounds.Width - (float)PeekAreaInsets * 2;
float itemHeight = (float)bounds.Height - (ShowIndicators ? 30 : 0);
for (int i = 0; i < _items.Count; i++)
{
float x = bounds.Left + (float)PeekAreaInsets + i * (itemWidth + (float)ItemSpacing) - _scrollOffset;
var itemBounds = new SKRect(x, bounds.Top, x + itemWidth, bounds.Top + itemHeight);
float x = (float)bounds.Left + (float)PeekAreaInsets + i * (itemWidth + (float)ItemSpacing) - _scrollOffset;
var itemBounds = new Rect(x, bounds.Top, itemWidth, itemHeight);
_items[i].Arrange(itemBounds);
}
@@ -389,7 +389,7 @@ public class SkiaCarouselView : SkiaLayoutView
_isDragging = false;
// Determine target position based on velocity and position
float itemWidth = Bounds.Width - (float)PeekAreaInsets * 2;
float itemWidth = (float)Bounds.Width - (float)PeekAreaInsets * 2;
int targetPosition = GetPositionForOffset(_scrollOffset);
// Apply velocity influence

View File

@@ -431,10 +431,10 @@ public class SkiaCheckBox : SkiaView
#region Layout
protected override SKSize MeasureOverride(SKSize availableSize)
protected override Size MeasureOverride(Size availableSize)
{
var boxSize = (float)BoxSize;
return new SKSize(boxSize + 8f, boxSize + 8f);
var boxSize = BoxSize;
return new Size(boxSize + 8.0, boxSize + 8.0);
}
#endregion

View File

@@ -420,10 +420,10 @@ public class SkiaCollectionView : SkiaItemsView
{
try
{
var availableSize = new SKSize(bounds.Width, float.MaxValue);
var availableSize = new Size(bounds.Width, float.MaxValue);
var measuredSize = itemView.Measure(availableSize);
var rawHeight = measuredSize.Height;
var rawHeight = (float)measuredSize.Height;
if (float.IsNaN(rawHeight) || float.IsInfinity(rawHeight) || rawHeight > 10000f)
{
rawHeight = ItemHeight;
@@ -437,7 +437,7 @@ public class SkiaCollectionView : SkiaItemsView
}
var actualBounds = new SKRect(bounds.Left, bounds.Top, bounds.Right, bounds.Top + measuredHeight);
itemView.Arrange(actualBounds);
itemView.Arrange(new Rect(actualBounds.Left, actualBounds.Top, actualBounds.Width, actualBounds.Height));
itemView.Draw(canvas);
if (isSelected)

View File

@@ -125,42 +125,42 @@ public class SkiaContentPresenter : SkiaView
Content?.Draw(canvas);
}
protected override SKSize MeasureOverride(SKSize availableSize)
protected override Size MeasureOverride(Size availableSize)
{
var padding = Padding;
var paddingLeft = (float)padding.Left;
var paddingTop = (float)padding.Top;
var paddingRight = (float)padding.Right;
var paddingBottom = (float)padding.Bottom;
var paddingLeft = padding.Left;
var paddingTop = padding.Top;
var paddingRight = padding.Right;
var paddingBottom = padding.Bottom;
if (Content == null)
return new SKSize(paddingLeft + paddingRight, paddingTop + paddingBottom);
return new Size(paddingLeft + paddingRight, paddingTop + paddingBottom);
// When alignment is not Fill, give content unlimited size in that dimension
// so it can measure its natural size without truncation
var measureWidth = HorizontalContentAlignment == LayoutAlignment.Fill
? Math.Max(0, availableSize.Width - paddingLeft - paddingRight)
? (float)Math.Max(0, availableSize.Width - paddingLeft - paddingRight)
: float.PositiveInfinity;
var measureHeight = VerticalContentAlignment == LayoutAlignment.Fill
? Math.Max(0, availableSize.Height - paddingTop - paddingBottom)
? (float)Math.Max(0, availableSize.Height - paddingTop - paddingBottom)
: float.PositiveInfinity;
var contentSize = Content.Measure(new SKSize(measureWidth, measureHeight));
return new SKSize(
var contentSize = Content.Measure(new Size(measureWidth, measureHeight));
return new Size(
contentSize.Width + paddingLeft + paddingRight,
contentSize.Height + paddingTop + paddingBottom);
}
protected override SKRect ArrangeOverride(SKRect bounds)
protected override Rect ArrangeOverride(Rect bounds)
{
if (Content != null)
{
var padding = Padding;
var contentBounds = new SKRect(
bounds.Left + (float)padding.Left,
bounds.Top + (float)padding.Top,
bounds.Right - (float)padding.Right,
bounds.Bottom - (float)padding.Bottom);
var contentBounds = new Rect(
bounds.Left + padding.Left,
bounds.Top + padding.Top,
bounds.Width - padding.Left - padding.Right,
bounds.Height - padding.Top - padding.Bottom);
// Apply alignment
var contentSize = Content.DesiredSize;
@@ -171,12 +171,12 @@ public class SkiaContentPresenter : SkiaView
return bounds;
}
private static SKRect ApplyAlignment(SKRect availableBounds, SKSize contentSize, LayoutAlignment horizontal, LayoutAlignment vertical)
private static Rect ApplyAlignment(Rect availableBounds, Size contentSize, LayoutAlignment horizontal, LayoutAlignment vertical)
{
float x = availableBounds.Left;
float y = availableBounds.Top;
float width = horizontal == LayoutAlignment.Fill ? availableBounds.Width : contentSize.Width;
float height = vertical == LayoutAlignment.Fill ? availableBounds.Height : contentSize.Height;
double x = availableBounds.Left;
double y = availableBounds.Top;
double width = horizontal == LayoutAlignment.Fill ? availableBounds.Width : contentSize.Width;
double height = vertical == LayoutAlignment.Fill ? availableBounds.Height : contentSize.Height;
// Horizontal alignment
switch (horizontal)
@@ -200,7 +200,7 @@ public class SkiaContentPresenter : SkiaView
break;
}
return new SKRect(x, y, x + width, y + height);
return new Rect(x, y, width, height);
}
public override SkiaView? HitTest(float x, float y)

View File

@@ -299,7 +299,8 @@ public class SkiaDatePicker : SkiaView
{
if (_isOpen)
{
DrawCalendar(canvas, ScreenBounds);
var skScreenBounds = new SKRect((float)ScreenBounds.Left, (float)ScreenBounds.Top, (float)(ScreenBounds.Left + ScreenBounds.Width), (float)(ScreenBounds.Top + ScreenBounds.Height));
DrawCalendar(canvas, skScreenBounds);
}
}
@@ -579,7 +580,7 @@ public class SkiaDatePicker : SkiaView
if (IsOpen)
{
SKRect screenBounds = ScreenBounds;
SKRect screenBounds = new SKRect((float)ScreenBounds.Left, (float)ScreenBounds.Top, (float)(ScreenBounds.Left + ScreenBounds.Width), (float)(ScreenBounds.Top + ScreenBounds.Height));
SKRect calendarRect = GetCalendarRect(screenBounds);
SKRect headerRect = new SKRect(calendarRect.Left, calendarRect.Top, calendarRect.Right, calendarRect.Top + 48f);
@@ -680,14 +681,14 @@ public class SkiaDatePicker : SkiaView
}
}
protected override SKSize MeasureOverride(SKSize availableSize)
protected override Size MeasureOverride(Size availableSize)
{
return new SKSize(availableSize.Width < float.MaxValue ? Math.Min(availableSize.Width, 200f) : 200f, 40f);
return new Size(availableSize.Width < double.MaxValue ? Math.Min(availableSize.Width, 200.0) : 200.0, 40.0);
}
protected override bool HitTestPopupArea(float x, float y)
{
SKRect screenBounds = ScreenBounds;
SKRect screenBounds = new SKRect((float)ScreenBounds.Left, (float)ScreenBounds.Top, (float)(ScreenBounds.Left + ScreenBounds.Width), (float)(ScreenBounds.Top + ScreenBounds.Height));
if (screenBounds.Contains(x, y))
{
return true;

View File

@@ -1075,9 +1075,9 @@ public class SkiaEditor : SkiaView, IInputContext
{
_scrollOffsetY = cursorY;
}
else if (cursorY + lineSpacing > _scrollOffsetY + viewHeight)
else if (cursorY + lineSpacing > _scrollOffsetY + (float)viewHeight)
{
_scrollOffsetY = cursorY + lineSpacing - viewHeight;
_scrollOffsetY = cursorY + lineSpacing - (float)viewHeight;
}
}
@@ -1377,7 +1377,7 @@ public class SkiaEditor : SkiaView, IInputContext
var lineHeight = (float)LineHeight;
var lineSpacing = fontSize * lineHeight;
var totalHeight = _lines.Count * lineSpacing;
var viewHeight = Bounds.Height - (float)(Padding.Top + Padding.Bottom);
var viewHeight = (float)Bounds.Height - (float)(Padding.Top + Padding.Bottom);
var maxScroll = Math.Max(0, totalHeight - viewHeight);
_scrollOffsetY = Math.Clamp(_scrollOffsetY - e.DeltaY * 3, 0, maxScroll);
@@ -1578,22 +1578,22 @@ public class SkiaEditor : SkiaView, IInputContext
_inputMethodService.SetCursorLocation(x, y, 2, height);
}
protected override SKSize MeasureOverride(SKSize availableSize)
protected override Size MeasureOverride(Size availableSize)
{
if (AutoSize)
{
var fontSize = (float)FontSize;
var lineHeight = (float)LineHeight;
var lineSpacing = fontSize * lineHeight;
var verticalPadding = (float)(Padding.Top + Padding.Bottom);
var verticalPadding = Padding.Top + Padding.Bottom;
var height = Math.Max(lineSpacing + verticalPadding, _lines.Count * lineSpacing + verticalPadding);
return new SKSize(
availableSize.Width < float.MaxValue ? availableSize.Width : 200,
(float)Math.Min(height, availableSize.Height < float.MaxValue ? availableSize.Height : 200));
return new Size(
availableSize.Width < double.MaxValue ? availableSize.Width : 200,
Math.Min(height, availableSize.Height < double.MaxValue ? availableSize.Height : 200));
}
return new SKSize(
availableSize.Width < float.MaxValue ? Math.Min(availableSize.Width, 200) : 200,
availableSize.Height < float.MaxValue ? Math.Min(availableSize.Height, 150) : 150);
return new Size(
availableSize.Width < double.MaxValue ? Math.Min(availableSize.Width, 200) : 200,
availableSize.Height < double.MaxValue ? Math.Min(availableSize.Height, 150) : 150);
}
}

View File

@@ -1367,8 +1367,8 @@ public class SkiaEntry : SkiaView, IInputContext
{
var clearButtonSize = 20f;
var clearButtonMargin = 8f;
var clearCenterX = Bounds.Right - clearButtonMargin - clearButtonSize / 2;
var clearCenterY = Bounds.MidY;
var clearCenterX = (float)(Bounds.Left + Bounds.Width) - clearButtonMargin - clearButtonSize / 2;
var clearCenterY = (float)(Bounds.Top + Bounds.Height / 2);
var dx = e.X - clearCenterX;
var dy = e.Y - clearCenterY;
@@ -1385,7 +1385,7 @@ public class SkiaEntry : SkiaView, IInputContext
// Calculate cursor position from click using screen coordinates
var screenBounds = ScreenBounds;
var clickX = e.X - screenBounds.Left - (float)Padding.Left + _scrollOffset;
var clickX = e.X - (float)screenBounds.Left - (float)Padding.Left + _scrollOffset;
_cursorPosition = GetCharacterIndexAtX(clickX);
// Check for double-click (select word)
@@ -1446,7 +1446,7 @@ public class SkiaEntry : SkiaView, IInputContext
// Extend selection to current mouse position
var screenBounds = ScreenBounds;
var clickX = e.X - screenBounds.Left - (float)Padding.Left + _scrollOffset;
var clickX = e.X - (float)screenBounds.Left - (float)Padding.Left + _scrollOffset;
var newPosition = GetCharacterIndexAtX(clickX);
if (newPosition != _cursorPosition)
@@ -1675,7 +1675,7 @@ public class SkiaEntry : SkiaView, IInputContext
_inputMethodService.SetCursorLocation(x, y, 2, height);
}
protected override SKSize MeasureOverride(SKSize availableSize)
protected override Size MeasureOverride(Size availableSize)
{
var fontStyle = GetFontStyle();
var typeface = SkiaRenderingEngine.Current?.ResourceCache.GetTypeface(GetEffectiveFontFamily(), fontStyle)
@@ -1688,9 +1688,9 @@ public class SkiaEntry : SkiaView, IInputContext
var metrics = font.Metrics;
var textHeight = metrics.Descent - metrics.Ascent + metrics.Leading;
return new SKSize(
return new Size(
200, // Default width, will be overridden by layout
textHeight + (float)Padding.Top + (float)Padding.Bottom + (float)BorderWidth * 2);
textHeight + Padding.Top + Padding.Bottom + BorderWidth * 2);
}
}

View File

@@ -88,34 +88,36 @@ public class SkiaFlexLayout : SkiaLayoutView
public static FlexAlignSelf GetAlignSelf(SkiaView view) => (FlexAlignSelf)view.GetValue(AlignSelfProperty);
public static void SetAlignSelf(SkiaView view, FlexAlignSelf value) => view.SetValue(AlignSelfProperty, value);
protected override SKSize MeasureOverride(SKSize availableSize)
protected override Size MeasureOverride(Size availableSize)
{
bool isRow = Direction == FlexDirection.Row || Direction == FlexDirection.RowReverse;
float totalMain = 0f;
float maxCross = 0f;
var sizeAvailable = new Size(availableSize.Width, availableSize.Height);
foreach (var child in Children)
{
if (!child.IsVisible)
continue;
var childSize = child.Measure(availableSize);
var childSize = child.Measure(sizeAvailable);
if (isRow)
{
totalMain += childSize.Width;
maxCross = Math.Max(maxCross, childSize.Height);
totalMain += (float)childSize.Width;
maxCross = Math.Max(maxCross, (float)childSize.Height);
}
else
{
totalMain += childSize.Height;
maxCross = Math.Max(maxCross, childSize.Width);
totalMain += (float)childSize.Height;
maxCross = Math.Max(maxCross, (float)childSize.Width);
}
}
return isRow ? new SKSize(totalMain, maxCross) : new SKSize(maxCross, totalMain);
return isRow ? new Size(totalMain, maxCross) : new Size(maxCross, totalMain);
}
protected override SKRect ArrangeOverride(SKRect bounds)
protected override Rect ArrangeOverride(Rect bounds)
{
if (Children.Count == 0)
return bounds;
@@ -127,10 +129,10 @@ public class SkiaFlexLayout : SkiaLayoutView
if (orderedChildren.Count == 0)
return bounds;
float mainSize = isRow ? bounds.Width : bounds.Height;
float crossSize = isRow ? bounds.Height : bounds.Width;
float mainSize = isRow ? (float)bounds.Width : (float)bounds.Height;
float crossSize = isRow ? (float)bounds.Height : (float)bounds.Width;
var childInfos = new List<(SkiaView child, SKSize size, float grow, float shrink)>();
var childInfos = new List<(SkiaView child, Size size, float grow, float shrink)>();
float totalBasis = 0f;
float totalGrow = 0f;
float totalShrink = 0f;
@@ -141,21 +143,21 @@ public class SkiaFlexLayout : SkiaLayoutView
float grow = GetGrow(child);
float shrink = GetShrink(child);
SKSize size;
Size size;
if (basis.IsAuto)
{
size = child.Measure(new SKSize(bounds.Width, bounds.Height));
size = child.Measure(new Size(bounds.Width, bounds.Height));
}
else
{
float length = basis.Length;
size = isRow
? child.Measure(new SKSize(length, bounds.Height))
: child.Measure(new SKSize(bounds.Width, length));
? child.Measure(new Size(length, bounds.Height))
: child.Measure(new Size(bounds.Width, length));
}
childInfos.Add((child, size, grow, shrink));
totalBasis += isRow ? size.Width : size.Height;
totalBasis += isRow ? (float)size.Width : (float)size.Height;
totalGrow += grow;
totalShrink += shrink;
}
@@ -165,8 +167,8 @@ public class SkiaFlexLayout : SkiaLayoutView
var resolvedSizes = new List<(SkiaView child, float mainSize, float crossSize)>();
foreach (var (child, size, grow, shrink) in childInfos)
{
float childMainSize = isRow ? size.Width : size.Height;
float childCrossSize = isRow ? size.Height : size.Width;
float childMainSize = isRow ? (float)size.Width : (float)size.Height;
float childCrossSize = isRow ? (float)size.Height : (float)size.Width;
if (freeSpace > 0f && totalGrow > 0f)
{
@@ -183,7 +185,7 @@ public class SkiaFlexLayout : SkiaLayoutView
float usedSpace = resolvedSizes.Sum(s => s.mainSize);
float remainingSpace = Math.Max(0f, mainSize - usedSpace);
float position = isRow ? bounds.Left : bounds.Top;
float position = isRow ? (float)bounds.Left : (float)bounds.Top;
float spacing = 0f;
switch (JustifyContent)
@@ -221,13 +223,13 @@ public class SkiaFlexLayout : SkiaLayoutView
var alignSelf = GetAlignSelf(child);
var effectiveAlign = alignSelf == FlexAlignSelf.Auto ? AlignItems : (FlexAlignItems)alignSelf;
float crossPos = isRow ? bounds.Top : bounds.Left;
float crossPos = isRow ? (float)bounds.Top : (float)bounds.Left;
float finalCrossSize = childCrossSize;
switch (effectiveAlign)
{
case FlexAlignItems.End:
crossPos = (isRow ? bounds.Bottom : bounds.Right) - finalCrossSize;
crossPos = (isRow ? (float)bounds.Bottom : (float)bounds.Right) - finalCrossSize;
break;
case FlexAlignItems.Center:
crossPos += (crossSize - finalCrossSize) / 2f;
@@ -237,14 +239,14 @@ public class SkiaFlexLayout : SkiaLayoutView
break;
}
SKRect childBounds;
Rect childBounds;
if (isRow)
{
childBounds = new SKRect(position, crossPos, position + childMainSize, crossPos + finalCrossSize);
childBounds = new Rect(position, crossPos, childMainSize, finalCrossSize);
}
else
{
childBounds = new SKRect(crossPos, position, crossPos + finalCrossSize, position + childMainSize);
childBounds = new Rect(crossPos, position, finalCrossSize, childMainSize);
}
child.Arrange(childBounds);

View File

@@ -154,40 +154,36 @@ public class SkiaFlyoutPage : SkiaLayoutView
/// </summary>
public event EventHandler? IsPresentedChanged;
protected override SKSize MeasureOverride(SKSize availableSize)
protected override Size MeasureOverride(Size availableSize)
{
// Measure flyout
if (_flyout != null)
{
_flyout.Measure(new SKSize(FlyoutWidth, availableSize.Height));
_flyout.Measure(new Size(FlyoutWidth, availableSize.Height));
}
// Measure detail to full size
if (_detail != null)
{
_detail.Measure(availableSize);
_detail.Measure(new Size(availableSize.Width, availableSize.Height));
}
return availableSize;
}
protected override SKRect ArrangeOverride(SKRect bounds)
protected override Rect ArrangeOverride(Rect bounds)
{
// Arrange detail to fill the entire area
if (_detail != null)
{
_detail.Arrange(bounds);
_detail.Arrange(new Rect(bounds.Left, bounds.Top, bounds.Width, bounds.Height));
}
// Arrange flyout (positioned based on animation progress)
if (_flyout != null)
{
float flyoutX = bounds.Left - FlyoutWidth + (FlyoutWidth * _flyoutAnimationProgress);
var flyoutBounds = new SKRect(
flyoutX,
bounds.Top,
flyoutX + FlyoutWidth,
bounds.Bottom);
float flyoutX = (float)bounds.Left - FlyoutWidth + (FlyoutWidth * _flyoutAnimationProgress);
var flyoutBounds = new Rect(flyoutX, bounds.Top, FlyoutWidth, bounds.Height);
_flyout.Arrange(flyoutBounds);
}
@@ -211,7 +207,8 @@ public class SkiaFlyoutPage : SkiaLayoutView
Color = _scrimColorSK.WithAlpha((byte)(_scrimColorSK.Alpha * _flyoutAnimationProgress)),
Style = SKPaintStyle.Fill
};
canvas.DrawRect(Bounds, scrimPaint);
var skBounds = new SKRect((float)Bounds.Left, (float)Bounds.Top, (float)(Bounds.Left + Bounds.Width), (float)(Bounds.Top + Bounds.Height));
canvas.DrawRect(skBounds, scrimPaint);
// Draw flyout shadow
if (_flyout != null && ShadowWidth > 0)
@@ -230,12 +227,12 @@ public class SkiaFlyoutPage : SkiaLayoutView
{
if (_flyout == null) return;
float shadowRight = _flyout.Bounds.Right;
float shadowRight = (float)(_flyout.Bounds.Left + _flyout.Bounds.Width);
var shadowRect = new SKRect(
shadowRight,
Bounds.Top,
(float)Bounds.Top,
shadowRight + ShadowWidth,
Bounds.Bottom);
(float)(Bounds.Top + Bounds.Height));
using var shadowPaint = new SKPaint
{

View File

@@ -49,17 +49,17 @@ public class SkiaGraphicsView : SkiaView
}
}
protected override SKSize MeasureOverride(SKSize availableSize)
protected override Size MeasureOverride(Size availableSize)
{
// Graphics view takes all available space by default
if (availableSize.Width < float.MaxValue && availableSize.Height < float.MaxValue)
if (availableSize.Width < double.MaxValue && availableSize.Height < double.MaxValue)
{
return availableSize;
}
// Return a reasonable default size
return new SKSize(
availableSize.Width < float.MaxValue ? availableSize.Width : 100,
availableSize.Height < float.MaxValue ? availableSize.Height : 100);
return new Size(
availableSize.Width < double.MaxValue ? availableSize.Width : 100,
availableSize.Height < double.MaxValue ? availableSize.Height : 100);
}
}

View File

@@ -1028,7 +1028,7 @@ public class SkiaImage : SkiaView
Invalidate();
}
public override void Arrange(SKRect bounds)
public override void Arrange(Rect bounds)
{
base.Arrange(bounds);
@@ -1037,21 +1037,21 @@ public class SkiaImage : SkiaView
{
if (_isSvg && !string.IsNullOrEmpty(_currentFilePath) && !_isLoading)
{
float width = bounds.Width;
float height = bounds.Height;
float width = (float)bounds.Width;
float height = (float)bounds.Height;
if ((width > _svgLoadedWidth * 1.1 || height > _svgLoadedHeight * 1.1) &&
width > 0f && height > 0f &&
(width != _lastArrangedBounds.Width || height != _lastArrangedBounds.Height))
{
_lastArrangedBounds = bounds;
_lastArrangedBounds = new SKRect((float)bounds.Left, (float)bounds.Top, (float)bounds.Right, (float)bounds.Bottom);
_ = LoadSvgAtSizeAsync(_currentFilePath, width, height);
}
}
}
}
protected override SKRect ArrangeOverride(SKRect bounds)
protected override Rect ArrangeOverride(Rect bounds)
{
var desiredWidth = DesiredSize.Width;
var desiredHeight = DesiredSize.Height;
@@ -1059,38 +1059,38 @@ public class SkiaImage : SkiaView
if (desiredWidth > 0 && desiredHeight > 0 &&
(desiredWidth < bounds.Width || desiredHeight < bounds.Height))
{
float finalWidth = Math.Min(desiredWidth, bounds.Width);
float finalHeight = Math.Min(desiredHeight, bounds.Height);
double finalWidth = Math.Min(desiredWidth, bounds.Width);
double finalHeight = Math.Min(desiredHeight, bounds.Height);
float x = bounds.Left;
double x = bounds.Left;
var hAlignValue = (int)HorizontalOptions.Alignment;
if (hAlignValue == 1) x = bounds.Left + (bounds.Width - finalWidth) / 2;
else if (hAlignValue == 2) x = bounds.Right - finalWidth;
float y = bounds.Top;
double y = bounds.Top;
var vAlignValue = (int)VerticalOptions.Alignment;
if (vAlignValue == 1) y = bounds.Top + (bounds.Height - finalHeight) / 2;
else if (vAlignValue == 2) y = bounds.Bottom - finalHeight;
return new SKRect(x, y, x + finalWidth, y + finalHeight);
return new Rect(x, y, finalWidth, finalHeight);
}
return bounds;
}
protected override SKSize MeasureOverride(SKSize availableSize)
protected override Size MeasureOverride(Size availableSize)
{
double widthRequest = base.WidthRequest;
double heightRequest = base.HeightRequest;
if (widthRequest > 0.0 && heightRequest > 0.0)
return new SKSize((float)widthRequest, (float)heightRequest);
return new Size(widthRequest, heightRequest);
if (_image == null)
{
if (widthRequest > 0.0) return new SKSize((float)widthRequest, (float)widthRequest);
if (heightRequest > 0.0) return new SKSize((float)heightRequest, (float)heightRequest);
return new SKSize(100f, 100f);
if (widthRequest > 0.0) return new Size(widthRequest, widthRequest);
if (heightRequest > 0.0) return new Size(heightRequest, heightRequest);
return new Size(100.0, 100.0);
}
float imageWidth = _image.Width;
@@ -1098,35 +1098,35 @@ public class SkiaImage : SkiaView
if (widthRequest > 0.0)
{
float scale = (float)widthRequest / imageWidth;
return new SKSize((float)widthRequest, imageHeight * scale);
double scale = widthRequest / imageWidth;
return new Size(widthRequest, imageHeight * scale);
}
if (heightRequest > 0.0)
{
float scale = (float)heightRequest / imageHeight;
return new SKSize(imageWidth * scale, (float)heightRequest);
double scale = heightRequest / imageHeight;
return new Size(imageWidth * scale, heightRequest);
}
if (availableSize.Width < float.MaxValue && availableSize.Height < float.MaxValue)
if (availableSize.Width < double.MaxValue && availableSize.Height < double.MaxValue)
{
float scale = Math.Min(availableSize.Width / imageWidth, availableSize.Height / imageHeight);
return new SKSize(imageWidth * scale, imageHeight * scale);
double scale = Math.Min(availableSize.Width / imageWidth, availableSize.Height / imageHeight);
return new Size(imageWidth * scale, imageHeight * scale);
}
if (availableSize.Width < float.MaxValue)
if (availableSize.Width < double.MaxValue)
{
float scale = availableSize.Width / imageWidth;
return new SKSize(availableSize.Width, imageHeight * scale);
double scale = availableSize.Width / imageWidth;
return new Size(availableSize.Width, imageHeight * scale);
}
if (availableSize.Height < float.MaxValue)
if (availableSize.Height < double.MaxValue)
{
float scale = availableSize.Height / imageHeight;
return new SKSize(imageWidth * scale, availableSize.Height);
double scale = availableSize.Height / imageHeight;
return new Size(imageWidth * scale, availableSize.Height);
}
return new SKSize(imageWidth, imageHeight);
return new Size(imageWidth, imageHeight);
}
protected override void Dispose(bool disposing)

View File

@@ -641,7 +641,7 @@ public class SkiaImageButton : SkiaView
Released?.Invoke(this, EventArgs.Empty);
if (wasPressed && Bounds.Contains(new SKPoint(e.X, e.Y)))
if (wasPressed && Bounds.Contains(e.X, e.Y))
{
Clicked?.Invoke(this, EventArgs.Empty);
ExecuteCommand();
@@ -687,66 +687,65 @@ public class SkiaImageButton : SkiaView
#region Layout
protected override SKSize MeasureOverride(SKSize availableSize)
protected override Size MeasureOverride(Size availableSize)
{
var padding = Padding;
var paddingWidth = (float)(padding.Left + padding.Right);
var paddingHeight = (float)(padding.Top + padding.Bottom);
var paddingWidth = padding.Left + padding.Right;
var paddingHeight = padding.Top + padding.Bottom;
// Respect explicit WidthRequest/HeightRequest first (MAUI standard behavior)
if (WidthRequest > 0 && HeightRequest > 0)
{
return new SKSize((float)WidthRequest, (float)HeightRequest);
return new Size(WidthRequest, HeightRequest);
}
if (WidthRequest > 0)
{
// Fixed width, calculate height from aspect ratio or use width
float height = HeightRequest > 0 ? (float)HeightRequest
: _image != null ? (float)WidthRequest * _image.Height / _image.Width
: (float)WidthRequest;
return new SKSize((float)WidthRequest, height);
double height = HeightRequest > 0 ? HeightRequest
: _image != null ? WidthRequest * _image.Height / _image.Width
: WidthRequest;
return new Size(WidthRequest, height);
}
if (HeightRequest > 0)
{
// Fixed height, calculate width from aspect ratio or use height
float width = WidthRequest > 0 ? (float)WidthRequest
: _image != null ? (float)HeightRequest * _image.Width / _image.Height
: (float)HeightRequest;
return new SKSize(width, (float)HeightRequest);
double width = WidthRequest > 0 ? WidthRequest
: _image != null ? HeightRequest * _image.Width / _image.Height
: HeightRequest;
return new Size(width, HeightRequest);
}
// No explicit size - calculate from content
if (_image == null)
return new SKSize(44 + paddingWidth, 44 + paddingHeight); // Default touch target size
return new Size(44 + paddingWidth, 44 + paddingHeight); // Default touch target size
var imageWidth = _image.Width;
var imageHeight = _image.Height;
if (availableSize.Width < float.MaxValue && availableSize.Height < float.MaxValue)
if (availableSize.Width < double.MaxValue && availableSize.Height < double.MaxValue)
{
var availableContent = new SKSize(
availableSize.Width - paddingWidth,
availableSize.Height - paddingHeight);
var scale = Math.Min(availableContent.Width / imageWidth, availableContent.Height / imageHeight);
return new SKSize(imageWidth * scale + paddingWidth, imageHeight * scale + paddingHeight);
var availableContentW = availableSize.Width - paddingWidth;
var availableContentH = availableSize.Height - paddingHeight;
var scale = Math.Min(availableContentW / imageWidth, availableContentH / imageHeight);
return new Size(imageWidth * scale + paddingWidth, imageHeight * scale + paddingHeight);
}
else if (availableSize.Width < float.MaxValue)
else if (availableSize.Width < double.MaxValue)
{
var availableWidth = availableSize.Width - paddingWidth;
var scale = availableWidth / imageWidth;
return new SKSize(availableSize.Width, imageHeight * scale + paddingHeight);
return new Size(availableSize.Width, imageHeight * scale + paddingHeight);
}
else if (availableSize.Height < float.MaxValue)
else if (availableSize.Height < double.MaxValue)
{
var availableHeight = availableSize.Height - paddingHeight;
var scale = availableHeight / imageHeight;
return new SKSize(imageWidth * scale + paddingWidth, availableSize.Height);
return new Size(imageWidth * scale + paddingWidth, availableSize.Height);
}
return new SKSize(imageWidth + paddingWidth, imageHeight + paddingHeight);
return new Size(imageWidth + paddingWidth, imageHeight + paddingHeight);
}
protected override SKRect ArrangeOverride(SKRect bounds)
protected override Rect ArrangeOverride(Rect bounds)
{
// If we have explicit size requests, constrain to desired size
// This follows MAUI standard behavior - controls respect WidthRequest/HeightRequest
@@ -757,12 +756,12 @@ public class SkiaImageButton : SkiaView
if (desiredWidth > 0 && desiredHeight > 0 &&
(desiredWidth < bounds.Width || desiredHeight < bounds.Height))
{
float finalWidth = Math.Min(desiredWidth, bounds.Width);
float finalHeight = Math.Min(desiredHeight, bounds.Height);
double finalWidth = Math.Min(desiredWidth, bounds.Width);
double finalHeight = Math.Min(desiredHeight, bounds.Height);
// Calculate position based on HorizontalOptions
// LayoutAlignment: Start=0, Center=1, End=2, Fill=3
float x = bounds.Left;
double x = bounds.Left;
var hAlignValue = (int)HorizontalOptions.Alignment;
if (hAlignValue == 1) // Center
{
@@ -775,7 +774,7 @@ public class SkiaImageButton : SkiaView
// Fill (3) and Start (0) both use x = bounds.Left
// Calculate position based on VerticalOptions
float y = bounds.Top;
double y = bounds.Top;
var vAlignValue = (int)VerticalOptions.Alignment;
if (vAlignValue == 1) // Center
{
@@ -787,7 +786,7 @@ public class SkiaImageButton : SkiaView
}
// Fill (3) and Start (0) both use y = bounds.Top
return new SKRect(x, y, x + finalWidth, y + finalHeight);
return new Rect(x, y, finalWidth, finalHeight);
}
return bounds;

View File

@@ -145,18 +145,18 @@ public class SkiaIndicatorView : SkiaView
/// </summary>
public bool HideSingle { get; set; } = true;
protected override SKSize MeasureOverride(SKSize availableSize)
protected override Size MeasureOverride(Size availableSize)
{
if (_count <= 0 || (HideSingle && _count <= 1))
{
return SKSize.Empty;
return Size.Zero;
}
int visibleCount = Math.Min(_count, MaximumVisible);
float totalWidth = visibleCount * (float)IndicatorSize + (visibleCount - 1) * (float)IndicatorSpacing;
float height = Math.Max((float)IndicatorSize, (float)SelectedIndicatorSize);
double totalWidth = visibleCount * IndicatorSize + (visibleCount - 1) * IndicatorSpacing;
double height = Math.Max(IndicatorSize, SelectedIndicatorSize);
return new SKSize(totalWidth, height);
return new Size(totalWidth, height);
}
protected override void OnDraw(SKCanvas canvas, SKRect bounds)
@@ -164,12 +164,13 @@ public class SkiaIndicatorView : SkiaView
if (_count <= 0 || (HideSingle && _count <= 1)) return;
canvas.Save();
canvas.ClipRect(Bounds);
var skBounds = new SKRect((float)Bounds.Left, (float)Bounds.Top, (float)(Bounds.Left + Bounds.Width), (float)(Bounds.Top + Bounds.Height));
canvas.ClipRect(skBounds);
int visibleCount = Math.Min(_count, MaximumVisible);
float totalWidth = visibleCount * (float)IndicatorSize + (visibleCount - 1) * (float)IndicatorSpacing;
float startX = Bounds.MidX - totalWidth / 2 + (float)IndicatorSize / 2;
float centerY = Bounds.MidY;
float startX = (float)(Bounds.Left + Bounds.Width / 2) - totalWidth / 2 + (float)IndicatorSize / 2;
float centerY = (float)(Bounds.Top + Bounds.Height / 2);
// Determine visible range if count > MaximumVisible
int startIndex = 0;
@@ -283,7 +284,7 @@ public class SkiaIndicatorView : SkiaView
{
int visibleCount = Math.Min(_count, MaximumVisible);
float totalWidth = visibleCount * (float)IndicatorSize + (visibleCount - 1) * (float)IndicatorSpacing;
float startX = Bounds.MidX - totalWidth / 2;
float startX = (float)(Bounds.Left + Bounds.Width / 2) - totalWidth / 2;
int startIndex = 0;
if (_count > MaximumVisible)
@@ -316,7 +317,7 @@ public class SkiaIndicatorView : SkiaView
// Calculate which indicator was clicked
int visibleCount = Math.Min(_count, MaximumVisible);
float totalWidth = visibleCount * (float)IndicatorSize + (visibleCount - 1) * (float)IndicatorSpacing;
float startX = Bounds.MidX - totalWidth / 2;
float startX = (float)(Bounds.Left + Bounds.Width / 2) - totalWidth / 2;
int startIndex = 0;
if (_count > MaximumVisible)

View File

@@ -176,7 +176,7 @@ public class SkiaItemsView : SkiaView
}
// Use ScreenBounds.Height for visible viewport
protected float MaxScrollOffset => Math.Max(0, TotalContentHeight - ScreenBounds.Height);
protected float MaxScrollOffset => Math.Max(0, TotalContentHeight - (float)ScreenBounds.Height);
protected override void OnDraw(SKCanvas canvas, SKRect bounds)
{
@@ -284,11 +284,11 @@ public class SkiaItemsView : SkiaView
if (itemView != null)
{
// Measure with large height to get natural size
var availableSize = new SKSize(bounds.Width, float.MaxValue);
var availableSize = new Size(bounds.Width, float.MaxValue);
var measuredSize = itemView.Measure(availableSize);
// Store individual item height (with minimum of default height)
var measuredHeight = Math.Max(measuredSize.Height, _itemHeight);
var measuredHeight = Math.Max((float)measuredSize.Height, _itemHeight);
if (!_itemHeights.TryGetValue(index, out var cachedHeight) || Math.Abs(cachedHeight - measuredHeight) > 1)
{
_itemHeights[index] = measuredHeight;
@@ -300,7 +300,7 @@ public class SkiaItemsView : SkiaView
}
// Arrange with the actual measured height
var actualBounds = new SKRect(bounds.Left, bounds.Top, bounds.Right, bounds.Top + measuredHeight);
var actualBounds = new Rect(bounds.Left, bounds.Top, bounds.Width, measuredHeight);
itemView.Arrange(actualBounds);
itemView.Draw(canvas);
return;
@@ -423,8 +423,8 @@ public class SkiaItemsView : SkiaView
_scrollbarDragStartY = e.Y;
_scrollbarDragStartScrollOffset = _scrollOffset;
// Cache values to prevent stutter
var thumbHeight = Math.Max(20, Bounds.Height * (Bounds.Height / TotalContentHeight));
_scrollbarDragAvailableTrack = Bounds.Height - thumbHeight;
var thumbHeight = Math.Max(20f, (float)Bounds.Height * ((float)Bounds.Height / TotalContentHeight));
_scrollbarDragAvailableTrack = (float)Bounds.Height - thumbHeight;
_scrollbarDragMaxScroll = MaxScrollOffset;
return;
}
@@ -445,15 +445,15 @@ public class SkiaItemsView : SkiaView
{
// Use ScreenBounds for hit testing (input events use screen coordinates)
var screenBounds = ScreenBounds;
var viewportRatio = screenBounds.Height / TotalContentHeight;
var thumbHeight = Math.Max(20, screenBounds.Height * viewportRatio);
var scrollRatio = MaxScrollOffset > 0 ? _scrollOffset / MaxScrollOffset : 0;
var thumbY = screenBounds.Top + (screenBounds.Height - thumbHeight) * scrollRatio;
var viewportRatio = (float)screenBounds.Height / TotalContentHeight;
var thumbHeight = Math.Max(20f, (float)screenBounds.Height * viewportRatio);
var scrollRatio = MaxScrollOffset > 0 ? _scrollOffset / MaxScrollOffset : 0f;
var thumbY = (float)screenBounds.Top + ((float)screenBounds.Height - thumbHeight) * scrollRatio;
return new SKRect(
screenBounds.Right - _scrollBarWidth,
(float)(screenBounds.Left + screenBounds.Width) - _scrollBarWidth,
thumbY,
screenBounds.Right,
(float)(screenBounds.Left + screenBounds.Width),
thumbY + thumbHeight);
}
@@ -621,12 +621,12 @@ public class SkiaItemsView : SkiaView
break;
case Key.PageUp:
SetScrollOffset(_scrollOffset - Bounds.Height);
SetScrollOffset(_scrollOffset - (float)Bounds.Height);
e.Handled = true;
break;
case Key.PageDown:
SetScrollOffset(_scrollOffset + Bounds.Height);
SetScrollOffset(_scrollOffset + (float)Bounds.Height);
e.Handled = true;
break;
@@ -663,9 +663,9 @@ public class SkiaItemsView : SkiaView
{
SetScrollOffset(itemTop);
}
else if (itemBottom > _scrollOffset + Bounds.Height)
else if (itemBottom > _scrollOffset + (float)Bounds.Height)
{
SetScrollOffset(itemBottom - Bounds.Height);
SetScrollOffset(itemBottom - (float)Bounds.Height);
}
}
@@ -679,14 +679,14 @@ public class SkiaItemsView : SkiaView
public override SkiaView? HitTest(float x, float y)
{
// HitTest uses Bounds (content space) - coordinates are transformed by parent
if (!IsVisible || !Bounds.Contains(new SKPoint(x, y)))
if (!IsVisible || !Bounds.Contains(x, y))
return null;
// Check scrollbar area FIRST before content
// This ensures scrollbar clicks are handled by this view
if (_showVerticalScrollBar && TotalContentHeight > Bounds.Height)
if (_showVerticalScrollBar && TotalContentHeight > (float)Bounds.Height)
{
var trackArea = new SKRect(Bounds.Right - _scrollBarWidth, Bounds.Top, Bounds.Right, Bounds.Bottom);
var trackArea = new SKRect((float)(Bounds.Left + Bounds.Width) - _scrollBarWidth, (float)Bounds.Top, (float)(Bounds.Left + Bounds.Width), (float)(Bounds.Top + Bounds.Height));
if (trackArea.Contains(x, y))
return this;
}
@@ -694,21 +694,21 @@ public class SkiaItemsView : SkiaView
return this;
}
protected override SKSize MeasureOverride(SKSize availableSize)
protected override Size MeasureOverride(Size availableSize)
{
var width = availableSize.Width < float.MaxValue ? availableSize.Width : 200;
var height = availableSize.Height < float.MaxValue ? availableSize.Height : 300;
var width = availableSize.Width < double.MaxValue ? availableSize.Width : 200;
var height = availableSize.Height < double.MaxValue ? availableSize.Height : 300;
// Clear item caches when width changes significantly (items need re-measurement for text wrapping)
if (Math.Abs(width - _lastMeasuredWidth) > 5)
{
_itemHeights.Clear();
_itemViewCache.Clear();
_lastMeasuredWidth = width;
_lastMeasuredWidth = (float)width;
}
// Items view takes all available space
return new SKSize(width, height);
return new Size(width, height);
}
protected override void Dispose(bool disposing)

View File

@@ -410,7 +410,7 @@ public class SkiaLabel : SkiaView
// Calculate character position from click
var screenBounds = ScreenBounds;
var clickX = e.X - screenBounds.Left - (float)Padding.Left;
var clickX = e.X - (float)screenBounds.Left - (float)Padding.Left;
var charIndex = GetCharacterIndexAtX(clickX);
// Check for double-click (select word)
@@ -448,7 +448,7 @@ public class SkiaLabel : SkiaView
if (string.IsNullOrEmpty(text)) return;
var screenBounds = ScreenBounds;
var clickX = e.X - screenBounds.Left - (float)Padding.Left;
var clickX = e.X - (float)screenBounds.Left - (float)Padding.Left;
var charIndex = GetCharacterIndexAtX(clickX);
_selectionLength = charIndex - _selectionStart;
@@ -1192,16 +1192,16 @@ public class SkiaLabel : SkiaView
#region Measurement
protected override SKSize MeasureOverride(SKSize availableSize)
protected override Size MeasureOverride(Size availableSize)
{
var padding = Padding;
float paddingH = (float)(padding.Left + padding.Right);
float paddingV = (float)(padding.Top + padding.Bottom);
double paddingH = padding.Left + padding.Right;
double paddingV = padding.Top + padding.Bottom;
string displayText = GetDisplayText();
if (string.IsNullOrEmpty(displayText) && (FormattedText == null || FormattedText.Spans.Count == 0))
{
return new SKSize(paddingH, paddingV + (float)FontSize);
return new Size(paddingH, paddingV + FontSize);
}
float fontSize = FontSize > 0 ? (float)FontSize : 14f;
@@ -1213,7 +1213,7 @@ public class SkiaLabel : SkiaView
using var paint = new SKPaint(font);
float width, height;
double width, height;
// LineHeight -1 means platform default (use 1.0 multiplier)
double effectiveLineHeight = LineHeight < 0 ? 1.0 : LineHeight;
@@ -1221,7 +1221,7 @@ public class SkiaLabel : SkiaView
{
// Measure formatted text
width = 0;
height = (float)(fontSize * effectiveLineHeight);
height = fontSize * effectiveLineHeight;
foreach (var span in FormattedText.Spans)
{
if (!string.IsNullOrEmpty(span.Text))
@@ -1240,7 +1240,7 @@ public class SkiaLabel : SkiaView
// Account for character spacing
if (CharacterSpacing != 0 && displayText.Length > 1)
{
width += (float)(CharacterSpacing * (displayText.Length - 1));
width += CharacterSpacing * (displayText.Length - 1);
}
// Account for multi-line
@@ -1248,7 +1248,7 @@ public class SkiaLabel : SkiaView
{
var lines = displayText.Split('\n');
int lineCount = MaxLines > 0 ? Math.Min(lines.Length, MaxLines) : lines.Length;
height = (float)(lineCount * fontSize * effectiveLineHeight);
height = lineCount * fontSize * effectiveLineHeight;
}
}
@@ -1258,14 +1258,14 @@ public class SkiaLabel : SkiaView
// Respect explicit size requests
if (WidthRequest >= 0)
{
width = (float)WidthRequest;
width = WidthRequest;
}
if (HeightRequest >= 0)
{
height = (float)HeightRequest;
height = HeightRequest;
}
return new SKSize(Math.Max(width, 1f), Math.Max(height, 1f));
return new Size(Math.Max(width, 1.0), Math.Max(height, 1.0));
}
#endregion

View File

@@ -193,7 +193,7 @@ public abstract class SkiaLayoutView : SkiaView
/// </summary>
protected virtual SKRect GetContentBounds()
{
return GetContentBounds(Bounds);
return GetContentBounds(new SKRect((float)Bounds.Left, (float)Bounds.Top, (float)(Bounds.Left + Bounds.Width), (float)(Bounds.Top + Bounds.Height)));
}
/// <summary>
@@ -247,7 +247,7 @@ public abstract class SkiaLayoutView : SkiaView
public override SkiaView? HitTest(float x, float y)
{
if (!IsVisible || !IsEnabled || !Bounds.Contains(new SKPoint(x, y)))
if (!IsVisible || !IsEnabled || !Bounds.Contains(x, y))
{
if (this is SkiaBorder)
{
@@ -357,7 +357,7 @@ public class SkiaStackLayout : SkiaLayoutView
set => SetValue(OrientationProperty, value);
}
protected override SKSize MeasureOverride(SKSize availableSize)
protected override Size MeasureOverride(Size availableSize)
{
// Handle NaN/Infinity in padding
var paddingLeft = (float)(double.IsNaN(Padding.Left) ? 0 : Padding.Left);
@@ -365,8 +365,8 @@ public class SkiaStackLayout : SkiaLayoutView
var paddingTop = (float)(double.IsNaN(Padding.Top) ? 0 : Padding.Top);
var paddingBottom = (float)(double.IsNaN(Padding.Bottom) ? 0 : Padding.Bottom);
var contentWidth = availableSize.Width - paddingLeft - paddingRight;
var contentHeight = availableSize.Height - paddingTop - paddingBottom;
var contentWidth = (float)availableSize.Width - paddingLeft - paddingRight;
var contentHeight = (float)availableSize.Height - paddingTop - paddingBottom;
// Clamp negative sizes to 0
if (contentWidth < 0 || float.IsNaN(contentWidth)) contentWidth = 0;
@@ -377,7 +377,7 @@ public class SkiaStackLayout : SkiaLayoutView
float maxWidth = 0;
float maxHeight = 0;
var childAvailable = new SKSize(contentWidth, contentHeight);
var childAvailable = new Size(contentWidth, contentHeight);
foreach (var child in Children)
{
@@ -386,8 +386,8 @@ public class SkiaStackLayout : SkiaLayoutView
var childSize = child.Measure(childAvailable);
// Skip NaN sizes from child measurements
var childWidth = float.IsNaN(childSize.Width) ? 0 : childSize.Width;
var childHeight = float.IsNaN(childSize.Height) ? 0 : childSize.Height;
var childWidth = double.IsNaN(childSize.Width) ? 0f : (float)childSize.Width;
var childHeight = double.IsNaN(childSize.Height) ? 0f : (float)childSize.Height;
if (Orientation == StackOrientation.Vertical)
{
@@ -408,22 +408,22 @@ public class SkiaStackLayout : SkiaLayoutView
if (Orientation == StackOrientation.Vertical)
{
totalHeight += totalSpacing;
return new SKSize(
return new Size(
maxWidth + paddingLeft + paddingRight,
totalHeight + paddingTop + paddingBottom);
}
else
{
totalWidth += totalSpacing;
return new SKSize(
return new Size(
totalWidth + paddingLeft + paddingRight,
maxHeight + paddingTop + paddingBottom);
}
}
protected override SKRect ArrangeOverride(SKRect bounds)
protected override Rect ArrangeOverride(Rect bounds)
{
var content = GetContentBounds(bounds);
var content = GetContentBounds(new SKRect((float)bounds.Left, (float)bounds.Top, (float)bounds.Right, (float)bounds.Bottom));
// Clamp content dimensions if infinite - use reasonable defaults
var contentWidth = float.IsInfinity(content.Width) || float.IsNaN(content.Width) ? 800f : content.Width;
@@ -438,14 +438,14 @@ public class SkiaStackLayout : SkiaLayoutView
var childDesired = child.DesiredSize;
// Handle NaN and Infinity in desired size
var childWidth = float.IsNaN(childDesired.Width) || float.IsInfinity(childDesired.Width)
var childWidth = double.IsNaN(childDesired.Width) || double.IsInfinity(childDesired.Width)
? contentWidth
: childDesired.Width;
var childHeight = float.IsNaN(childDesired.Height) || float.IsInfinity(childDesired.Height)
: (float)childDesired.Width;
var childHeight = double.IsNaN(childDesired.Height) || double.IsInfinity(childDesired.Height)
? contentHeight
: childDesired.Height;
: (float)childDesired.Height;
SKRect childBounds;
float childBoundsLeft, childBoundsTop, childBoundsWidth, childBoundsHeight;
if (Orientation == StackOrientation.Vertical)
{
// For ScrollView children, give them the remaining viewport height
@@ -455,11 +455,10 @@ public class SkiaStackLayout : SkiaLayoutView
? remainingHeight
: Math.Min(childHeight, remainingHeight > 0 ? remainingHeight : childHeight);
childBounds = new SKRect(
content.Left,
content.Top + offset,
content.Left + contentWidth,
content.Top + offset + useHeight);
childBoundsLeft = content.Left;
childBoundsTop = content.Top + offset;
childBoundsWidth = contentWidth;
childBoundsHeight = useHeight;
offset += useHeight + (float)Spacing;
}
else
@@ -473,7 +472,7 @@ public class SkiaStackLayout : SkiaLayoutView
// Respect child's VerticalOptions for horizontal layouts
var useHeight = Math.Min(childHeight, contentHeight);
float childTop = content.Top;
float childBottom = content.Top + useHeight;
float childBottomCalc = content.Top + useHeight;
var verticalOptions = child.VerticalOptions;
var alignmentValue = (int)verticalOptions.Alignment;
@@ -482,34 +481,33 @@ public class SkiaStackLayout : SkiaLayoutView
if (alignmentValue == 1) // Center
{
childTop = content.Top + (contentHeight - useHeight) / 2;
childBottom = childTop + useHeight;
childBottomCalc = childTop + useHeight;
}
else if (alignmentValue == 2) // End
{
childTop = content.Top + contentHeight - useHeight;
childBottom = content.Top + contentHeight;
childBottomCalc = content.Top + contentHeight;
}
else if (alignmentValue == 3) // Fill
{
childTop = content.Top;
childBottom = content.Top + contentHeight;
childBottomCalc = content.Top + contentHeight;
}
childBounds = new SKRect(
content.Left + offset,
childTop,
content.Left + offset + useWidth,
childBottom);
childBoundsLeft = content.Left + offset;
childBoundsTop = childTop;
childBoundsWidth = useWidth;
childBoundsHeight = childBottomCalc - childTop;
offset += useWidth + (float)Spacing;
}
// Apply child's margin
var margin = child.Margin;
var marginedBounds = new SKRect(
childBounds.Left + (float)margin.Left,
childBounds.Top + (float)margin.Top,
childBounds.Right - (float)margin.Right,
childBounds.Bottom - (float)margin.Bottom);
var marginedBounds = new Rect(
childBoundsLeft + (float)margin.Left,
childBoundsTop + (float)margin.Top,
childBoundsWidth - (float)margin.Left - (float)margin.Right,
childBoundsHeight - (float)margin.Top - (float)margin.Bottom);
child.Arrange(marginedBounds);
}
return bounds;
@@ -626,10 +624,10 @@ public class SkiaGrid : SkiaLayoutView
Invalidate();
}
protected override SKSize MeasureOverride(SKSize availableSize)
protected override Size MeasureOverride(Size availableSize)
{
var contentWidth = availableSize.Width - (float)Padding.Left - (float)Padding.Right;
var contentHeight = availableSize.Height - (float)Padding.Top - (float)Padding.Bottom;
var contentWidth = (float)(availableSize.Width - Padding.Left - Padding.Right);
var contentHeight = (float)(availableSize.Height - Padding.Top - Padding.Bottom);
// Handle NaN/Infinity
if (float.IsNaN(contentWidth) || float.IsInfinity(contentWidth)) contentWidth = 800;
@@ -652,8 +650,8 @@ public class SkiaGrid : SkiaLayoutView
var def = pos.Column < _columnDefinitions.Count ? _columnDefinitions[pos.Column] : GridLength.Star;
if (def.IsAuto && pos.ColumnSpan == 1)
{
var childSize = child.Measure(new SKSize(float.PositiveInfinity, float.PositiveInfinity));
var childWidth = float.IsNaN(childSize.Width) ? 0 : childSize.Width;
var childSize = child.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));
var childWidth = double.IsNaN(childSize.Width) ? 0f : (float)childSize.Width;
columnNaturalWidths[pos.Column] = Math.Max(columnNaturalWidths[pos.Column], childWidth);
}
}
@@ -670,11 +668,11 @@ public class SkiaGrid : SkiaLayoutView
var cellWidth = GetCellWidth(pos.Column, pos.ColumnSpan);
// Give infinite height for initial measure
var childSize = child.Measure(new SKSize(cellWidth, float.PositiveInfinity));
var childSize = child.Measure(new Size(cellWidth, double.PositiveInfinity));
// Track max height for each row
// Cap infinite/very large heights - child returning infinity means it doesn't have a natural height
var childHeight = childSize.Height;
var childHeight = (float)childSize.Height;
if (float.IsNaN(childHeight) || float.IsInfinity(childHeight) || childHeight > 100000)
{
// Use a default minimum - will be expanded by Star sizing if finite height is available
@@ -706,16 +704,16 @@ public class SkiaGrid : SkiaLayoutView
var cellWidth = GetCellWidth(pos.Column, pos.ColumnSpan);
var cellHeight = GetCellHeight(pos.Row, pos.RowSpan);
child.Measure(new SKSize(cellWidth, cellHeight));
child.Measure(new Size(cellWidth, cellHeight));
}
// Calculate total size
var totalWidth = _columnWidths.Sum() + Math.Max(0, columnCount - 1) * ColumnSpacing;
var totalHeight = _rowHeights.Sum() + Math.Max(0, rowCount - 1) * RowSpacing;
return new SKSize(
totalWidth + (float)Padding.Left + (float)Padding.Right,
totalHeight + (float)Padding.Top + (float)Padding.Bottom);
return new Size(
totalWidth + Padding.Left + Padding.Right,
totalHeight + Padding.Top + Padding.Bottom);
}
private int GetMaxRow()
@@ -827,11 +825,11 @@ public class SkiaGrid : SkiaLayoutView
return offset;
}
protected override SKRect ArrangeOverride(SKRect bounds)
protected override Rect ArrangeOverride(Rect bounds)
{
try
{
var content = GetContentBounds(bounds);
var content = GetContentBounds(new SKRect((float)bounds.Left, (float)bounds.Top, (float)bounds.Right, (float)bounds.Bottom));
// Recalculate row heights for arrange bounds if they differ from measurement
// This ensures Star rows expand to fill available space
@@ -909,11 +907,11 @@ public class SkiaGrid : SkiaLayoutView
// Apply child's margin
var margin = child.Margin;
var marginedBounds = new SKRect(
var marginedBounds = new Rect(
x + (float)margin.Left,
y + (float)margin.Top,
x + width - (float)margin.Right,
y + height - (float)margin.Bottom);
width - (float)margin.Left - (float)margin.Right,
height - (float)margin.Top - (float)margin.Bottom);
child.Arrange(marginedBounds);
}
return bounds;
@@ -1024,7 +1022,7 @@ public class SkiaAbsoluteLayout : SkiaLayoutView
Invalidate();
}
protected override SKSize MeasureOverride(SKSize availableSize)
protected override Size MeasureOverride(Size availableSize)
{
float maxRight = 0;
float maxBottom = 0;
@@ -1036,20 +1034,20 @@ public class SkiaAbsoluteLayout : SkiaLayoutView
var layout = GetLayoutBounds(child);
var bounds = layout.Bounds;
child.Measure(new SKSize(bounds.Width, bounds.Height));
child.Measure(new Size(bounds.Width, bounds.Height));
maxRight = Math.Max(maxRight, bounds.Right);
maxBottom = Math.Max(maxBottom, bounds.Bottom);
}
return new SKSize(
maxRight + (float)Padding.Left + (float)Padding.Right,
maxBottom + (float)Padding.Top + (float)Padding.Bottom);
return new Size(
maxRight + Padding.Left + Padding.Right,
maxBottom + Padding.Top + Padding.Bottom);
}
protected override SKRect ArrangeOverride(SKRect bounds)
protected override Rect ArrangeOverride(Rect bounds)
{
var content = GetContentBounds(bounds);
var content = GetContentBounds(new SKRect((float)bounds.Left, (float)bounds.Top, (float)bounds.Right, (float)bounds.Bottom));
foreach (var child in Children)
{
@@ -1077,7 +1075,7 @@ public class SkiaAbsoluteLayout : SkiaLayoutView
if (flags.HasFlag(AbsoluteLayoutFlags.WidthProportional))
width = childBounds.Width * content.Width;
else if (childBounds.Width < 0)
width = child.DesiredSize.Width;
width = (float)child.DesiredSize.Width;
else
width = childBounds.Width;
@@ -1085,17 +1083,17 @@ public class SkiaAbsoluteLayout : SkiaLayoutView
if (flags.HasFlag(AbsoluteLayoutFlags.HeightProportional))
height = childBounds.Height * content.Height;
else if (childBounds.Height < 0)
height = child.DesiredSize.Height;
height = (float)child.DesiredSize.Height;
else
height = childBounds.Height;
// Apply child's margin
var margin = child.Margin;
var marginedBounds = new SKRect(
var marginedBounds = new Rect(
x + (float)margin.Left,
y + (float)margin.Top,
x + width - (float)margin.Right,
y + height - (float)margin.Bottom);
width - (float)margin.Left - (float)margin.Right,
height - (float)margin.Top - (float)margin.Bottom);
child.Arrange(marginedBounds);
}
return bounds;

View File

@@ -104,9 +104,9 @@ public class SkiaMenuBar : SkiaView
/// </summary>
public float ItemPadding { get; set; } = 12f;
protected override SKSize MeasureOverride(SKSize availableSize)
protected override Size MeasureOverride(Size availableSize)
{
return new SKSize(availableSize.Width, BarHeight);
return new Size(availableSize.Width, BarHeight);
}
protected override void OnDraw(SKCanvas canvas, SKRect bounds)
@@ -119,7 +119,8 @@ public class SkiaMenuBar : SkiaView
Color = _menuBackgroundColorSK,
Style = SKPaintStyle.Fill
};
canvas.DrawRect(Bounds, bgPaint);
var skBounds = new SKRect((float)Bounds.Left, (float)Bounds.Top, (float)(Bounds.Left + Bounds.Width), (float)(Bounds.Top + Bounds.Height));
canvas.DrawRect(skBounds, bgPaint);
// Draw bottom border
using var borderPaint = new SKPaint
@@ -128,7 +129,7 @@ public class SkiaMenuBar : SkiaView
Style = SKPaintStyle.Stroke,
StrokeWidth = 1
};
canvas.DrawLine(Bounds.Left, Bounds.Bottom, Bounds.Right, Bounds.Bottom, borderPaint);
canvas.DrawLine((float)Bounds.Left, (float)(Bounds.Top + Bounds.Height), (float)(Bounds.Left + Bounds.Width), (float)(Bounds.Top + Bounds.Height), borderPaint);
// Draw menu items
using var textPaint = new SKPaint
@@ -138,7 +139,7 @@ public class SkiaMenuBar : SkiaView
IsAntialias = true
};
float x = Bounds.Left;
float x = (float)Bounds.Left;
for (int i = 0; i < _items.Count; i++)
{
@@ -147,7 +148,7 @@ public class SkiaMenuBar : SkiaView
textPaint.MeasureText(item.Text, ref textBounds);
float itemWidth = textBounds.Width + ItemPadding * 2;
var itemBounds = new SKRect(x, Bounds.Top, x + itemWidth, Bounds.Bottom);
var itemBounds = new SKRect(x, (float)Bounds.Top, x + itemWidth, (float)(Bounds.Top + Bounds.Height));
// Draw item background
if (i == _openIndex)
@@ -161,9 +162,9 @@ public class SkiaMenuBar : SkiaView
canvas.DrawRect(itemBounds, hoverPaint);
}
// Draw text
// Draw text (MidY = Top + Height/2)
float textX = x + ItemPadding;
float textY = Bounds.MidY - textBounds.MidY;
float textY = (float)(Bounds.Top + Bounds.Height / 2) - textBounds.MidY;
canvas.DrawText(item.Text, textX, textY, textPaint);
item.Bounds = itemBounds;

View File

@@ -287,7 +287,7 @@ public class SkiaNavigationPage : SkiaView
{
canvas.Save();
canvas.Translate(currentOffset, 0);
_currentPage.Bounds = bounds;
_currentPage.Bounds = new Rect(bounds.Left, bounds.Top, bounds.Width, bounds.Height);
_currentPage.Draw(canvas);
canvas.Restore();
}
@@ -295,7 +295,7 @@ public class SkiaNavigationPage : SkiaView
// Draw incoming page
canvas.Save();
canvas.Translate(incomingOffset, 0);
_incomingPage.Bounds = bounds;
_incomingPage.Bounds = new Rect(bounds.Left, bounds.Top, bounds.Width, bounds.Height);
_incomingPage.Draw(canvas);
canvas.Restore();
}
@@ -308,7 +308,7 @@ public class SkiaNavigationPage : SkiaView
// Draw incoming page (sliding in)
canvas.Save();
canvas.Translate(incomingOffset, 0);
_incomingPage.Bounds = bounds;
_incomingPage.Bounds = new Rect(bounds.Left, bounds.Top, bounds.Width, bounds.Height);
_incomingPage.Draw(canvas);
canvas.Restore();
@@ -317,7 +317,7 @@ public class SkiaNavigationPage : SkiaView
{
canvas.Save();
canvas.Translate(currentOffset, 0);
_currentPage.Bounds = bounds;
_currentPage.Bounds = new Rect(bounds.Left, bounds.Top, bounds.Width, bounds.Height);
_currentPage.Draw(canvas);
canvas.Restore();
}
@@ -327,7 +327,7 @@ public class SkiaNavigationPage : SkiaView
{
// Draw current page normally
Console.WriteLine("[SkiaNavigationPage] OnDraw: drawing _currentPage=" + _currentPage.Title);
_currentPage.Bounds = bounds;
_currentPage.Bounds = new Rect(bounds.Left, bounds.Top, bounds.Width, bounds.Height);
_currentPage.Draw(canvas);
// Draw back button if applicable
@@ -368,7 +368,7 @@ public class SkiaNavigationPage : SkiaView
return 1 - (float)Math.Pow(1 - t, 3);
}
protected override SKSize MeasureOverride(SKSize availableSize)
protected override Size MeasureOverride(Size availableSize)
{
return availableSize;
}

View File

@@ -187,9 +187,9 @@ public class SkiaPage : SkiaView
contentBounds.Bottom - (float)margin.Bottom);
// Measure and arrange the content before drawing
var availableSize = new SKSize(adjustedBounds.Width, adjustedBounds.Height);
var availableSize = new Size(adjustedBounds.Width, adjustedBounds.Height);
_content.Measure(availableSize);
_content.Arrange(adjustedBounds);
_content.Arrange(new Rect(adjustedBounds.Left, adjustedBounds.Top, adjustedBounds.Width, adjustedBounds.Height));
Console.WriteLine($"[SkiaPage] Drawing content: {_content.GetType().Name}, Bounds={_content.Bounds}, IsVisible={_content.IsVisible}");
_content.Draw(canvas);
}
@@ -294,7 +294,7 @@ public class SkiaPage : SkiaView
NavigatingFrom?.Invoke(this, EventArgs.Empty);
}
protected override SKSize MeasureOverride(SKSize availableSize)
protected override Size MeasureOverride(Size availableSize)
{
// Page takes all available space
return availableSize;

View File

@@ -419,7 +419,8 @@ public class SkiaPicker : SkiaView
private void DrawDropdownOverlay(SKCanvas canvas)
{
if (_items.Count == 0 || !_isOpen) return;
DrawDropdown(canvas, ScreenBounds);
var skScreenBounds = new SKRect((float)ScreenBounds.Left, (float)ScreenBounds.Top, (float)(ScreenBounds.Left + ScreenBounds.Width), (float)(ScreenBounds.Top + ScreenBounds.Height));
DrawDropdown(canvas, skScreenBounds);
}
protected override void OnDraw(SKCanvas canvas, SKRect bounds)
@@ -808,10 +809,10 @@ public class SkiaPicker : SkiaView
#region Layout
protected override SKSize MeasureOverride(SKSize availableSize)
protected override Size MeasureOverride(Size availableSize)
{
return new SKSize(
availableSize.Width < float.MaxValue ? Math.Min(availableSize.Width, 200) : 200,
return new Size(
availableSize.Width < double.MaxValue ? Math.Min(availableSize.Width, 200) : 200,
40);
}
@@ -837,10 +838,10 @@ public class SkiaPicker : SkiaView
var dropdownMaxHeight = (float)_dropdownMaxHeight;
var dropdownHeight = Math.Min(_items.Count * itemHeight, dropdownMaxHeight);
var dropdownRect = new SKRect(
screenBounds.Left,
screenBounds.Bottom + 4,
screenBounds.Right,
screenBounds.Bottom + 4 + dropdownHeight);
(float)screenBounds.Left,
(float)(screenBounds.Top + screenBounds.Height) + 4,
(float)(screenBounds.Left + screenBounds.Width),
(float)(screenBounds.Top + screenBounds.Height) + 4 + dropdownHeight);
return dropdownRect.Contains(x, y);
}

View File

@@ -244,10 +244,10 @@ public class SkiaProgressBar : SkiaView
#region Layout
protected override SKSize MeasureOverride(SKSize availableSize)
protected override Size MeasureOverride(Size availableSize)
{
var barHeight = (float)BarHeight;
return new SKSize(200f, barHeight + 8f);
var barHeight = BarHeight;
return new Size(200, barHeight + 8);
}
#endregion

View File

@@ -507,7 +507,7 @@ public class SkiaRadioButton : SkiaView
#region Layout
protected override SKSize MeasureOverride(SKSize availableSize)
protected override Size MeasureOverride(Size availableSize)
{
var radioSize = (float)RadioSize;
var fontSize = (float)FontSize;
@@ -520,7 +520,7 @@ public class SkiaRadioButton : SkiaView
using var paint = new SKPaint(font);
textWidth = paint.MeasureText(Content) + spacing;
}
return new SKSize(radioSize + textWidth, Math.Max(radioSize, fontSize * 1.5f));
return new Size(radioSize + textWidth, Math.Max(radioSize, fontSize * 1.5f));
}
#endregion

View File

@@ -130,25 +130,21 @@ public class SkiaRefreshView : SkiaLayoutView
/// </summary>
public event EventHandler? Refreshing;
protected override SKSize MeasureOverride(SKSize availableSize)
protected override Size MeasureOverride(Size availableSize)
{
if (_content != null)
{
_content.Measure(availableSize);
_content.Measure(new Size(availableSize.Width, availableSize.Height));
}
return availableSize;
}
protected override SKRect ArrangeOverride(SKRect bounds)
protected override Rect ArrangeOverride(Rect bounds)
{
if (_content != null)
{
float offset = _isRefreshing ? _refreshThreshold : _pullDistance;
var contentBounds = new SKRect(
bounds.Left,
bounds.Top + offset,
bounds.Right,
bounds.Bottom + offset);
var contentBounds = new Rect(bounds.Left, bounds.Top + offset, bounds.Width, bounds.Height);
_content.Arrange(contentBounds);
}
return bounds;

View File

@@ -240,9 +240,9 @@ public class SkiaScrollView : SkiaView
get
{
// Handle infinite or NaN bounds - use a reasonable default viewport
var viewportWidth = float.IsInfinity(Bounds.Width) || float.IsNaN(Bounds.Width) || Bounds.Width <= 0
var viewportWidth = double.IsInfinity(Bounds.Width) || double.IsNaN(Bounds.Width) || Bounds.Width <= 0
? 800f
: Bounds.Width;
: (float)Bounds.Width;
return Math.Max(0, ContentSize.Width - viewportWidth);
}
}
@@ -256,9 +256,9 @@ public class SkiaScrollView : SkiaView
{
// Handle infinite, NaN, or unreasonably large bounds - use a reasonable default viewport
var boundsHeight = Bounds.Height;
var viewportHeight = (float.IsInfinity(boundsHeight) || float.IsNaN(boundsHeight) || boundsHeight <= 0 || boundsHeight > 10000)
var viewportHeight = (double.IsInfinity(boundsHeight) || double.IsNaN(boundsHeight) || boundsHeight <= 0 || boundsHeight > 10000)
? 544f // Default viewport height (600 - 56 for shell header)
: boundsHeight;
: (float)boundsHeight;
return Math.Max(0, ContentSize.Height - viewportHeight);
}
}
@@ -290,17 +290,18 @@ public class SkiaScrollView : SkiaView
// Reserve space for vertical scrollbar if content might be taller than viewport
effectiveWidth -= ScrollBarWidth;
}
var availableSize = new SKSize(effectiveWidth, float.PositiveInfinity);
var availableSize = new Size(effectiveWidth, double.PositiveInfinity);
// Update ContentSize with the properly constrained measurement
ContentSize = _content.Measure(availableSize);
var contentDesired = _content.Measure(availableSize);
ContentSize = new SKSize((float)contentDesired.Width, (float)contentDesired.Height);
// Apply content's margin
var margin = _content.Margin;
var contentBounds = new SKRect(
bounds.Left + (float)margin.Left,
bounds.Top + (float)margin.Top,
bounds.Left + Math.Max(bounds.Width, _content.DesiredSize.Width) - (float)margin.Right,
bounds.Top + Math.Max(bounds.Height, _content.DesiredSize.Height) - (float)margin.Bottom);
var contentLeft = bounds.Left + (float)margin.Left;
var contentTop = bounds.Top + (float)margin.Top;
var contentWidth = Math.Max(bounds.Width, (float)_content.DesiredSize.Width) - (float)margin.Left - (float)margin.Right;
var contentHeight = Math.Max(bounds.Height, (float)_content.DesiredSize.Height) - (float)margin.Top - (float)margin.Bottom;
var contentBounds = new Rect(contentLeft, contentTop, contentWidth, contentHeight);
_content.Arrange(contentBounds);
canvas.Save();
@@ -358,8 +359,8 @@ public class SkiaScrollView : SkiaView
private void DrawVerticalScrollbar(SKCanvas canvas, SKRect bounds, bool hasHorizontal)
{
var trackHeight = bounds.Height - (hasHorizontal ? ScrollBarWidth : 0);
var thumbHeight = Math.Max(20, (bounds.Height / ContentSize.Height) * trackHeight);
var thumbY = (ScrollY / ScrollableHeight) * (trackHeight - thumbHeight);
var thumbHeight = Math.Max(20f, (bounds.Height / ContentSize.Height) * trackHeight);
var thumbY = ScrollableHeight > 0 ? (ScrollY / ScrollableHeight) * (trackHeight - thumbHeight) : 0f;
using var paint = new SKPaint
{
@@ -381,8 +382,8 @@ public class SkiaScrollView : SkiaView
private void DrawHorizontalScrollbar(SKCanvas canvas, SKRect bounds, bool hasVertical)
{
var trackWidth = bounds.Width - (hasVertical ? ScrollBarWidth : 0);
var thumbWidth = Math.Max(20, (bounds.Width / ContentSize.Width) * trackWidth);
var thumbX = (ScrollX / ScrollableWidth) * (trackWidth - thumbWidth);
var thumbWidth = Math.Max(20f, (bounds.Width / ContentSize.Width) * trackWidth);
var thumbX = ScrollableWidth > 0 ? (ScrollX / ScrollableWidth) * (trackWidth - thumbWidth) : 0f;
using var paint = new SKPaint
{
@@ -444,8 +445,8 @@ public class SkiaScrollView : SkiaView
_scrollbarDragStartScrollY = _scrollY;
// Cache values to prevent stutter from floating-point recalculations
var hasHorizontal = ShouldShowHorizontalScrollbar();
var trackHeight = Bounds.Height - (hasHorizontal ? ScrollBarWidth : 0);
var thumbHeight = Math.Max(20, (Bounds.Height / ContentSize.Height) * trackHeight);
var trackHeight = (float)Bounds.Height - (hasHorizontal ? ScrollBarWidth : 0);
var thumbHeight = Math.Max(20f, ((float)Bounds.Height / ContentSize.Height) * trackHeight);
_scrollbarDragAvailableTrack = trackHeight - thumbHeight;
_scrollbarDragScrollableExtent = ScrollableHeight;
return;
@@ -463,8 +464,8 @@ public class SkiaScrollView : SkiaView
_scrollbarDragStartScrollX = _scrollX;
// Cache values to prevent stutter from floating-point recalculations
var hasVertical = ShouldShowVerticalScrollbar();
var trackWidth = Bounds.Width - (hasVertical ? ScrollBarWidth : 0);
var thumbWidth = Math.Max(20, (Bounds.Width / ContentSize.Width) * trackWidth);
var trackWidth = (float)Bounds.Width - (hasVertical ? ScrollBarWidth : 0);
var thumbWidth = Math.Max(20f, ((float)Bounds.Width / ContentSize.Width) * trackWidth);
_scrollbarDragAvailableTrack = trackWidth - thumbWidth;
_scrollbarDragScrollableExtent = ScrollableWidth;
return;
@@ -549,34 +550,34 @@ public class SkiaScrollView : SkiaView
private SKRect GetVerticalScrollbarThumbBounds()
{
var hasHorizontal = ShouldShowHorizontalScrollbar();
var trackHeight = Bounds.Height - (hasHorizontal ? ScrollBarWidth : 0);
var thumbHeight = Math.Max(20, (Bounds.Height / ContentSize.Height) * trackHeight);
var thumbY = ScrollableHeight > 0 ? (ScrollY / ScrollableHeight) * (trackHeight - thumbHeight) : 0;
var trackHeight = (float)Bounds.Height - (hasHorizontal ? ScrollBarWidth : 0);
var thumbHeight = Math.Max(20f, ((float)Bounds.Height / ContentSize.Height) * trackHeight);
var thumbY = ScrollableHeight > 0 ? (ScrollY / ScrollableHeight) * (trackHeight - thumbHeight) : 0f;
return new SKRect(
Bounds.Right - ScrollBarWidth,
Bounds.Top + thumbY,
Bounds.Right,
Bounds.Top + thumbY + thumbHeight);
(float)(Bounds.Left + Bounds.Width) - ScrollBarWidth,
(float)Bounds.Top + thumbY,
(float)(Bounds.Left + Bounds.Width),
(float)Bounds.Top + thumbY + thumbHeight);
}
private SKRect GetHorizontalScrollbarThumbBounds()
{
var hasVertical = ShouldShowVerticalScrollbar();
var trackWidth = Bounds.Width - (hasVertical ? ScrollBarWidth : 0);
var thumbWidth = Math.Max(20, (Bounds.Width / ContentSize.Width) * trackWidth);
var thumbX = ScrollableWidth > 0 ? (ScrollX / ScrollableWidth) * (trackWidth - thumbWidth) : 0;
var trackWidth = (float)Bounds.Width - (hasVertical ? ScrollBarWidth : 0);
var thumbWidth = Math.Max(20f, ((float)Bounds.Width / ContentSize.Width) * trackWidth);
var thumbX = ScrollableWidth > 0 ? (ScrollX / ScrollableWidth) * (trackWidth - thumbWidth) : 0f;
return new SKRect(
Bounds.Left + thumbX,
Bounds.Bottom - ScrollBarWidth,
Bounds.Left + thumbX + thumbWidth,
Bounds.Bottom);
(float)Bounds.Left + thumbX,
(float)(Bounds.Top + Bounds.Height) - ScrollBarWidth,
(float)Bounds.Left + thumbX + thumbWidth,
(float)(Bounds.Top + Bounds.Height));
}
public override SkiaView? HitTest(float x, float y)
{
if (!IsVisible || !IsEnabled || !Bounds.Contains(new SKPoint(x, y)))
if (!IsVisible || !IsEnabled || !Bounds.Contains(x, y))
return null;
// Check scrollbar areas FIRST before content
@@ -585,14 +586,14 @@ public class SkiaScrollView : SkiaView
{
var thumbBounds = GetVerticalScrollbarThumbBounds();
// Check if click is in the scrollbar track area (not just thumb)
var trackArea = new SKRect(Bounds.Right - ScrollBarWidth, Bounds.Top, Bounds.Right, Bounds.Bottom);
var trackArea = new SKRect((float)(Bounds.Left + Bounds.Width) - ScrollBarWidth, (float)Bounds.Top, (float)(Bounds.Left + Bounds.Width), (float)(Bounds.Top + Bounds.Height));
if (trackArea.Contains(x, y))
return this;
}
if (ShouldShowHorizontalScrollbar() && ScrollableWidth > 0)
{
var trackArea = new SKRect(Bounds.Left, Bounds.Bottom - ScrollBarWidth, Bounds.Right, Bounds.Bottom);
var trackArea = new SKRect((float)Bounds.Left, (float)(Bounds.Top + Bounds.Height) - ScrollBarWidth, (float)(Bounds.Left + Bounds.Width), (float)(Bounds.Top + Bounds.Height));
if (trackArea.Contains(x, y))
return this;
}
@@ -680,38 +681,40 @@ public class SkiaScrollView : SkiaView
float targetY = _scrollY;
// Calculate viewport dimensions
float viewportWidth = Bounds.Width;
float viewportHeight = Bounds.Height;
float viewportWidth = (float)Bounds.Width;
float viewportHeight = (float)Bounds.Height;
float elementRight = (float)(elementBounds.Left + elementBounds.Width);
float elementBottom = (float)(elementBounds.Top + elementBounds.Height);
switch (position)
{
case ScrollToPosition.Start:
targetX = elementBounds.Left;
targetY = elementBounds.Top;
targetX = (float)elementBounds.Left;
targetY = (float)elementBounds.Top;
break;
case ScrollToPosition.Center:
targetX = elementBounds.Left - (viewportWidth - elementBounds.Width) / 2;
targetY = elementBounds.Top - (viewportHeight - elementBounds.Height) / 2;
targetX = (float)elementBounds.Left - (viewportWidth - (float)elementBounds.Width) / 2;
targetY = (float)elementBounds.Top - (viewportHeight - (float)elementBounds.Height) / 2;
break;
case ScrollToPosition.End:
targetX = elementBounds.Right - viewportWidth;
targetY = elementBounds.Bottom - viewportHeight;
targetX = elementRight - viewportWidth;
targetY = elementBottom - viewportHeight;
break;
case ScrollToPosition.MakeVisible:
default:
// Only scroll if element is not fully visible
if (elementBounds.Left < _scrollX)
targetX = elementBounds.Left;
else if (elementBounds.Right > _scrollX + viewportWidth)
targetX = elementBounds.Right - viewportWidth;
targetX = (float)elementBounds.Left;
else if (elementRight > _scrollX + viewportWidth)
targetX = elementRight - viewportWidth;
if (elementBounds.Top < _scrollY)
targetY = elementBounds.Top;
else if (elementBounds.Bottom > _scrollY + viewportHeight)
targetY = elementBounds.Bottom - viewportHeight;
targetY = (float)elementBounds.Top;
else if (elementBottom > _scrollY + viewportHeight)
targetY = elementBottom - viewportHeight;
break;
}
@@ -730,15 +733,18 @@ public class SkiaScrollView : SkiaView
if (_content == null) return;
var viewBounds = view.Bounds;
float viewRight = (float)(viewBounds.Left + viewBounds.Width);
float viewBottom = (float)(viewBounds.Top + viewBounds.Height);
// Check if view is fully visible
var visibleRect = new SKRect(
ScrollX,
ScrollY,
ScrollX + Bounds.Width,
ScrollY + Bounds.Height);
ScrollX + (float)Bounds.Width,
ScrollY + (float)Bounds.Height);
if (visibleRect.Contains(viewBounds))
var viewSKRect = new SKRect((float)viewBounds.Left, (float)viewBounds.Top, viewRight, viewBottom);
if (visibleRect.Contains(viewSKRect))
return;
// Calculate scroll position to bring view into view
@@ -746,14 +752,14 @@ public class SkiaScrollView : SkiaView
float targetY = ScrollY;
if (viewBounds.Left < visibleRect.Left)
targetX = viewBounds.Left;
else if (viewBounds.Right > visibleRect.Right)
targetX = viewBounds.Right - Bounds.Width;
targetX = (float)viewBounds.Left;
else if (viewRight > visibleRect.Right)
targetX = viewRight - (float)Bounds.Width;
if (viewBounds.Top < visibleRect.Top)
targetY = viewBounds.Top;
else if (viewBounds.Bottom > visibleRect.Bottom)
targetY = viewBounds.Bottom - Bounds.Height;
targetY = (float)viewBounds.Top;
else if (viewBottom > visibleRect.Bottom)
targetY = viewBottom - (float)Bounds.Height;
ScrollTo(targetX, targetY, animated);
}
@@ -770,7 +776,7 @@ public class SkiaScrollView : SkiaView
return Math.Clamp(value, 0, ScrollableHeight);
}
protected override SKSize MeasureOverride(SKSize availableSize)
protected override Size MeasureOverride(Size availableSize)
{
if (_content != null)
{
@@ -787,17 +793,17 @@ public class SkiaScrollView : SkiaView
{
case ScrollOrientation.Horizontal:
contentWidth = float.PositiveInfinity;
contentHeight = float.IsInfinity(availableSize.Height) ? 400f : availableSize.Height;
contentHeight = double.IsInfinity(availableSize.Height) ? 400f : (float)availableSize.Height;
break;
case ScrollOrientation.Neither:
contentWidth = float.IsInfinity(availableSize.Width) ? 400f : availableSize.Width;
contentHeight = float.IsInfinity(availableSize.Height) ? 400f : availableSize.Height;
contentWidth = double.IsInfinity(availableSize.Width) ? 400f : (float)availableSize.Width;
contentHeight = double.IsInfinity(availableSize.Height) ? 400f : (float)availableSize.Height;
break;
case ScrollOrientation.Both:
// For Both: first measure with viewport width to get responsive layout
// Content can still exceed viewport if it has minimum width constraints
// Reserve space for vertical scrollbar to prevent horizontal scrollbar
contentWidth = float.IsInfinity(availableSize.Width) ? 800f : availableSize.Width;
contentWidth = double.IsInfinity(availableSize.Width) ? 800f : (float)availableSize.Width;
if (VerticalScrollBarVisibility != ScrollBarVisibility.Never)
contentWidth -= ScrollBarWidth;
contentHeight = float.PositiveInfinity;
@@ -805,14 +811,15 @@ public class SkiaScrollView : SkiaView
case ScrollOrientation.Vertical:
default:
// Reserve space for vertical scrollbar to prevent horizontal scrollbar
contentWidth = float.IsInfinity(availableSize.Width) ? 800f : availableSize.Width;
contentWidth = double.IsInfinity(availableSize.Width) ? 800f : (float)availableSize.Width;
if (VerticalScrollBarVisibility != ScrollBarVisibility.Never)
contentWidth -= ScrollBarWidth;
contentHeight = float.PositiveInfinity;
break;
}
ContentSize = _content.Measure(new SKSize(contentWidth, contentHeight));
var contentDesiredMeasure = _content.Measure(new Size(contentWidth, contentHeight));
ContentSize = new SKSize((float)contentDesiredMeasure.Width, (float)contentDesiredMeasure.Height);
}
else
{
@@ -823,41 +830,41 @@ public class SkiaScrollView : SkiaView
// IMPORTANT: When available is infinite, return a reasonable viewport size, NOT content size
// A ScrollView should NOT expand to fit its content - it should stay at a fixed viewport
// and scroll the content. Use a default viewport size when parent gives infinity.
const float DefaultViewportWidth = 400f;
const float DefaultViewportHeight = 400f;
const double DefaultViewportWidth = 400.0;
const double DefaultViewportHeight = 400.0;
var width = float.IsInfinity(availableSize.Width) || float.IsNaN(availableSize.Width)
var width = double.IsInfinity(availableSize.Width) || double.IsNaN(availableSize.Width)
? Math.Min(ContentSize.Width, DefaultViewportWidth)
: availableSize.Width;
var height = float.IsInfinity(availableSize.Height) || float.IsNaN(availableSize.Height)
var height = double.IsInfinity(availableSize.Height) || double.IsNaN(availableSize.Height)
? Math.Min(ContentSize.Height, DefaultViewportHeight)
: availableSize.Height;
return new SKSize(width, height);
return new Size(width, height);
}
protected override SKRect ArrangeOverride(SKRect bounds)
protected override Rect ArrangeOverride(Rect bounds)
{
// CRITICAL: If bounds has infinite height, use a fixed viewport size
// NOT ContentSize.Height - that would make ScrollableHeight = 0
const float DefaultViewportHeight = 544f; // 600 - 56 for shell header
var actualBounds = bounds;
if (float.IsInfinity(bounds.Height) || float.IsNaN(bounds.Height))
if (double.IsInfinity(bounds.Height) || double.IsNaN(bounds.Height))
{
Console.WriteLine($"[SkiaScrollView] WARNING: Infinite/NaN height, using default viewport={DefaultViewportHeight}");
actualBounds = new SKRect(bounds.Left, bounds.Top, bounds.Right, bounds.Top + DefaultViewportHeight);
actualBounds = new Rect(bounds.Left, bounds.Top, bounds.Width, DefaultViewportHeight);
}
if (_content != null)
{
// Apply content's margin and arrange content at its full size
var margin = _content.Margin;
var contentBounds = new SKRect(
actualBounds.Left + (float)margin.Left,
actualBounds.Top + (float)margin.Top,
actualBounds.Left + Math.Max(actualBounds.Width, ContentSize.Width) - (float)margin.Right,
actualBounds.Top + Math.Max(actualBounds.Height, ContentSize.Height) - (float)margin.Bottom);
var contentLeft = (float)actualBounds.Left + (float)margin.Left;
var contentTop = (float)actualBounds.Top + (float)margin.Top;
var contentWidth = Math.Max((float)actualBounds.Width, ContentSize.Width) - (float)margin.Left - (float)margin.Right;
var contentHeight = Math.Max((float)actualBounds.Height, ContentSize.Height) - (float)margin.Top - (float)margin.Bottom;
var contentBounds = new Rect(contentLeft, contentTop, contentWidth, contentHeight);
_content.Arrange(contentBounds);
}

View File

@@ -177,7 +177,7 @@ public class SkiaSearchBar : SkiaView
? bounds.Right - clearButtonSize - iconPadding * 2
: bounds.Right - iconPadding;
var entryBounds = new SKRect(entryLeft, bounds.Top, entryRight, bounds.Bottom);
var entryBounds = new Rect(entryLeft, bounds.Top, entryRight - entryLeft, bounds.Height);
_entry.Arrange(entryBounds);
_entry.Draw(canvas);
@@ -306,9 +306,9 @@ public class SkiaSearchBar : SkiaView
#region Measurement
protected override SKSize MeasureOverride(SKSize availableSize)
protected override Size MeasureOverride(Size availableSize)
{
return new SKSize(250, 40);
return new Size(250, 40);
}
#endregion

View File

@@ -750,36 +750,36 @@ public class SkiaShell : SkiaLayoutView
}
}
protected override SKSize MeasureOverride(SKSize availableSize)
protected override Size MeasureOverride(Size availableSize)
{
// Measure current content with padding accounted for (consistent with ArrangeOverride)
if (_currentContent != null)
{
float contentTop = NavBarIsVisible ? NavBarHeight : 0;
float contentBottom = TabBarIsVisible ? TabBarHeight : 0;
var contentSize = new SKSize(
availableSize.Width - (float)Padding.Left - (float)Padding.Right,
availableSize.Height - contentTop - contentBottom - (float)Padding.Top - (float)Padding.Bottom);
var contentSize = new Size(
availableSize.Width - Padding.Left - Padding.Right,
availableSize.Height - contentTop - contentBottom - Padding.Top - Padding.Bottom);
_currentContent.Measure(contentSize);
}
return availableSize;
}
protected override SKRect ArrangeOverride(SKRect bounds)
protected override Rect ArrangeOverride(Rect bounds)
{
Console.WriteLine($"[SkiaShell] ArrangeOverride - bounds={bounds}");
// Arrange current content with padding
if (_currentContent != null)
{
float contentTop = bounds.Top + (NavBarIsVisible ? NavBarHeight : 0) + ContentPadding;
float contentBottom = bounds.Bottom - (TabBarIsVisible ? TabBarHeight : 0) - ContentPadding;
var contentBounds = new SKRect(
float contentTop = (float)bounds.Top + (NavBarIsVisible ? NavBarHeight : 0) + ContentPadding;
float contentBottom = (float)bounds.Bottom - (TabBarIsVisible ? TabBarHeight : 0) - ContentPadding;
var contentBounds = new Rect(
bounds.Left + ContentPadding,
contentTop,
bounds.Right - ContentPadding,
contentBottom);
bounds.Width - ContentPadding * 2,
contentBottom - contentTop);
Console.WriteLine($"[SkiaShell] Arranging content with bounds={contentBounds}, padding={ContentPadding}");
_currentContent.Arrange(contentBounds);
}
@@ -1011,8 +1011,8 @@ public class SkiaShell : SkiaLayoutView
// Check flyout area
if (_flyoutAnimationProgress > 0)
{
float flyoutX = Bounds.Left - FlyoutWidth + (FlyoutWidth * _flyoutAnimationProgress);
var flyoutBounds = new SKRect(flyoutX, Bounds.Top, flyoutX + FlyoutWidth, Bounds.Bottom);
float flyoutX = (float)Bounds.Left - FlyoutWidth + (FlyoutWidth * _flyoutAnimationProgress);
var flyoutBounds = new SKRect(flyoutX, (float)Bounds.Top, flyoutX + FlyoutWidth, (float)Bounds.Bottom);
if (flyoutBounds.Contains(x, y))
{
@@ -1027,13 +1027,13 @@ public class SkiaShell : SkiaLayoutView
}
// Check nav bar
if (NavBarIsVisible && y < Bounds.Top + NavBarHeight)
if (NavBarIsVisible && y < (float)Bounds.Top + NavBarHeight)
{
return this;
}
// Check tab bar
if (TabBarIsVisible && y > Bounds.Bottom - TabBarHeight)
if (TabBarIsVisible && y > (float)Bounds.Bottom - TabBarHeight)
{
return this;
}
@@ -1055,8 +1055,8 @@ public class SkiaShell : SkiaLayoutView
// Check flyout tap
if (_flyoutAnimationProgress > 0)
{
float flyoutX = Bounds.Left - FlyoutWidth + (FlyoutWidth * _flyoutAnimationProgress);
var flyoutBounds = new SKRect(flyoutX, Bounds.Top, flyoutX + FlyoutWidth, Bounds.Bottom);
float flyoutX = (float)Bounds.Left - FlyoutWidth + (FlyoutWidth * _flyoutAnimationProgress);
var flyoutBounds = new SKRect(flyoutX, (float)Bounds.Top, flyoutX + FlyoutWidth, (float)Bounds.Bottom);
if (flyoutBounds.Contains(e.X, e.Y))
{
@@ -1105,13 +1105,13 @@ public class SkiaShell : SkiaLayoutView
}
// Check tab bar tap
if (TabBarIsVisible && e.Y > Bounds.Bottom - TabBarHeight)
if (TabBarIsVisible && e.Y > (float)Bounds.Bottom - TabBarHeight)
{
if (_selectedSectionIndex >= 0 && _selectedSectionIndex < _sections.Count)
{
var section = _sections[_selectedSectionIndex];
float tabWidth = Bounds.Width / section.Items.Count;
int tappedIndex = (int)((e.X - Bounds.Left) / tabWidth);
float tabWidth = (float)Bounds.Width / section.Items.Count;
int tappedIndex = (int)((e.X - (float)Bounds.Left) / tabWidth);
tappedIndex = Math.Clamp(tappedIndex, 0, section.Items.Count - 1);
if (tappedIndex != _selectedItemIndex)
@@ -1130,8 +1130,8 @@ public class SkiaShell : SkiaLayoutView
{
if (FlyoutIsPresented && _flyoutAnimationProgress > 0)
{
float flyoutX = Bounds.Left - FlyoutWidth + (FlyoutWidth * _flyoutAnimationProgress);
var flyoutBounds = new SKRect(flyoutX, Bounds.Top, flyoutX + FlyoutWidth, Bounds.Bottom);
float flyoutX = (float)Bounds.Left - FlyoutWidth + (FlyoutWidth * _flyoutAnimationProgress);
var flyoutBounds = new SKRect(flyoutX, (float)Bounds.Top, flyoutX + FlyoutWidth, (float)Bounds.Bottom);
if (flyoutBounds.Contains(e.X, e.Y))
{

View File

@@ -476,10 +476,10 @@ public class SkiaSlider : SkiaView
#region Layout
protected override SKSize MeasureOverride(SKSize availableSize)
protected override Size MeasureOverride(Size availableSize)
{
var thumbRadius = (float)ThumbRadius;
return new SKSize(200, thumbRadius * 2 + 16);
var thumbRadius = ThumbRadius;
return new Size(200, thumbRadius * 2 + 16);
}
#endregion

View File

@@ -520,10 +520,10 @@ public class SkiaStepper : SkiaView
#region Layout
protected override SKSize MeasureOverride(SKSize availableSize)
protected override Size MeasureOverride(Size availableSize)
{
var buttonWidth = (float)ButtonWidth;
return new SKSize(buttonWidth * 2 + 1, 32);
var buttonWidth = ButtonWidth;
return new Size(buttonWidth * 2 + 1, 32);
}
#endregion

View File

@@ -137,24 +137,24 @@ public class SkiaSwipeView : SkiaLayoutView
Invalidate();
}
protected override SKSize MeasureOverride(SKSize availableSize)
protected override Size MeasureOverride(Size availableSize)
{
if (_content != null)
{
_content.Measure(availableSize);
_content.Measure(new Size(availableSize.Width, availableSize.Height));
}
return availableSize;
}
protected override SKRect ArrangeOverride(SKRect bounds)
protected override Rect ArrangeOverride(Rect bounds)
{
if (_content != null)
{
var contentBounds = new SKRect(
var contentBounds = new Rect(
bounds.Left + _swipeOffset,
bounds.Top,
bounds.Right + _swipeOffset,
bounds.Bottom);
bounds.Width,
bounds.Height);
_content.Arrange(contentBounds);
}
return bounds;

View File

@@ -439,11 +439,11 @@ public class SkiaSwitch : SkiaView
#region Layout
protected override SKSize MeasureOverride(SKSize availableSize)
protected override Size MeasureOverride(Size availableSize)
{
var trackWidth = (float)TrackWidth;
var trackHeight = (float)TrackHeight;
return new SKSize(trackWidth + 8f, trackHeight + 8f);
var trackWidth = TrackWidth;
var trackHeight = TrackHeight;
return new Size(trackWidth + 8, trackHeight + 8);
}
#endregion

View File

@@ -216,11 +216,11 @@ public class SkiaTabbedPage : SkiaLayoutView
Invalidate();
}
protected override SKSize MeasureOverride(SKSize availableSize)
protected override Size MeasureOverride(Size availableSize)
{
// Measure the content area (excluding tab bar)
var contentHeight = availableSize.Height - TabBarHeight;
var contentSize = new SKSize(availableSize.Width, contentHeight);
var contentSize = new Size(availableSize.Width, contentHeight);
foreach (var tab in _tabs)
{
@@ -230,25 +230,25 @@ public class SkiaTabbedPage : SkiaLayoutView
return availableSize;
}
protected override SKRect ArrangeOverride(SKRect bounds)
protected override Rect ArrangeOverride(Rect bounds)
{
// Calculate content bounds based on tab bar position
SKRect contentBounds;
Rect contentBounds;
if (TabBarOnBottom)
{
contentBounds = new SKRect(
contentBounds = new Rect(
bounds.Left,
bounds.Top,
bounds.Right,
bounds.Bottom - TabBarHeight);
bounds.Width,
bounds.Height - TabBarHeight);
}
else
{
contentBounds = new SKRect(
contentBounds = new Rect(
bounds.Left,
bounds.Top + TabBarHeight,
bounds.Right,
bounds.Bottom);
bounds.Width,
bounds.Height - TabBarHeight);
}
// Arrange each tab's content to fill the content area
@@ -284,18 +284,18 @@ public class SkiaTabbedPage : SkiaLayoutView
if (TabBarOnBottom)
{
tabBarBounds = new SKRect(
Bounds.Left,
Bounds.Bottom - TabBarHeight,
Bounds.Right,
Bounds.Bottom);
(float)Bounds.Left,
(float)Bounds.Bottom - TabBarHeight,
(float)Bounds.Right,
(float)Bounds.Bottom);
}
else
{
tabBarBounds = new SKRect(
Bounds.Left,
Bounds.Top,
Bounds.Right,
Bounds.Top + TabBarHeight);
(float)Bounds.Left,
(float)Bounds.Top,
(float)Bounds.Right,
(float)Bounds.Top + TabBarHeight);
}
// Draw background
@@ -377,18 +377,18 @@ public class SkiaTabbedPage : SkiaLayoutView
if (TabBarOnBottom)
{
tabBarBounds = new SKRect(
Bounds.Left,
Bounds.Bottom - TabBarHeight,
Bounds.Right,
Bounds.Bottom);
(float)Bounds.Left,
(float)(Bounds.Top + Bounds.Height) - TabBarHeight,
(float)(Bounds.Left + Bounds.Width),
(float)(Bounds.Top + Bounds.Height));
}
else
{
tabBarBounds = new SKRect(
Bounds.Left,
Bounds.Top,
Bounds.Right,
Bounds.Top + TabBarHeight);
(float)Bounds.Left,
(float)Bounds.Top,
(float)(Bounds.Left + Bounds.Width),
(float)Bounds.Top + TabBarHeight);
}
if (tabBarBounds.Contains(x, y))
@@ -415,18 +415,18 @@ public class SkiaTabbedPage : SkiaLayoutView
if (TabBarOnBottom)
{
tabBarBounds = new SKRect(
Bounds.Left,
Bounds.Bottom - TabBarHeight,
Bounds.Right,
Bounds.Bottom);
(float)Bounds.Left,
(float)(Bounds.Top + Bounds.Height) - TabBarHeight,
(float)(Bounds.Left + Bounds.Width),
(float)(Bounds.Top + Bounds.Height));
}
else
{
tabBarBounds = new SKRect(
Bounds.Left,
Bounds.Top,
Bounds.Right,
Bounds.Top + TabBarHeight);
(float)Bounds.Left,
(float)Bounds.Top,
(float)(Bounds.Left + Bounds.Width),
(float)Bounds.Top + TabBarHeight);
}
if (tabBarBounds.Contains(e.X, e.Y) && _tabs.Count > 0)

View File

@@ -323,11 +323,12 @@ public abstract class SkiaTemplatedView : SkiaView
/// </summary>
protected abstract void DrawDefaultAppearance(SKCanvas canvas, SKRect bounds);
protected override SKSize MeasureOverride(SKSize availableSize)
protected override Size MeasureOverride(Size availableSize)
{
if (_templateRoot != null && _templateApplied)
{
return _templateRoot.Measure(availableSize);
var measured = _templateRoot.Measure(new Size(availableSize.Width, availableSize.Height));
return new Size(measured.Width, measured.Height);
}
return MeasureDefaultAppearance(availableSize);
@@ -337,12 +338,12 @@ public abstract class SkiaTemplatedView : SkiaView
/// Measures the default appearance when no template is applied.
/// Override in derived classes.
/// </summary>
protected virtual SKSize MeasureDefaultAppearance(SKSize availableSize)
protected virtual Size MeasureDefaultAppearance(Size availableSize)
{
return new SKSize(100, 40);
return new Size(100, 40);
}
public new void Arrange(SKRect bounds)
public new void Arrange(Rect bounds)
{
base.Arrange(bounds);

View File

@@ -278,7 +278,8 @@ public class SkiaTimePicker : SkiaView
private void DrawClockOverlay(SKCanvas canvas)
{
if (!_isOpen) return;
DrawClockPopup(canvas, ScreenBounds);
var sb = ScreenBounds;
DrawClockPopup(canvas, new SKRect((float)sb.Left, (float)sb.Top, (float)sb.Right, (float)sb.Bottom));
}
private void DrawPickerButton(SKCanvas canvas, SKRect bounds)
@@ -499,7 +500,7 @@ public class SkiaTimePicker : SkiaView
if (IsOpen)
{
var screenBounds = ScreenBounds;
var popupRect = GetPopupRect(screenBounds);
var popupRect = GetPopupRect(new SKRect((float)screenBounds.Left, (float)screenBounds.Top, (float)screenBounds.Right, (float)screenBounds.Bottom));
var headerRect = new SKRect(popupRect.Left, popupRect.Top, popupRect.Right, popupRect.Top + HeaderHeight);
if (headerRect.Contains(e.X, e.Y))
@@ -598,9 +599,9 @@ public class SkiaTimePicker : SkiaView
Invalidate();
}
protected override SKSize MeasureOverride(SKSize availableSize)
protected override Size MeasureOverride(Size availableSize)
{
return new SKSize(availableSize.Width < float.MaxValue ? Math.Min(availableSize.Width, 200) : 200, 40);
return new Size(availableSize.Width < double.MaxValue ? Math.Min(availableSize.Width, 200) : 200, 40);
}
protected override bool HitTestPopupArea(float x, float y)
@@ -611,7 +612,7 @@ public class SkiaTimePicker : SkiaView
if (_isOpen)
{
var popupRect = GetPopupRect(screenBounds);
var popupRect = GetPopupRect(new SKRect((float)screenBounds.Left, (float)screenBounds.Top, (float)screenBounds.Right, (float)screenBounds.Bottom));
return popupRect.Contains(x, y);
}

View File

@@ -3,6 +3,7 @@
using Microsoft.Maui.Controls;
using Microsoft.Maui.Controls.Shapes;
using Microsoft.Maui.Graphics;
using Microsoft.Maui.Platform.Linux;
using Microsoft.Maui.Platform.Linux.Handlers;
using Microsoft.Maui.Platform.Linux.Rendering;
@@ -701,14 +702,14 @@ public abstract class SkiaView : BindableObject, IDisposable, IAccessible
#endregion
private bool _disposed;
private SKRect _bounds;
private Rect _bounds;
private SkiaView? _parent;
private readonly List<SkiaView> _children = new();
/// <summary>
/// Gets the absolute bounds of this view in screen coordinates.
/// </summary>
public SKRect GetAbsoluteBounds()
public Rect GetAbsoluteBounds()
{
var bounds = Bounds;
var current = Parent;
@@ -717,11 +718,11 @@ public abstract class SkiaView : BindableObject, IDisposable, IAccessible
// Adjust for scroll offset if parent is a ScrollView
if (current is SkiaScrollView scrollView)
{
bounds = new SKRect(
bounds = new Rect(
bounds.Left - scrollView.ScrollX,
bounds.Top - scrollView.ScrollY,
bounds.Right - scrollView.ScrollX,
bounds.Bottom - scrollView.ScrollY);
bounds.Width,
bounds.Height);
}
current = current.Parent;
}
@@ -730,8 +731,9 @@ public abstract class SkiaView : BindableObject, IDisposable, IAccessible
/// <summary>
/// Gets or sets the bounds of this view in parent coordinates.
/// Uses MAUI Rect for public API compliance.
/// </summary>
public SKRect Bounds
public Rect Bounds
{
get => _bounds;
set
@@ -744,6 +746,15 @@ public abstract class SkiaView : BindableObject, IDisposable, IAccessible
}
}
/// <summary>
/// Gets the bounds as SKRect for internal SkiaSharp rendering.
/// </summary>
internal SKRect BoundsSK => new SKRect(
(float)_bounds.Left,
(float)_bounds.Top,
(float)_bounds.Right,
(float)_bounds.Bottom);
/// <summary>
/// Gets or sets whether this view is visible.
/// </summary>
@@ -1115,7 +1126,7 @@ public abstract class SkiaView : BindableObject, IDisposable, IAccessible
/// <summary>
/// Gets the bounds of this view in screen coordinates (accounting for scroll offsets).
/// </summary>
public SKRect ScreenBounds
public Rect ScreenBounds
{
get
{
@@ -1127,11 +1138,11 @@ public abstract class SkiaView : BindableObject, IDisposable, IAccessible
{
if (parent is SkiaScrollView scrollView)
{
bounds = new SKRect(
bounds = new Rect(
bounds.Left - scrollView.ScrollX,
bounds.Top - scrollView.ScrollY,
bounds.Right - scrollView.ScrollX,
bounds.Bottom - scrollView.ScrollY);
bounds.Width,
bounds.Height);
}
parent = parent.Parent;
}
@@ -1142,8 +1153,14 @@ public abstract class SkiaView : BindableObject, IDisposable, IAccessible
/// <summary>
/// Gets the desired size calculated during measure.
/// Uses MAUI Size for public API compliance.
/// </summary>
public SKSize DesiredSize { get; protected set; }
public Size DesiredSize { get; protected set; }
/// <summary>
/// Gets the desired size as SKSize for internal SkiaSharp rendering.
/// </summary>
internal SKSize DesiredSizeSK => new SKSize((float)DesiredSize.Width, (float)DesiredSize.Height);
/// <summary>
/// Gets the child views.
@@ -1262,7 +1279,9 @@ public abstract class SkiaView : BindableObject, IDisposable, IAccessible
// Notify rendering engine of dirty region
if (Bounds.Width > 0 && Bounds.Height > 0)
{
SkiaRenderingEngine.Current?.InvalidateRegion(Bounds);
SkiaRenderingEngine.Current?.InvalidateRegion(new SKRect(
(float)Bounds.Left, (float)Bounds.Top,
(float)Bounds.Right, (float)Bounds.Bottom));
}
if (_parent != null)
@@ -1280,7 +1299,7 @@ public abstract class SkiaView : BindableObject, IDisposable, IAccessible
/// </summary>
public void InvalidateMeasure()
{
DesiredSize = SKSize.Empty;
DesiredSize = Size.Zero;
_parent?.InvalidateMeasure();
Invalidate();
}
@@ -1297,14 +1316,17 @@ public abstract class SkiaView : BindableObject, IDisposable, IAccessible
canvas.Save();
// Get SKRect for internal rendering
var skBounds = BoundsSK;
// Apply transforms if any are set
if (Scale != 1.0 || ScaleX != 1.0 || ScaleY != 1.0 ||
Rotation != 0.0 || RotationX != 0.0 || RotationY != 0.0 ||
TranslationX != 0.0 || TranslationY != 0.0)
{
// Calculate anchor point in absolute coordinates
float anchorAbsX = Bounds.Left + (float)(Bounds.Width * AnchorX);
float anchorAbsY = Bounds.Top + (float)(Bounds.Height * AnchorY);
float anchorAbsX = skBounds.Left + (float)(Bounds.Width * AnchorX);
float anchorAbsY = skBounds.Top + (float)(Bounds.Height * AnchorY);
// Move origin to anchor point
canvas.Translate(anchorAbsX, anchorAbsY);
@@ -1342,20 +1364,20 @@ public abstract class SkiaView : BindableObject, IDisposable, IAccessible
// Draw shadow if set
if (Shadow != null)
{
DrawShadow(canvas, Bounds);
DrawShadow(canvas, skBounds);
}
// Apply clip geometry if set
if (Clip != null)
{
ApplyClip(canvas, Bounds);
ApplyClip(canvas, skBounds);
}
// Draw background at absolute bounds
DrawBackground(canvas, Bounds);
DrawBackground(canvas, skBounds);
// Draw content at absolute bounds
OnDraw(canvas, Bounds);
OnDraw(canvas, skBounds);
// Draw children - they draw at their own absolute bounds
foreach (var child in _children)
@@ -1530,8 +1552,9 @@ public abstract class SkiaView : BindableObject, IDisposable, IAccessible
/// <summary>
/// Measures the desired size of this view.
/// Uses MAUI Size for public API compliance.
/// </summary>
public SKSize Measure(SKSize availableSize)
public Size Measure(Size availableSize)
{
DesiredSize = MeasureOverride(availableSize);
return DesiredSize;
@@ -1539,36 +1562,40 @@ public abstract class SkiaView : BindableObject, IDisposable, IAccessible
/// <summary>
/// Override to provide custom measurement.
/// Uses MAUI Size for public API compliance.
/// </summary>
protected virtual SKSize MeasureOverride(SKSize availableSize)
protected virtual Size MeasureOverride(Size availableSize)
{
var width = WidthRequest >= 0 ? (float)WidthRequest : 0;
var height = HeightRequest >= 0 ? (float)HeightRequest : 0;
return new SKSize(width, height);
var width = WidthRequest >= 0 ? WidthRequest : 0;
var height = HeightRequest >= 0 ? HeightRequest : 0;
return new Size(width, height);
}
/// <summary>
/// Arranges this view within the given bounds.
/// Uses MAUI Rect for public API compliance.
/// </summary>
public virtual void Arrange(SKRect bounds)
public virtual void Arrange(Rect bounds)
{
Bounds = ArrangeOverride(bounds);
}
/// <summary>
/// Override to customize arrangement within the given bounds.
/// Uses MAUI Rect for public API compliance.
/// </summary>
protected virtual SKRect ArrangeOverride(SKRect bounds)
protected virtual Rect ArrangeOverride(Rect bounds)
{
return bounds;
}
/// <summary>
/// Performs hit testing to find the view at the given point.
/// Uses MAUI Point for public API compliance.
/// </summary>
public virtual SkiaView? HitTest(SKPoint point)
public virtual SkiaView? HitTest(Point point)
{
return HitTest(point.X, point.Y);
return HitTest((float)point.X, (float)point.Y);
}
/// <summary>

View File

@@ -137,7 +137,7 @@ public class SkiaWebView : SkiaView
private string? _userAgent;
private CookieContainer _cookies = new();
private double _loadProgress;
private SKRect _lastBounds;
private Rect _lastBounds;
private int _lastMainX;
private int _lastMainY;
private int _lastPosX;
@@ -1340,7 +1340,7 @@ public class SkiaWebView : SkiaView
protected override void OnDraw(SKCanvas canvas, SKRect bounds)
{
base.OnDraw(canvas, bounds);
Bounds = bounds;
Bounds = new Rect(bounds.Left, bounds.Top, bounds.Width, bounds.Height);
if (_isInitialized)
{
@@ -1364,7 +1364,7 @@ public class SkiaWebView : SkiaView
if (needsUpdate && bounds.Width > 50f && bounds.Height > 50f)
{
PositionUsingGtk();
_lastBounds = bounds;
_lastBounds = new Rect(bounds.Left, bounds.Top, bounds.Width, bounds.Height);
}
}
}