Fixes for handlers
This commit is contained in:
@@ -536,11 +536,32 @@ public class SkiaButton : SkiaView, IButtonController
|
||||
|
||||
#region Drawing
|
||||
|
||||
/// <summary>
|
||||
/// Override to prevent base class from drawing rectangular background.
|
||||
/// Button draws its own rounded background in OnDraw.
|
||||
/// </summary>
|
||||
protected override void DrawBackground(SKCanvas canvas, SKRect bounds)
|
||||
{
|
||||
// Don't draw anything - OnDraw handles the rounded background
|
||||
}
|
||||
|
||||
protected override void OnDraw(SKCanvas canvas, SKRect bounds)
|
||||
{
|
||||
// BackgroundColor is inherited from SkiaView as MAUI Color - convert to SKColor for rendering
|
||||
var bgColor = GetEffectiveBackgroundColor();
|
||||
bool hasBackground = bgColor.Alpha > 0;
|
||||
|
||||
// Check if BackgroundColor was explicitly set (even if set to transparent)
|
||||
// This distinguishes "no background specified" from "explicitly transparent"
|
||||
bool hasExplicitBackground = BackgroundColor != null;
|
||||
|
||||
// If no background color is set, use a default button background (like other MAUI platforms)
|
||||
// This ensures buttons are visible even without explicit styling
|
||||
if (!hasExplicitBackground)
|
||||
{
|
||||
bgColor = SkiaTheme.Gray200SK; // Default button background
|
||||
}
|
||||
|
||||
bool hasBackground = hasExplicitBackground ? bgColor.Alpha > 0 : true;
|
||||
|
||||
// Determine current state color
|
||||
SKColor currentBgColor;
|
||||
@@ -571,6 +592,10 @@ public class SkiaButton : SkiaView, IButtonController
|
||||
|
||||
var roundRect = new SKRoundRect(bounds, cornerRadius);
|
||||
|
||||
// Clip to rounded rectangle to prevent background bleeding in corners
|
||||
canvas.Save();
|
||||
canvas.ClipRoundRect(roundRect, antialias: true);
|
||||
|
||||
// Draw background
|
||||
if (currentBgColor.Alpha > 0)
|
||||
{
|
||||
@@ -612,17 +637,26 @@ public class SkiaButton : SkiaView, IButtonController
|
||||
}
|
||||
|
||||
// Draw content (text and/or image)
|
||||
DrawContent(canvas, bounds);
|
||||
DrawContent(canvas, bounds, hasExplicitBackground);
|
||||
|
||||
// Restore canvas state (undo clipping)
|
||||
canvas.Restore();
|
||||
}
|
||||
|
||||
private void DrawContent(SKCanvas canvas, SKRect bounds)
|
||||
private void DrawContent(SKCanvas canvas, SKRect bounds, bool hasExplicitBackground)
|
||||
{
|
||||
var padding = Padding;
|
||||
// Handle NaN padding (default to 14, 10)
|
||||
float padLeft = float.IsNaN((float)padding.Left) ? 14f : (float)padding.Left;
|
||||
float padTop = float.IsNaN((float)padding.Top) ? 10f : (float)padding.Top;
|
||||
float padRight = float.IsNaN((float)padding.Right) ? 14f : (float)padding.Right;
|
||||
float padBottom = float.IsNaN((float)padding.Bottom) ? 10f : (float)padding.Bottom;
|
||||
|
||||
var contentBounds = new SKRect(
|
||||
bounds.Left + (float)padding.Left,
|
||||
bounds.Top + (float)padding.Top,
|
||||
bounds.Right - (float)padding.Right,
|
||||
bounds.Bottom - (float)padding.Bottom);
|
||||
bounds.Left + padLeft,
|
||||
bounds.Top + padTop,
|
||||
bounds.Right - padRight,
|
||||
bounds.Bottom - padBottom);
|
||||
|
||||
// Prepare font
|
||||
bool isBold = FontAttributes.HasFlag(FontAttributes.Bold);
|
||||
@@ -640,8 +674,24 @@ public class SkiaButton : SkiaView, IButtonController
|
||||
SkiaRenderingEngine.Current?.ResourceCache.GetTypeface(fontFamily, fontStyle) ?? SKTypeface.Default,
|
||||
fontSize);
|
||||
|
||||
// Prepare text color (null means use platform default: white for buttons)
|
||||
var textColor = TextColor != null ? ToSKColor(TextColor) : SkiaTheme.BackgroundWhiteSK;
|
||||
// Prepare text color
|
||||
// If TextColor is set, use it; otherwise use a sensible default based on background
|
||||
SKColor textColor;
|
||||
if (TextColor != null)
|
||||
{
|
||||
textColor = ToSKColor(TextColor);
|
||||
}
|
||||
else if (hasExplicitBackground)
|
||||
{
|
||||
// Explicit background but no text color - use white (common for colored buttons)
|
||||
textColor = SkiaTheme.BackgroundWhiteSK;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Default button (gray background) - use dark text for contrast
|
||||
textColor = SkiaTheme.Gray800SK;
|
||||
}
|
||||
|
||||
if (!IsEnabled)
|
||||
{
|
||||
textColor = textColor.WithAlpha(128);
|
||||
@@ -945,6 +995,11 @@ public class SkiaButton : SkiaView, IButtonController
|
||||
var padding = Padding;
|
||||
float paddingH = (float)(padding.Left + padding.Right);
|
||||
float paddingV = (float)(padding.Top + padding.Bottom);
|
||||
|
||||
// Handle NaN padding (can happen with style resolution issues)
|
||||
if (float.IsNaN(paddingH)) paddingH = 28f; // Default: 14 + 14
|
||||
if (float.IsNaN(paddingV)) paddingV = 20f; // Default: 10 + 10
|
||||
|
||||
float fontSize = FontSize > 0 ? (float)FontSize : 14f;
|
||||
|
||||
// Prepare font for measurement
|
||||
@@ -978,7 +1033,9 @@ public class SkiaButton : SkiaView, IButtonController
|
||||
{
|
||||
textWidth += (float)(CharacterSpacing * (displayText.Length - 1));
|
||||
}
|
||||
textHeight = textBounds.Height;
|
||||
// Use font metrics for proper line height (ascent is negative)
|
||||
var metrics = font.Metrics;
|
||||
textHeight = metrics.Descent - metrics.Ascent;
|
||||
}
|
||||
|
||||
float imageWidth = 0, imageHeight = 0;
|
||||
@@ -1037,7 +1094,10 @@ public class SkiaButton : SkiaView, IButtonController
|
||||
height = (float)HeightRequest;
|
||||
}
|
||||
|
||||
return new Size(Math.Max(width, 44f), Math.Max(height, 30f));
|
||||
var result = new Size(Math.Max(width, 44f), Math.Max(height, 36f));
|
||||
if (Text == "Round")
|
||||
Console.WriteLine($"[SkiaButton.Measure] Text='Round' WReq={WidthRequest} HReq={HeightRequest} width={width:F1} height={height:F1} result={result.Width:F0}x{result.Height:F0}");
|
||||
return result;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -921,7 +921,14 @@ public class SkiaEditor : SkiaView, IInputContext
|
||||
Color = GetEffectivePlaceholderColor(),
|
||||
IsAntialias = true
|
||||
};
|
||||
canvas.DrawText(Placeholder, contentRect.Left, contentRect.Top + fontSize, placeholderPaint);
|
||||
// Handle multiline placeholder text by splitting on newlines
|
||||
var placeholderLines = Placeholder.Split('\n');
|
||||
var y = contentRect.Top + fontSize;
|
||||
foreach (var line in placeholderLines)
|
||||
{
|
||||
canvas.DrawText(line, contentRect.Left, y, placeholderPaint);
|
||||
y += lineSpacing;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -361,7 +361,11 @@ public class SkiaStackLayout : SkiaLayoutView
|
||||
float maxWidth = 0;
|
||||
float maxHeight = 0;
|
||||
|
||||
var childAvailable = new Size(contentWidth, contentHeight);
|
||||
// For stack layouts, give children infinite size in the stacking direction
|
||||
// so they can measure to their natural size
|
||||
var childAvailable = Orientation == StackOrientation.Horizontal
|
||||
? new Size(double.PositiveInfinity, contentHeight) // Horizontal: infinite width, constrained height
|
||||
: new Size(contentWidth, double.PositiveInfinity); // Vertical: constrained width, infinite height
|
||||
|
||||
foreach (var child in Children)
|
||||
{
|
||||
@@ -447,11 +451,9 @@ public class SkiaStackLayout : SkiaLayoutView
|
||||
}
|
||||
else
|
||||
{
|
||||
// For ScrollView children, give them the remaining viewport width
|
||||
var remainingWidth = Math.Max(0, contentWidth - offset);
|
||||
var useWidth = child is SkiaScrollView
|
||||
? remainingWidth
|
||||
: Math.Min(childWidth, remainingWidth > 0 ? remainingWidth : childWidth);
|
||||
// Horizontal stack: give each child its measured width
|
||||
// Don't constrain - let content overflow if needed (parent clips)
|
||||
var useWidth = childWidth;
|
||||
|
||||
// Respect child's VerticalOptions for horizontal layouts
|
||||
var useHeight = Math.Min(childHeight, contentHeight);
|
||||
|
||||
@@ -295,12 +295,36 @@ public class SkiaScrollView : SkiaView
|
||||
var contentDesired = _content.Measure(availableSize);
|
||||
ContentSize = new SKSize((float)contentDesired.Width, (float)contentDesired.Height);
|
||||
|
||||
// Apply content's margin
|
||||
// Apply content's margin and arrange based on scroll orientation
|
||||
var margin = _content.Margin;
|
||||
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;
|
||||
|
||||
// Content dimensions depend on scroll orientation
|
||||
float contentWidth, contentHeight;
|
||||
switch (Orientation)
|
||||
{
|
||||
case ScrollOrientation.Horizontal:
|
||||
contentWidth = Math.Max(bounds.Width, (float)_content.DesiredSize.Width);
|
||||
contentHeight = bounds.Height;
|
||||
break;
|
||||
case ScrollOrientation.Neither:
|
||||
contentWidth = bounds.Width;
|
||||
contentHeight = bounds.Height;
|
||||
break;
|
||||
case ScrollOrientation.Both:
|
||||
contentWidth = Math.Max(bounds.Width, (float)_content.DesiredSize.Width);
|
||||
contentHeight = Math.Max(bounds.Height, (float)_content.DesiredSize.Height);
|
||||
break;
|
||||
case ScrollOrientation.Vertical:
|
||||
default:
|
||||
contentWidth = bounds.Width;
|
||||
contentHeight = Math.Max(bounds.Height, (float)_content.DesiredSize.Height);
|
||||
break;
|
||||
}
|
||||
|
||||
contentWidth -= (float)margin.Left + (float)margin.Right;
|
||||
contentHeight -= (float)margin.Top + (float)margin.Bottom;
|
||||
var contentBounds = new Rect(contentLeft, contentTop, contentWidth, contentHeight);
|
||||
_content.Arrange(contentBounds);
|
||||
|
||||
@@ -858,12 +882,41 @@ public class SkiaScrollView : SkiaView
|
||||
|
||||
if (_content != null)
|
||||
{
|
||||
// Apply content's margin and arrange content at its full size
|
||||
// Apply content's margin and arrange content based on scroll orientation
|
||||
var margin = _content.Margin;
|
||||
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;
|
||||
|
||||
// Content dimensions depend on scroll orientation:
|
||||
// - Vertical: width constrained to viewport, height can expand
|
||||
// - Horizontal: width can expand, height constrained to viewport
|
||||
// - Both: both can expand
|
||||
// - Neither: both constrained to viewport
|
||||
float contentWidth, contentHeight;
|
||||
switch (Orientation)
|
||||
{
|
||||
case ScrollOrientation.Horizontal:
|
||||
contentWidth = Math.Max((float)actualBounds.Width, ContentSize.Width);
|
||||
contentHeight = (float)actualBounds.Height;
|
||||
break;
|
||||
case ScrollOrientation.Neither:
|
||||
contentWidth = (float)actualBounds.Width;
|
||||
contentHeight = (float)actualBounds.Height;
|
||||
break;
|
||||
case ScrollOrientation.Both:
|
||||
contentWidth = Math.Max((float)actualBounds.Width, ContentSize.Width);
|
||||
contentHeight = Math.Max((float)actualBounds.Height, ContentSize.Height);
|
||||
break;
|
||||
case ScrollOrientation.Vertical:
|
||||
default:
|
||||
// Vertical scroll: constrain width to viewport, allow height to expand
|
||||
contentWidth = (float)actualBounds.Width;
|
||||
contentHeight = Math.Max((float)actualBounds.Height, ContentSize.Height);
|
||||
break;
|
||||
}
|
||||
|
||||
contentWidth -= (float)margin.Left + (float)margin.Right;
|
||||
contentHeight -= (float)margin.Top + (float)margin.Bottom;
|
||||
var contentBounds = new Rect(contentLeft, contentTop, contentWidth, contentHeight);
|
||||
|
||||
_content.Arrange(contentBounds);
|
||||
|
||||
@@ -109,7 +109,8 @@ public class SkiaSearchBar : SkiaView
|
||||
BackgroundColor = Colors.Transparent,
|
||||
BorderColor = Colors.Transparent,
|
||||
FocusedBorderColor = Colors.Transparent,
|
||||
BorderWidth = 0
|
||||
BorderWidth = 0,
|
||||
VerticalTextAlignment = TextAlignment.Center
|
||||
};
|
||||
|
||||
_entry.TextChanged += (s, e) =>
|
||||
|
||||
Reference in New Issue
Block a user