Update with recovered code from VM binaries (Jan 1)

Recovered from decompiled OpenMaui.Controls.Linux.dll:
- SkiaShell.cs: FlyoutHeader, FlyoutFooter, scroll support (918 -> 1325 lines)
- X11Window.cs: Cursor support (XCreateFontCursor, XDefineCursor)
- All handlers with dark mode support
- All services with latest implementations
- LinuxApplication with theme change handling
This commit is contained in:
2026-01-01 06:22:48 -05:00
parent 1e84c6168a
commit 1f096c38dc
254 changed files with 49359 additions and 38457 deletions

143
Views/SkiaAbsoluteLayout.cs Normal file
View File

@@ -0,0 +1,143 @@
using System;
using System.Collections.Generic;
using SkiaSharp;
namespace Microsoft.Maui.Platform;
public class SkiaAbsoluteLayout : SkiaLayoutView
{
private readonly Dictionary<SkiaView, AbsoluteLayoutBounds> _childBounds = new Dictionary<SkiaView, AbsoluteLayoutBounds>();
public void AddChild(SkiaView child, SKRect bounds, AbsoluteLayoutFlags flags = AbsoluteLayoutFlags.None)
{
//IL_000e: Unknown result type (might be due to invalid IL or missing references)
base.AddChild(child);
_childBounds[child] = new AbsoluteLayoutBounds(bounds, flags);
}
public override void RemoveChild(SkiaView child)
{
base.RemoveChild(child);
_childBounds.Remove(child);
}
public AbsoluteLayoutBounds GetLayoutBounds(SkiaView child)
{
//IL_0010: Unknown result type (might be due to invalid IL or missing references)
if (!_childBounds.TryGetValue(child, out var value))
{
return new AbsoluteLayoutBounds(SKRect.Empty, AbsoluteLayoutFlags.None);
}
return value;
}
public void SetLayoutBounds(SkiaView child, SKRect bounds, AbsoluteLayoutFlags flags = AbsoluteLayoutFlags.None)
{
//IL_0007: Unknown result type (might be due to invalid IL or missing references)
_childBounds[child] = new AbsoluteLayoutBounds(bounds, flags);
InvalidateMeasure();
Invalidate();
}
protected override SKSize MeasureOverride(SKSize availableSize)
{
//IL_0034: Unknown result type (might be due to invalid IL or missing references)
//IL_0039: Unknown result type (might be due to invalid IL or missing references)
//IL_004a: Unknown result type (might be due to invalid IL or missing references)
//IL_004f: Unknown result type (might be due to invalid IL or missing references)
//IL_0087: Unknown result type (might be due to invalid IL or missing references)
//IL_008c: Unknown result type (might be due to invalid IL or missing references)
//IL_0097: Unknown result type (might be due to invalid IL or missing references)
//IL_009c: Unknown result type (might be due to invalid IL or missing references)
//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
//IL_00c7: Unknown result type (might be due to invalid IL or missing references)
float num = 0f;
float num2 = 0f;
foreach (SkiaView child in base.Children)
{
if (child.IsVisible)
{
SKRect bounds = GetLayoutBounds(child).Bounds;
child.Measure(new SKSize(((SKRect)(ref bounds)).Width, ((SKRect)(ref bounds)).Height));
num = Math.Max(num, ((SKRect)(ref bounds)).Right);
num2 = Math.Max(num2, ((SKRect)(ref bounds)).Bottom);
}
}
float num3 = num;
SKRect padding = base.Padding;
float num4 = num3 + ((SKRect)(ref padding)).Left;
padding = base.Padding;
float num5 = num4 + ((SKRect)(ref padding)).Right;
float num6 = num2;
padding = base.Padding;
float num7 = num6 + ((SKRect)(ref padding)).Top;
padding = base.Padding;
return new SKSize(num5, num7 + ((SKRect)(ref padding)).Bottom);
}
protected override SKRect ArrangeOverride(SKRect bounds)
{
//IL_0001: Unknown result type (might be due to invalid IL or missing references)
//IL_0002: Unknown result type (might be due to invalid IL or missing references)
//IL_0007: Unknown result type (might be due to invalid IL or missing references)
//IL_0035: Unknown result type (might be due to invalid IL or missing references)
//IL_003a: Unknown result type (might be due to invalid IL or missing references)
//IL_01c7: Unknown result type (might be due to invalid IL or missing references)
//IL_00fb: Unknown result type (might be due to invalid IL or missing references)
//IL_0100: Unknown result type (might be due to invalid IL or missing references)
//IL_014c: Unknown result type (might be due to invalid IL or missing references)
//IL_0151: Unknown result type (might be due to invalid IL or missing references)
//IL_0168: Unknown result type (might be due to invalid IL or missing references)
//IL_016d: Unknown result type (might be due to invalid IL or missing references)
//IL_01a9: Unknown result type (might be due to invalid IL or missing references)
SKRect contentBounds = GetContentBounds(bounds);
SKRect bounds3 = default(SKRect);
foreach (SkiaView child in base.Children)
{
if (child.IsVisible)
{
AbsoluteLayoutBounds layoutBounds = GetLayoutBounds(child);
SKRect bounds2 = layoutBounds.Bounds;
AbsoluteLayoutFlags flags = layoutBounds.Flags;
float num = ((!flags.HasFlag(AbsoluteLayoutFlags.XProportional)) ? (((SKRect)(ref contentBounds)).Left + ((SKRect)(ref bounds2)).Left) : (((SKRect)(ref contentBounds)).Left + ((SKRect)(ref bounds2)).Left * ((SKRect)(ref contentBounds)).Width));
float num2 = ((!flags.HasFlag(AbsoluteLayoutFlags.YProportional)) ? (((SKRect)(ref contentBounds)).Top + ((SKRect)(ref bounds2)).Top) : (((SKRect)(ref contentBounds)).Top + ((SKRect)(ref bounds2)).Top * ((SKRect)(ref contentBounds)).Height));
float num3;
SKSize desiredSize;
if (flags.HasFlag(AbsoluteLayoutFlags.WidthProportional))
{
num3 = ((SKRect)(ref bounds2)).Width * ((SKRect)(ref contentBounds)).Width;
}
else if (((SKRect)(ref bounds2)).Width < 0f)
{
desiredSize = child.DesiredSize;
num3 = ((SKSize)(ref desiredSize)).Width;
}
else
{
num3 = ((SKRect)(ref bounds2)).Width;
}
float num4;
if (flags.HasFlag(AbsoluteLayoutFlags.HeightProportional))
{
num4 = ((SKRect)(ref bounds2)).Height * ((SKRect)(ref contentBounds)).Height;
}
else if (((SKRect)(ref bounds2)).Height < 0f)
{
desiredSize = child.DesiredSize;
num4 = ((SKSize)(ref desiredSize)).Height;
}
else
{
num4 = ((SKRect)(ref bounds2)).Height;
}
Thickness margin = child.Margin;
((SKRect)(ref bounds3))._002Ector(num + (float)((Thickness)(ref margin)).Left, num2 + (float)((Thickness)(ref margin)).Top, num + num3 - (float)((Thickness)(ref margin)).Right, num2 + num4 - (float)((Thickness)(ref margin)).Bottom);
child.Arrange(bounds3);
}
}
return bounds;
}
}

View File

@@ -1,238 +1,222 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System;
using Microsoft.Maui.Controls;
using SkiaSharp;
namespace Microsoft.Maui.Platform;
/// <summary>
/// Skia-rendered activity indicator (spinner) control with full XAML styling support.
/// </summary>
public class SkiaActivityIndicator : SkiaView
{
#region BindableProperties
public static readonly BindableProperty IsRunningProperty = BindableProperty.Create("IsRunning", typeof(bool), typeof(SkiaActivityIndicator), (object)false, (BindingMode)2, (ValidateValueDelegate)null, (BindingPropertyChangedDelegate)delegate(BindableObject b, object o, object n)
{
((SkiaActivityIndicator)(object)b).OnIsRunningChanged();
}, (BindingPropertyChangingDelegate)null, (CoerceValueDelegate)null, (CreateDefaultValueDelegate)null);
/// <summary>
/// Bindable property for IsRunning.
/// </summary>
public static readonly BindableProperty IsRunningProperty =
BindableProperty.Create(
nameof(IsRunning),
typeof(bool),
typeof(SkiaActivityIndicator),
false,
propertyChanged: (b, o, n) => ((SkiaActivityIndicator)b).OnIsRunningChanged());
public static readonly BindableProperty ColorProperty = BindableProperty.Create("Color", typeof(SKColor), typeof(SkiaActivityIndicator), (object)new SKColor((byte)33, (byte)150, (byte)243), (BindingMode)2, (ValidateValueDelegate)null, (BindingPropertyChangedDelegate)delegate(BindableObject b, object o, object n)
{
((SkiaActivityIndicator)(object)b).Invalidate();
}, (BindingPropertyChangingDelegate)null, (CoerceValueDelegate)null, (CreateDefaultValueDelegate)null);
/// <summary>
/// Bindable property for Color.
/// </summary>
public static readonly BindableProperty ColorProperty =
BindableProperty.Create(
nameof(Color),
typeof(SKColor),
typeof(SkiaActivityIndicator),
new SKColor(0x21, 0x96, 0xF3),
propertyChanged: (b, o, n) => ((SkiaActivityIndicator)b).Invalidate());
public static readonly BindableProperty DisabledColorProperty = BindableProperty.Create("DisabledColor", typeof(SKColor), typeof(SkiaActivityIndicator), (object)new SKColor((byte)189, (byte)189, (byte)189), (BindingMode)2, (ValidateValueDelegate)null, (BindingPropertyChangedDelegate)delegate(BindableObject b, object o, object n)
{
((SkiaActivityIndicator)(object)b).Invalidate();
}, (BindingPropertyChangingDelegate)null, (CoerceValueDelegate)null, (CreateDefaultValueDelegate)null);
/// <summary>
/// Bindable property for DisabledColor.
/// </summary>
public static readonly BindableProperty DisabledColorProperty =
BindableProperty.Create(
nameof(DisabledColor),
typeof(SKColor),
typeof(SkiaActivityIndicator),
new SKColor(0xBD, 0xBD, 0xBD),
propertyChanged: (b, o, n) => ((SkiaActivityIndicator)b).Invalidate());
public static readonly BindableProperty SizeProperty = BindableProperty.Create("Size", typeof(float), typeof(SkiaActivityIndicator), (object)32f, (BindingMode)2, (ValidateValueDelegate)null, (BindingPropertyChangedDelegate)delegate(BindableObject b, object o, object n)
{
((SkiaActivityIndicator)(object)b).InvalidateMeasure();
}, (BindingPropertyChangingDelegate)null, (CoerceValueDelegate)null, (CreateDefaultValueDelegate)null);
/// <summary>
/// Bindable property for Size.
/// </summary>
public static readonly BindableProperty SizeProperty =
BindableProperty.Create(
nameof(Size),
typeof(float),
typeof(SkiaActivityIndicator),
32f,
propertyChanged: (b, o, n) => ((SkiaActivityIndicator)b).InvalidateMeasure());
public static readonly BindableProperty StrokeWidthProperty = BindableProperty.Create("StrokeWidth", typeof(float), typeof(SkiaActivityIndicator), (object)3f, (BindingMode)2, (ValidateValueDelegate)null, (BindingPropertyChangedDelegate)delegate(BindableObject b, object o, object n)
{
((SkiaActivityIndicator)(object)b).InvalidateMeasure();
}, (BindingPropertyChangingDelegate)null, (CoerceValueDelegate)null, (CreateDefaultValueDelegate)null);
/// <summary>
/// Bindable property for StrokeWidth.
/// </summary>
public static readonly BindableProperty StrokeWidthProperty =
BindableProperty.Create(
nameof(StrokeWidth),
typeof(float),
typeof(SkiaActivityIndicator),
3f,
propertyChanged: (b, o, n) => ((SkiaActivityIndicator)b).InvalidateMeasure());
public static readonly BindableProperty RotationSpeedProperty = BindableProperty.Create("RotationSpeed", typeof(float), typeof(SkiaActivityIndicator), (object)360f, (BindingMode)2, (ValidateValueDelegate)null, (BindingPropertyChangedDelegate)null, (BindingPropertyChangingDelegate)null, (CoerceValueDelegate)null, (CreateDefaultValueDelegate)null);
/// <summary>
/// Bindable property for RotationSpeed.
/// </summary>
public static readonly BindableProperty RotationSpeedProperty =
BindableProperty.Create(
nameof(RotationSpeed),
typeof(float),
typeof(SkiaActivityIndicator),
360f);
public static readonly BindableProperty ArcCountProperty = BindableProperty.Create("ArcCount", typeof(int), typeof(SkiaActivityIndicator), (object)12, (BindingMode)2, (ValidateValueDelegate)null, (BindingPropertyChangedDelegate)delegate(BindableObject b, object o, object n)
{
((SkiaActivityIndicator)(object)b).Invalidate();
}, (BindingPropertyChangingDelegate)null, (CoerceValueDelegate)null, (CreateDefaultValueDelegate)null);
/// <summary>
/// Bindable property for ArcCount.
/// </summary>
public static readonly BindableProperty ArcCountProperty =
BindableProperty.Create(
nameof(ArcCount),
typeof(int),
typeof(SkiaActivityIndicator),
12,
propertyChanged: (b, o, n) => ((SkiaActivityIndicator)b).Invalidate());
private float _rotationAngle;
#endregion
private DateTime _lastUpdateTime = DateTime.UtcNow;
#region Properties
public bool IsRunning
{
get
{
return (bool)((BindableObject)this).GetValue(IsRunningProperty);
}
set
{
((BindableObject)this).SetValue(IsRunningProperty, (object)value);
}
}
/// <summary>
/// Gets or sets whether the indicator is running.
/// </summary>
public bool IsRunning
{
get => (bool)GetValue(IsRunningProperty);
set => SetValue(IsRunningProperty, value);
}
public SKColor Color
{
get
{
//IL_000b: Unknown result type (might be due to invalid IL or missing references)
return (SKColor)((BindableObject)this).GetValue(ColorProperty);
}
set
{
//IL_0006: Unknown result type (might be due to invalid IL or missing references)
((BindableObject)this).SetValue(ColorProperty, (object)value);
}
}
/// <summary>
/// Gets or sets the indicator color.
/// </summary>
public SKColor Color
{
get => (SKColor)GetValue(ColorProperty);
set => SetValue(ColorProperty, value);
}
public SKColor DisabledColor
{
get
{
//IL_000b: Unknown result type (might be due to invalid IL or missing references)
return (SKColor)((BindableObject)this).GetValue(DisabledColorProperty);
}
set
{
//IL_0006: Unknown result type (might be due to invalid IL or missing references)
((BindableObject)this).SetValue(DisabledColorProperty, (object)value);
}
}
/// <summary>
/// Gets or sets the disabled color.
/// </summary>
public SKColor DisabledColor
{
get => (SKColor)GetValue(DisabledColorProperty);
set => SetValue(DisabledColorProperty, value);
}
public float Size
{
get
{
return (float)((BindableObject)this).GetValue(SizeProperty);
}
set
{
((BindableObject)this).SetValue(SizeProperty, (object)value);
}
}
/// <summary>
/// Gets or sets the indicator size.
/// </summary>
public float Size
{
get => (float)GetValue(SizeProperty);
set => SetValue(SizeProperty, value);
}
public float StrokeWidth
{
get
{
return (float)((BindableObject)this).GetValue(StrokeWidthProperty);
}
set
{
((BindableObject)this).SetValue(StrokeWidthProperty, (object)value);
}
}
/// <summary>
/// Gets or sets the stroke width.
/// </summary>
public float StrokeWidth
{
get => (float)GetValue(StrokeWidthProperty);
set => SetValue(StrokeWidthProperty, value);
}
public float RotationSpeed
{
get
{
return (float)((BindableObject)this).GetValue(RotationSpeedProperty);
}
set
{
((BindableObject)this).SetValue(RotationSpeedProperty, (object)value);
}
}
/// <summary>
/// Gets or sets the rotation speed in degrees per second.
/// </summary>
public float RotationSpeed
{
get => (float)GetValue(RotationSpeedProperty);
set => SetValue(RotationSpeedProperty, value);
}
public int ArcCount
{
get
{
return (int)((BindableObject)this).GetValue(ArcCountProperty);
}
set
{
((BindableObject)this).SetValue(ArcCountProperty, (object)value);
}
}
/// <summary>
/// Gets or sets the number of arcs.
/// </summary>
public int ArcCount
{
get => (int)GetValue(ArcCountProperty);
set => SetValue(ArcCountProperty, value);
}
private void OnIsRunningChanged()
{
if (IsRunning)
{
_lastUpdateTime = DateTime.UtcNow;
}
Invalidate();
}
#endregion
protected override void OnDraw(SKCanvas canvas, SKRect bounds)
{
//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
//IL_00d1: Unknown result type (might be due to invalid IL or missing references)
//IL_00f8: Unknown result type (might be due to invalid IL or missing references)
//IL_00fd: Unknown result type (might be due to invalid IL or missing references)
//IL_00ff: Unknown result type (might be due to invalid IL or missing references)
//IL_0104: Unknown result type (might be due to invalid IL or missing references)
//IL_0105: Unknown result type (might be due to invalid IL or missing references)
//IL_010c: Unknown result type (might be due to invalid IL or missing references)
//IL_0113: Unknown result type (might be due to invalid IL or missing references)
//IL_011a: Unknown result type (might be due to invalid IL or missing references)
//IL_0126: Unknown result type (might be due to invalid IL or missing references)
//IL_012f: Expected O, but got Unknown
//IL_0157: Unknown result type (might be due to invalid IL or missing references)
//IL_015e: Expected O, but got Unknown
//IL_0166: Unknown result type (might be due to invalid IL or missing references)
if (!IsRunning && !base.IsEnabled)
{
return;
}
float midX = ((SKRect)(ref bounds)).MidX;
float midY = ((SKRect)(ref bounds)).MidY;
float num = Math.Min(Size / 2f, Math.Min(((SKRect)(ref bounds)).Width, ((SKRect)(ref bounds)).Height) / 2f) - StrokeWidth;
if (IsRunning)
{
DateTime utcNow = DateTime.UtcNow;
double totalSeconds = (utcNow - _lastUpdateTime).TotalSeconds;
_lastUpdateTime = utcNow;
_rotationAngle = (_rotationAngle + (float)((double)RotationSpeed * totalSeconds)) % 360f;
}
canvas.Save();
canvas.Translate(midX, midY);
canvas.RotateDegrees(_rotationAngle);
SKColor val = (base.IsEnabled ? Color : DisabledColor);
for (int i = 0; i < ArcCount; i++)
{
byte b = (byte)(255f * (1f - (float)i / (float)ArcCount));
SKColor color = ((SKColor)(ref val)).WithAlpha(b);
SKPaint val2 = new SKPaint
{
Color = color,
IsAntialias = true,
Style = (SKPaintStyle)1,
StrokeWidth = StrokeWidth,
StrokeCap = (SKStrokeCap)1
};
try
{
float num2 = 360f / (float)ArcCount * (float)i;
float num3 = 360f / (float)ArcCount / 2f;
SKPath val3 = new SKPath();
try
{
val3.AddArc(new SKRect(0f - num, 0f - num, num, num), num2, num3);
canvas.DrawPath(val3, val2);
}
finally
{
((IDisposable)val3)?.Dispose();
}
}
finally
{
((IDisposable)val2)?.Dispose();
}
}
canvas.Restore();
if (IsRunning)
{
Invalidate();
}
}
private float _rotationAngle;
private DateTime _lastUpdateTime = DateTime.UtcNow;
private void OnIsRunningChanged()
{
if (IsRunning)
{
_lastUpdateTime = DateTime.UtcNow;
}
Invalidate();
}
protected override void OnDraw(SKCanvas canvas, SKRect bounds)
{
if (!IsRunning && !IsEnabled)
{
return;
}
var centerX = bounds.MidX;
var centerY = bounds.MidY;
var radius = Math.Min(Size / 2, Math.Min(bounds.Width, bounds.Height) / 2) - StrokeWidth;
// Update rotation
if (IsRunning)
{
var now = DateTime.UtcNow;
var elapsed = (now - _lastUpdateTime).TotalSeconds;
_lastUpdateTime = now;
_rotationAngle = (_rotationAngle + (float)(RotationSpeed * elapsed)) % 360;
}
canvas.Save();
canvas.Translate(centerX, centerY);
canvas.RotateDegrees(_rotationAngle);
var color = IsEnabled ? Color : DisabledColor;
// Draw arcs with varying opacity
for (int i = 0; i < ArcCount; i++)
{
var alpha = (byte)(255 * (1 - (float)i / ArcCount));
var arcColor = color.WithAlpha(alpha);
using var paint = new SKPaint
{
Color = arcColor,
IsAntialias = true,
Style = SKPaintStyle.Stroke,
StrokeWidth = StrokeWidth,
StrokeCap = SKStrokeCap.Round
};
var startAngle = (360f / ArcCount) * i;
var sweepAngle = 360f / ArcCount / 2;
using var path = new SKPath();
path.AddArc(
new SKRect(-radius, -radius, radius, radius),
startAngle,
sweepAngle);
canvas.DrawPath(path, paint);
}
canvas.Restore();
// Request redraw for animation
if (IsRunning)
{
Invalidate();
}
}
protected override SKSize MeasureOverride(SKSize availableSize)
{
return new SKSize(Size + StrokeWidth * 2, Size + StrokeWidth * 2);
}
protected override SKSize MeasureOverride(SKSize availableSize)
{
//IL_0026: Unknown result type (might be due to invalid IL or missing references)
return new SKSize(Size + StrokeWidth * 2f, Size + StrokeWidth * 2f);
}
}

View File

@@ -1,385 +1,440 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using SkiaSharp;
namespace Microsoft.Maui.Platform;
/// <summary>
/// A modal alert dialog rendered with Skia.
/// Supports title, message, and up to two buttons (cancel/accept).
/// </summary>
public class SkiaAlertDialog : SkiaView
{
private readonly string _title;
private readonly string _message;
private readonly string? _cancel;
private readonly string? _accept;
private readonly TaskCompletionSource<bool> _tcs;
private readonly string _title;
private SKRect _cancelButtonBounds;
private SKRect _acceptButtonBounds;
private bool _cancelHovered;
private bool _acceptHovered;
private readonly string _message;
// Dialog styling
private static readonly SKColor OverlayColor = new SKColor(0, 0, 0, 128);
private static readonly SKColor DialogBackground = SKColors.White;
private static readonly SKColor TitleColor = new SKColor(0x21, 0x21, 0x21);
private static readonly SKColor MessageColor = new SKColor(0x61, 0x61, 0x61);
private static readonly SKColor ButtonColor = new SKColor(0x21, 0x96, 0xF3);
private static readonly SKColor ButtonHoverColor = new SKColor(0x19, 0x76, 0xD2);
private static readonly SKColor ButtonTextColor = SKColors.White;
private static readonly SKColor CancelButtonColor = new SKColor(0x9E, 0x9E, 0x9E);
private static readonly SKColor CancelButtonHoverColor = new SKColor(0x75, 0x75, 0x75);
private static readonly SKColor BorderColor = new SKColor(0xE0, 0xE0, 0xE0);
private readonly string? _cancel;
private const float DialogWidth = 400;
private const float DialogPadding = 24;
private const float ButtonHeight = 44;
private const float ButtonSpacing = 12;
private const float CornerRadius = 12;
private readonly string? _accept;
/// <summary>
/// Creates a new alert dialog.
/// </summary>
public SkiaAlertDialog(string title, string message, string? accept, string? cancel)
{
_title = title;
_message = message;
_accept = accept;
_cancel = cancel;
_tcs = new TaskCompletionSource<bool>();
IsFocusable = true;
}
private readonly TaskCompletionSource<bool> _tcs;
/// <summary>
/// Gets the task that completes when the dialog is dismissed.
/// Returns true if accept was clicked, false if cancel was clicked.
/// </summary>
public Task<bool> Result => _tcs.Task;
private SKRect _cancelButtonBounds;
protected override void OnDraw(SKCanvas canvas, SKRect bounds)
{
// Draw semi-transparent overlay covering entire screen
using var overlayPaint = new SKPaint
{
Color = OverlayColor,
Style = SKPaintStyle.Fill
};
canvas.DrawRect(bounds, overlayPaint);
private SKRect _acceptButtonBounds;
// Calculate dialog dimensions
var messageLines = WrapText(_message, DialogWidth - DialogPadding * 2, 16);
var dialogHeight = CalculateDialogHeight(messageLines.Count);
private bool _cancelHovered;
var dialogLeft = bounds.MidX - DialogWidth / 2;
var dialogTop = bounds.MidY - dialogHeight / 2;
var dialogBounds = new SKRect(dialogLeft, dialogTop, dialogLeft + DialogWidth, dialogTop + dialogHeight);
private bool _acceptHovered;
// Draw dialog shadow
using var shadowPaint = new SKPaint
{
Color = new SKColor(0, 0, 0, 60),
MaskFilter = SKMaskFilter.CreateBlur(SKBlurStyle.Normal, 8),
Style = SKPaintStyle.Fill
};
var shadowRect = new SKRect(dialogBounds.Left + 4, dialogBounds.Top + 4,
dialogBounds.Right + 4, dialogBounds.Bottom + 4);
canvas.DrawRoundRect(shadowRect, CornerRadius, CornerRadius, shadowPaint);
private static readonly SKColor OverlayColor = new SKColor((byte)0, (byte)0, (byte)0, (byte)128);
// Draw dialog background
using var bgPaint = new SKPaint
{
Color = DialogBackground,
Style = SKPaintStyle.Fill,
IsAntialias = true
};
canvas.DrawRoundRect(dialogBounds, CornerRadius, CornerRadius, bgPaint);
private static readonly SKColor DialogBackground = SKColors.White;
// Draw title
var yOffset = dialogBounds.Top + DialogPadding;
if (!string.IsNullOrEmpty(_title))
{
using var titleFont = new SKFont(SKTypeface.Default, 20) { Embolden = true };
using var titlePaint = new SKPaint(titleFont)
{
Color = TitleColor,
IsAntialias = true
};
canvas.DrawText(_title, dialogBounds.Left + DialogPadding, yOffset + 20, titlePaint);
yOffset += 36;
}
private static readonly SKColor TitleColor = new SKColor((byte)33, (byte)33, (byte)33);
// Draw message
if (!string.IsNullOrEmpty(_message))
{
using var messageFont = new SKFont(SKTypeface.Default, 16);
using var messagePaint = new SKPaint(messageFont)
{
Color = MessageColor,
IsAntialias = true
};
private static readonly SKColor MessageColor = new SKColor((byte)97, (byte)97, (byte)97);
foreach (var line in messageLines)
{
canvas.DrawText(line, dialogBounds.Left + DialogPadding, yOffset + 16, messagePaint);
yOffset += 22;
}
yOffset += 8;
}
private static readonly SKColor ButtonColor = new SKColor((byte)33, (byte)150, (byte)243);
// Draw buttons
yOffset = dialogBounds.Bottom - DialogPadding - ButtonHeight;
var buttonY = yOffset;
private static readonly SKColor ButtonHoverColor = new SKColor((byte)25, (byte)118, (byte)210);
var buttonCount = (_accept != null ? 1 : 0) + (_cancel != null ? 1 : 0);
var totalButtonWidth = DialogWidth - DialogPadding * 2;
private static readonly SKColor ButtonTextColor = SKColors.White;
if (buttonCount == 2)
{
var singleButtonWidth = (totalButtonWidth - ButtonSpacing) / 2;
private static readonly SKColor CancelButtonColor = new SKColor((byte)158, (byte)158, (byte)158);
// Cancel button (left)
_cancelButtonBounds = new SKRect(
dialogBounds.Left + DialogPadding,
buttonY,
dialogBounds.Left + DialogPadding + singleButtonWidth,
buttonY + ButtonHeight);
DrawButton(canvas, _cancelButtonBounds, _cancel!,
_cancelHovered ? CancelButtonHoverColor : CancelButtonColor);
private static readonly SKColor CancelButtonHoverColor = new SKColor((byte)117, (byte)117, (byte)117);
// Accept button (right)
_acceptButtonBounds = new SKRect(
dialogBounds.Right - DialogPadding - singleButtonWidth,
buttonY,
dialogBounds.Right - DialogPadding,
buttonY + ButtonHeight);
DrawButton(canvas, _acceptButtonBounds, _accept!,
_acceptHovered ? ButtonHoverColor : ButtonColor);
}
else if (_accept != null)
{
_acceptButtonBounds = new SKRect(
dialogBounds.Left + DialogPadding,
buttonY,
dialogBounds.Right - DialogPadding,
buttonY + ButtonHeight);
DrawButton(canvas, _acceptButtonBounds, _accept,
_acceptHovered ? ButtonHoverColor : ButtonColor);
}
else if (_cancel != null)
{
_cancelButtonBounds = new SKRect(
dialogBounds.Left + DialogPadding,
buttonY,
dialogBounds.Right - DialogPadding,
buttonY + ButtonHeight);
DrawButton(canvas, _cancelButtonBounds, _cancel,
_cancelHovered ? CancelButtonHoverColor : CancelButtonColor);
}
}
private static readonly SKColor BorderColor = new SKColor((byte)224, (byte)224, (byte)224);
private void DrawButton(SKCanvas canvas, SKRect bounds, string text, SKColor bgColor)
{
// Button background
using var bgPaint = new SKPaint
{
Color = bgColor,
Style = SKPaintStyle.Fill,
IsAntialias = true
};
canvas.DrawRoundRect(bounds, 8, 8, bgPaint);
private const float DialogWidth = 400f;
// Button text
using var font = new SKFont(SKTypeface.Default, 16) { Embolden = true };
using var textPaint = new SKPaint(font)
{
Color = ButtonTextColor,
IsAntialias = true
};
private const float DialogPadding = 24f;
var textBounds = new SKRect();
textPaint.MeasureText(text, ref textBounds);
private const float ButtonHeight = 44f;
var x = bounds.MidX - textBounds.MidX;
var y = bounds.MidY - textBounds.MidY;
canvas.DrawText(text, x, y, textPaint);
}
private const float ButtonSpacing = 12f;
private float CalculateDialogHeight(int messageLineCount)
{
var height = DialogPadding * 2; // Top and bottom padding
private const float CornerRadius = 12f;
if (!string.IsNullOrEmpty(_title))
height += 36; // Title height
public Task<bool> Result => _tcs.Task;
if (!string.IsNullOrEmpty(_message))
height += messageLineCount * 22 + 8; // Message lines + spacing
public SkiaAlertDialog(string title, string message, string? accept, string? cancel)
{
_title = title;
_message = message;
_accept = accept;
_cancel = cancel;
_tcs = new TaskCompletionSource<bool>();
base.IsFocusable = true;
}
height += ButtonHeight; // Buttons
protected override void OnDraw(SKCanvas canvas, SKRect bounds)
{
//IL_0000: Unknown result type (might be due to invalid IL or missing references)
//IL_0005: Unknown result type (might be due to invalid IL or missing references)
//IL_0006: Unknown result type (might be due to invalid IL or missing references)
//IL_0010: Unknown result type (might be due to invalid IL or missing references)
//IL_0018: Expected O, but got Unknown
//IL_0019: Unknown result type (might be due to invalid IL or missing references)
//IL_0071: Unknown result type (might be due to invalid IL or missing references)
//IL_0076: Unknown result type (might be due to invalid IL or missing references)
//IL_0078: Unknown result type (might be due to invalid IL or missing references)
//IL_007d: Unknown result type (might be due to invalid IL or missing references)
//IL_0083: Unknown result type (might be due to invalid IL or missing references)
//IL_008d: Unknown result type (might be due to invalid IL or missing references)
//IL_009e: Unknown result type (might be due to invalid IL or missing references)
//IL_00a7: Expected O, but got Unknown
//IL_00db: Unknown result type (might be due to invalid IL or missing references)
//IL_00e0: Unknown result type (might be due to invalid IL or missing references)
//IL_00e3: Unknown result type (might be due to invalid IL or missing references)
//IL_00f6: Unknown result type (might be due to invalid IL or missing references)
//IL_00fb: Unknown result type (might be due to invalid IL or missing references)
//IL_00fc: Unknown result type (might be due to invalid IL or missing references)
//IL_0106: Unknown result type (might be due to invalid IL or missing references)
//IL_010d: Unknown result type (might be due to invalid IL or missing references)
//IL_0116: Expected O, but got Unknown
//IL_0117: Unknown result type (might be due to invalid IL or missing references)
//IL_015d: Unknown result type (might be due to invalid IL or missing references)
//IL_0162: Unknown result type (might be due to invalid IL or missing references)
//IL_016b: Expected O, but got Unknown
//IL_01f1: Unknown result type (might be due to invalid IL or missing references)
//IL_01f8: Expected O, but got Unknown
//IL_016d: Unknown result type (might be due to invalid IL or missing references)
//IL_0172: Unknown result type (might be due to invalid IL or missing references)
//IL_0173: Unknown result type (might be due to invalid IL or missing references)
//IL_017d: Unknown result type (might be due to invalid IL or missing references)
//IL_0186: Expected O, but got Unknown
//IL_02fd: Unknown result type (might be due to invalid IL or missing references)
//IL_0302: Unknown result type (might be due to invalid IL or missing references)
//IL_030a: Unknown result type (might be due to invalid IL or missing references)
//IL_01fa: Unknown result type (might be due to invalid IL or missing references)
//IL_01ff: Unknown result type (might be due to invalid IL or missing references)
//IL_0200: Unknown result type (might be due to invalid IL or missing references)
//IL_020a: Unknown result type (might be due to invalid IL or missing references)
//IL_0213: Expected O, but got Unknown
//IL_03b9: Unknown result type (might be due to invalid IL or missing references)
//IL_03be: Unknown result type (might be due to invalid IL or missing references)
//IL_03c6: Unknown result type (might be due to invalid IL or missing references)
//IL_0324: Unknown result type (might be due to invalid IL or missing references)
//IL_031d: Unknown result type (might be due to invalid IL or missing references)
//IL_041c: Unknown result type (might be due to invalid IL or missing references)
//IL_0421: Unknown result type (might be due to invalid IL or missing references)
//IL_0429: Unknown result type (might be due to invalid IL or missing references)
//IL_03e0: Unknown result type (might be due to invalid IL or missing references)
//IL_03d9: Unknown result type (might be due to invalid IL or missing references)
//IL_0356: Unknown result type (might be due to invalid IL or missing references)
//IL_035b: Unknown result type (might be due to invalid IL or missing references)
//IL_0363: Unknown result type (might be due to invalid IL or missing references)
//IL_0443: Unknown result type (might be due to invalid IL or missing references)
//IL_043c: Unknown result type (might be due to invalid IL or missing references)
//IL_037d: Unknown result type (might be due to invalid IL or missing references)
//IL_0376: Unknown result type (might be due to invalid IL or missing references)
SKPaint val = new SKPaint
{
Color = OverlayColor,
Style = (SKPaintStyle)0
};
try
{
canvas.DrawRect(bounds, val);
List<string> list = WrapText(_message, 352f, 16f);
float num = CalculateDialogHeight(list.Count);
float num2 = ((SKRect)(ref bounds)).MidX - 200f;
float num3 = ((SKRect)(ref bounds)).MidY - num / 2f;
SKRect val2 = new SKRect(num2, num3, num2 + 400f, num3 + num);
SKPaint val3 = new SKPaint
{
Color = new SKColor((byte)0, (byte)0, (byte)0, (byte)60),
MaskFilter = SKMaskFilter.CreateBlur((SKBlurStyle)0, 8f),
Style = (SKPaintStyle)0
};
try
{
SKRect val4 = new SKRect(((SKRect)(ref val2)).Left + 4f, ((SKRect)(ref val2)).Top + 4f, ((SKRect)(ref val2)).Right + 4f, ((SKRect)(ref val2)).Bottom + 4f);
canvas.DrawRoundRect(val4, 12f, 12f, val3);
SKPaint val5 = new SKPaint
{
Color = DialogBackground,
Style = (SKPaintStyle)0,
IsAntialias = true
};
try
{
canvas.DrawRoundRect(val2, 12f, 12f, val5);
float num4 = ((SKRect)(ref val2)).Top + 24f;
if (!string.IsNullOrEmpty(_title))
{
SKFont val6 = new SKFont(SKTypeface.Default, 20f, 1f, 0f)
{
Embolden = true
};
try
{
SKPaint val7 = new SKPaint(val6)
{
Color = TitleColor,
IsAntialias = true
};
try
{
canvas.DrawText(_title, ((SKRect)(ref val2)).Left + 24f, num4 + 20f, val7);
num4 += 36f;
}
finally
{
((IDisposable)val7)?.Dispose();
}
}
finally
{
((IDisposable)val6)?.Dispose();
}
}
if (!string.IsNullOrEmpty(_message))
{
SKFont val8 = new SKFont(SKTypeface.Default, 16f, 1f, 0f);
try
{
SKPaint val9 = new SKPaint(val8)
{
Color = MessageColor,
IsAntialias = true
};
try
{
foreach (string item in list)
{
canvas.DrawText(item, ((SKRect)(ref val2)).Left + 24f, num4 + 16f, val9);
num4 += 22f;
}
num4 += 8f;
}
finally
{
((IDisposable)val9)?.Dispose();
}
}
finally
{
((IDisposable)val8)?.Dispose();
}
}
num4 = ((SKRect)(ref val2)).Bottom - 24f - 44f;
float num5 = num4;
int num6 = ((_accept != null) ? 1 : 0) + ((_cancel != null) ? 1 : 0);
float num7 = 352f;
if (num6 == 2)
{
float num8 = (num7 - 12f) / 2f;
_cancelButtonBounds = new SKRect(((SKRect)(ref val2)).Left + 24f, num5, ((SKRect)(ref val2)).Left + 24f + num8, num5 + 44f);
DrawButton(canvas, _cancelButtonBounds, _cancel, _cancelHovered ? CancelButtonHoverColor : CancelButtonColor);
_acceptButtonBounds = new SKRect(((SKRect)(ref val2)).Right - 24f - num8, num5, ((SKRect)(ref val2)).Right - 24f, num5 + 44f);
DrawButton(canvas, _acceptButtonBounds, _accept, _acceptHovered ? ButtonHoverColor : ButtonColor);
}
else if (_accept != null)
{
_acceptButtonBounds = new SKRect(((SKRect)(ref val2)).Left + 24f, num5, ((SKRect)(ref val2)).Right - 24f, num5 + 44f);
DrawButton(canvas, _acceptButtonBounds, _accept, _acceptHovered ? ButtonHoverColor : ButtonColor);
}
else if (_cancel != null)
{
_cancelButtonBounds = new SKRect(((SKRect)(ref val2)).Left + 24f, num5, ((SKRect)(ref val2)).Right - 24f, num5 + 44f);
DrawButton(canvas, _cancelButtonBounds, _cancel, _cancelHovered ? CancelButtonHoverColor : CancelButtonColor);
}
}
finally
{
((IDisposable)val5)?.Dispose();
}
}
finally
{
((IDisposable)val3)?.Dispose();
}
}
finally
{
((IDisposable)val)?.Dispose();
}
}
return Math.Max(height, 180); // Minimum height
}
private void DrawButton(SKCanvas canvas, SKRect bounds, string text, SKColor bgColor)
{
//IL_0000: Unknown result type (might be due to invalid IL or missing references)
//IL_0005: Unknown result type (might be due to invalid IL or missing references)
//IL_0006: Unknown result type (might be due to invalid IL or missing references)
//IL_000d: Unknown result type (might be due to invalid IL or missing references)
//IL_0014: Unknown result type (might be due to invalid IL or missing references)
//IL_001c: Expected O, but got Unknown
//IL_001d: Unknown result type (might be due to invalid IL or missing references)
//IL_0042: Unknown result type (might be due to invalid IL or missing references)
//IL_0047: Unknown result type (might be due to invalid IL or missing references)
//IL_004f: Expected O, but got Unknown
//IL_0050: Unknown result type (might be due to invalid IL or missing references)
//IL_0055: Unknown result type (might be due to invalid IL or missing references)
//IL_0056: Unknown result type (might be due to invalid IL or missing references)
//IL_0060: Unknown result type (might be due to invalid IL or missing references)
//IL_0068: Expected O, but got Unknown
//IL_006a: Unknown result type (might be due to invalid IL or missing references)
SKPaint val = new SKPaint
{
Color = bgColor,
Style = (SKPaintStyle)0,
IsAntialias = true
};
try
{
canvas.DrawRoundRect(bounds, 8f, 8f, val);
SKFont val2 = new SKFont(SKTypeface.Default, 16f, 1f, 0f)
{
Embolden = true
};
try
{
SKPaint val3 = new SKPaint(val2)
{
Color = ButtonTextColor,
IsAntialias = true
};
try
{
SKRect val4 = default(SKRect);
val3.MeasureText(text, ref val4);
float num = ((SKRect)(ref bounds)).MidX - ((SKRect)(ref val4)).MidX;
float num2 = ((SKRect)(ref bounds)).MidY - ((SKRect)(ref val4)).MidY;
canvas.DrawText(text, num, num2, val3);
}
finally
{
((IDisposable)val3)?.Dispose();
}
}
finally
{
((IDisposable)val2)?.Dispose();
}
}
finally
{
((IDisposable)val)?.Dispose();
}
}
private List<string> WrapText(string text, float maxWidth, float fontSize)
{
var lines = new List<string>();
if (string.IsNullOrEmpty(text))
return lines;
private float CalculateDialogHeight(int messageLineCount)
{
float num = 48f;
if (!string.IsNullOrEmpty(_title))
{
num += 36f;
}
if (!string.IsNullOrEmpty(_message))
{
num += (float)(messageLineCount * 22 + 8);
}
num += 44f;
return Math.Max(num, 180f);
}
using var font = new SKFont(SKTypeface.Default, fontSize);
using var paint = new SKPaint(font);
private List<string> WrapText(string text, float maxWidth, float fontSize)
{
//IL_0020: Unknown result type (might be due to invalid IL or missing references)
//IL_0026: Expected O, but got Unknown
//IL_0027: Unknown result type (might be due to invalid IL or missing references)
//IL_002d: Expected O, but got Unknown
List<string> list = new List<string>();
if (string.IsNullOrEmpty(text))
{
return list;
}
SKFont val = new SKFont(SKTypeface.Default, fontSize, 1f, 0f);
try
{
SKPaint val2 = new SKPaint(val);
try
{
string[] array = text.Split(' ');
string text2 = "";
string[] array2 = array;
foreach (string text3 in array2)
{
string text4 = (string.IsNullOrEmpty(text2) ? text3 : (text2 + " " + text3));
if (val2.MeasureText(text4) > maxWidth && !string.IsNullOrEmpty(text2))
{
list.Add(text2);
text2 = text3;
}
else
{
text2 = text4;
}
}
if (!string.IsNullOrEmpty(text2))
{
list.Add(text2);
}
return list;
}
finally
{
((IDisposable)val2)?.Dispose();
}
}
finally
{
((IDisposable)val)?.Dispose();
}
}
var words = text.Split(' ');
var currentLine = "";
public override void OnPointerMoved(PointerEventArgs e)
{
bool num = _cancelHovered || _acceptHovered;
_cancelHovered = _cancel != null && ((SKRect)(ref _cancelButtonBounds)).Contains(e.X, e.Y);
_acceptHovered = _accept != null && ((SKRect)(ref _acceptButtonBounds)).Contains(e.X, e.Y);
if (num != (_cancelHovered || _acceptHovered))
{
Invalidate();
}
}
foreach (var word in words)
{
var testLine = string.IsNullOrEmpty(currentLine) ? word : currentLine + " " + word;
var width = paint.MeasureText(testLine);
public override void OnPointerPressed(PointerEventArgs e)
{
if (_cancel != null && ((SKRect)(ref _cancelButtonBounds)).Contains(e.X, e.Y))
{
Dismiss(result: false);
}
else if (_accept != null && ((SKRect)(ref _acceptButtonBounds)).Contains(e.X, e.Y))
{
Dismiss(result: true);
}
}
if (width > maxWidth && !string.IsNullOrEmpty(currentLine))
{
lines.Add(currentLine);
currentLine = word;
}
else
{
currentLine = testLine;
}
}
public override void OnKeyDown(KeyEventArgs e)
{
if (e.Key == Key.Escape && _cancel != null)
{
Dismiss(result: false);
e.Handled = true;
}
else if (e.Key == Key.Enter && _accept != null)
{
Dismiss(result: true);
e.Handled = true;
}
}
if (!string.IsNullOrEmpty(currentLine))
lines.Add(currentLine);
private void Dismiss(bool result)
{
LinuxDialogService.HideDialog(this);
_tcs.TrySetResult(result);
}
return lines;
}
protected override SKSize MeasureOverride(SKSize availableSize)
{
//IL_0000: Unknown result type (might be due to invalid IL or missing references)
return availableSize;
}
public override void OnPointerMoved(PointerEventArgs e)
{
var wasHovered = _cancelHovered || _acceptHovered;
_cancelHovered = _cancel != null && _cancelButtonBounds.Contains(e.X, e.Y);
_acceptHovered = _accept != null && _acceptButtonBounds.Contains(e.X, e.Y);
if (wasHovered != (_cancelHovered || _acceptHovered))
Invalidate();
}
public override void OnPointerPressed(PointerEventArgs e)
{
// Check if clicking on buttons
if (_cancel != null && _cancelButtonBounds.Contains(e.X, e.Y))
{
Dismiss(false);
return;
}
if (_accept != null && _acceptButtonBounds.Contains(e.X, e.Y))
{
Dismiss(true);
return;
}
// Clicking outside dialog doesn't dismiss it (it's modal)
}
public override void OnKeyDown(KeyEventArgs e)
{
// Handle Escape to cancel
if (e.Key == Key.Escape && _cancel != null)
{
Dismiss(false);
e.Handled = true;
return;
}
// Handle Enter to accept
if (e.Key == Key.Enter && _accept != null)
{
Dismiss(true);
e.Handled = true;
return;
}
}
private void Dismiss(bool result)
{
// Remove from dialog system
LinuxDialogService.HideDialog(this);
_tcs.TrySetResult(result);
}
protected override SKSize MeasureOverride(SKSize availableSize)
{
// Dialog takes full screen for the overlay
return availableSize;
}
public override SkiaView? HitTest(float x, float y)
{
// Modal dialogs capture all input
return this;
}
}
/// <summary>
/// Service for showing modal dialogs in OpenMaui Linux.
/// </summary>
public static class LinuxDialogService
{
private static readonly List<SkiaAlertDialog> _activeDialogs = new();
private static Action? _invalidateCallback;
/// <summary>
/// Registers the invalidation callback (called by LinuxApplication).
/// </summary>
public static void SetInvalidateCallback(Action callback)
{
_invalidateCallback = callback;
}
/// <summary>
/// Shows an alert dialog and returns when dismissed.
/// </summary>
public static Task<bool> ShowAlertAsync(string title, string message, string? accept, string? cancel)
{
var dialog = new SkiaAlertDialog(title, message, accept, cancel);
_activeDialogs.Add(dialog);
_invalidateCallback?.Invoke();
return dialog.Result;
}
/// <summary>
/// Hides a dialog.
/// </summary>
internal static void HideDialog(SkiaAlertDialog dialog)
{
_activeDialogs.Remove(dialog);
_invalidateCallback?.Invoke();
}
/// <summary>
/// Gets whether there are active dialogs.
/// </summary>
public static bool HasActiveDialog => _activeDialogs.Count > 0;
/// <summary>
/// Gets the topmost dialog.
/// </summary>
public static SkiaAlertDialog? TopDialog => _activeDialogs.Count > 0 ? _activeDialogs[^1] : null;
/// <summary>
/// Draws all active dialogs.
/// </summary>
public static void DrawDialogs(SKCanvas canvas, SKRect bounds)
{
foreach (var dialog in _activeDialogs)
{
dialog.Measure(new SKSize(bounds.Width, bounds.Height));
dialog.Arrange(bounds);
dialog.Draw(canvas);
}
}
public override SkiaView? HitTest(float x, float y)
{
return this;
}
}

View File

@@ -1,310 +1,483 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System;
using Microsoft.Maui.Controls;
using Microsoft.Maui.Platform.Linux.Handlers;
using SkiaSharp;
namespace Microsoft.Maui.Platform;
/// <summary>
/// Skia-rendered border/frame container control with full XAML styling support.
/// </summary>
public class SkiaBorder : SkiaLayoutView
{
#region BindableProperties
public static readonly BindableProperty StrokeThicknessProperty = BindableProperty.Create("StrokeThickness", typeof(float), typeof(SkiaBorder), (object)1f, (BindingMode)2, (ValidateValueDelegate)null, (BindingPropertyChangedDelegate)delegate(BindableObject b, object o, object n)
{
((SkiaBorder)(object)b).Invalidate();
}, (BindingPropertyChangingDelegate)null, (CoerceValueDelegate)null, (CreateDefaultValueDelegate)null);
public static readonly BindableProperty StrokeThicknessProperty =
BindableProperty.Create(nameof(StrokeThickness), typeof(float), typeof(SkiaBorder), 1f,
propertyChanged: (b, o, n) => ((SkiaBorder)b).Invalidate());
public static readonly BindableProperty CornerRadiusProperty = BindableProperty.Create("CornerRadius", typeof(float), typeof(SkiaBorder), (object)0f, (BindingMode)2, (ValidateValueDelegate)null, (BindingPropertyChangedDelegate)delegate(BindableObject b, object o, object n)
{
((SkiaBorder)(object)b).Invalidate();
}, (BindingPropertyChangingDelegate)null, (CoerceValueDelegate)null, (CreateDefaultValueDelegate)null);
public static readonly BindableProperty CornerRadiusProperty =
BindableProperty.Create(nameof(CornerRadius), typeof(float), typeof(SkiaBorder), 0f,
propertyChanged: (b, o, n) => ((SkiaBorder)b).Invalidate());
public static readonly BindableProperty StrokeProperty = BindableProperty.Create("Stroke", typeof(SKColor), typeof(SkiaBorder), (object)SKColors.Black, (BindingMode)2, (ValidateValueDelegate)null, (BindingPropertyChangedDelegate)delegate(BindableObject b, object o, object n)
{
((SkiaBorder)(object)b).Invalidate();
}, (BindingPropertyChangingDelegate)null, (CoerceValueDelegate)null, (CreateDefaultValueDelegate)null);
public static readonly BindableProperty StrokeProperty =
BindableProperty.Create(nameof(Stroke), typeof(SKColor), typeof(SkiaBorder), SKColors.Black,
propertyChanged: (b, o, n) => ((SkiaBorder)b).Invalidate());
public static readonly BindableProperty PaddingLeftProperty = BindableProperty.Create("PaddingLeft", typeof(float), typeof(SkiaBorder), (object)0f, (BindingMode)2, (ValidateValueDelegate)null, (BindingPropertyChangedDelegate)delegate(BindableObject b, object o, object n)
{
((SkiaBorder)(object)b).InvalidateMeasure();
}, (BindingPropertyChangingDelegate)null, (CoerceValueDelegate)null, (CreateDefaultValueDelegate)null);
public static readonly BindableProperty PaddingLeftProperty =
BindableProperty.Create(nameof(PaddingLeft), typeof(float), typeof(SkiaBorder), 0f,
propertyChanged: (b, o, n) => ((SkiaBorder)b).InvalidateMeasure());
public static readonly BindableProperty PaddingTopProperty = BindableProperty.Create("PaddingTop", typeof(float), typeof(SkiaBorder), (object)0f, (BindingMode)2, (ValidateValueDelegate)null, (BindingPropertyChangedDelegate)delegate(BindableObject b, object o, object n)
{
((SkiaBorder)(object)b).InvalidateMeasure();
}, (BindingPropertyChangingDelegate)null, (CoerceValueDelegate)null, (CreateDefaultValueDelegate)null);
public static readonly BindableProperty PaddingTopProperty =
BindableProperty.Create(nameof(PaddingTop), typeof(float), typeof(SkiaBorder), 0f,
propertyChanged: (b, o, n) => ((SkiaBorder)b).InvalidateMeasure());
public static readonly BindableProperty PaddingRightProperty = BindableProperty.Create("PaddingRight", typeof(float), typeof(SkiaBorder), (object)0f, (BindingMode)2, (ValidateValueDelegate)null, (BindingPropertyChangedDelegate)delegate(BindableObject b, object o, object n)
{
((SkiaBorder)(object)b).InvalidateMeasure();
}, (BindingPropertyChangingDelegate)null, (CoerceValueDelegate)null, (CreateDefaultValueDelegate)null);
public static readonly BindableProperty PaddingRightProperty =
BindableProperty.Create(nameof(PaddingRight), typeof(float), typeof(SkiaBorder), 0f,
propertyChanged: (b, o, n) => ((SkiaBorder)b).InvalidateMeasure());
public static readonly BindableProperty PaddingBottomProperty = BindableProperty.Create("PaddingBottom", typeof(float), typeof(SkiaBorder), (object)0f, (BindingMode)2, (ValidateValueDelegate)null, (BindingPropertyChangedDelegate)delegate(BindableObject b, object o, object n)
{
((SkiaBorder)(object)b).InvalidateMeasure();
}, (BindingPropertyChangingDelegate)null, (CoerceValueDelegate)null, (CreateDefaultValueDelegate)null);
public static readonly BindableProperty PaddingBottomProperty =
BindableProperty.Create(nameof(PaddingBottom), typeof(float), typeof(SkiaBorder), 0f,
propertyChanged: (b, o, n) => ((SkiaBorder)b).InvalidateMeasure());
public static readonly BindableProperty HasShadowProperty = BindableProperty.Create("HasShadow", typeof(bool), typeof(SkiaBorder), (object)false, (BindingMode)2, (ValidateValueDelegate)null, (BindingPropertyChangedDelegate)delegate(BindableObject b, object o, object n)
{
((SkiaBorder)(object)b).Invalidate();
}, (BindingPropertyChangingDelegate)null, (CoerceValueDelegate)null, (CreateDefaultValueDelegate)null);
public static readonly BindableProperty HasShadowProperty =
BindableProperty.Create(nameof(HasShadow), typeof(bool), typeof(SkiaBorder), false,
propertyChanged: (b, o, n) => ((SkiaBorder)b).Invalidate());
public static readonly BindableProperty ShadowColorProperty = BindableProperty.Create("ShadowColor", typeof(SKColor), typeof(SkiaBorder), (object)new SKColor((byte)0, (byte)0, (byte)0, (byte)40), (BindingMode)2, (ValidateValueDelegate)null, (BindingPropertyChangedDelegate)delegate(BindableObject b, object o, object n)
{
((SkiaBorder)(object)b).Invalidate();
}, (BindingPropertyChangingDelegate)null, (CoerceValueDelegate)null, (CreateDefaultValueDelegate)null);
public static readonly BindableProperty ShadowColorProperty =
BindableProperty.Create(nameof(ShadowColor), typeof(SKColor), typeof(SkiaBorder), new SKColor(0, 0, 0, 40),
propertyChanged: (b, o, n) => ((SkiaBorder)b).Invalidate());
public static readonly BindableProperty ShadowBlurRadiusProperty = BindableProperty.Create("ShadowBlurRadius", typeof(float), typeof(SkiaBorder), (object)4f, (BindingMode)2, (ValidateValueDelegate)null, (BindingPropertyChangedDelegate)delegate(BindableObject b, object o, object n)
{
((SkiaBorder)(object)b).Invalidate();
}, (BindingPropertyChangingDelegate)null, (CoerceValueDelegate)null, (CreateDefaultValueDelegate)null);
public static readonly BindableProperty ShadowBlurRadiusProperty =
BindableProperty.Create(nameof(ShadowBlurRadius), typeof(float), typeof(SkiaBorder), 4f,
propertyChanged: (b, o, n) => ((SkiaBorder)b).Invalidate());
public static readonly BindableProperty ShadowOffsetXProperty = BindableProperty.Create("ShadowOffsetX", typeof(float), typeof(SkiaBorder), (object)2f, (BindingMode)2, (ValidateValueDelegate)null, (BindingPropertyChangedDelegate)delegate(BindableObject b, object o, object n)
{
((SkiaBorder)(object)b).Invalidate();
}, (BindingPropertyChangingDelegate)null, (CoerceValueDelegate)null, (CreateDefaultValueDelegate)null);
public static readonly BindableProperty ShadowOffsetXProperty =
BindableProperty.Create(nameof(ShadowOffsetX), typeof(float), typeof(SkiaBorder), 2f,
propertyChanged: (b, o, n) => ((SkiaBorder)b).Invalidate());
public static readonly BindableProperty ShadowOffsetYProperty = BindableProperty.Create("ShadowOffsetY", typeof(float), typeof(SkiaBorder), (object)2f, (BindingMode)2, (ValidateValueDelegate)null, (BindingPropertyChangedDelegate)delegate(BindableObject b, object o, object n)
{
((SkiaBorder)(object)b).Invalidate();
}, (BindingPropertyChangingDelegate)null, (CoerceValueDelegate)null, (CreateDefaultValueDelegate)null);
public static readonly BindableProperty ShadowOffsetYProperty =
BindableProperty.Create(nameof(ShadowOffsetY), typeof(float), typeof(SkiaBorder), 2f,
propertyChanged: (b, o, n) => ((SkiaBorder)b).Invalidate());
private bool _isPressed;
#endregion
public float StrokeThickness
{
get
{
return (float)((BindableObject)this).GetValue(StrokeThicknessProperty);
}
set
{
((BindableObject)this).SetValue(StrokeThicknessProperty, (object)value);
}
}
#region Properties
public float CornerRadius
{
get
{
return (float)((BindableObject)this).GetValue(CornerRadiusProperty);
}
set
{
((BindableObject)this).SetValue(CornerRadiusProperty, (object)value);
}
}
public float StrokeThickness
{
get => (float)GetValue(StrokeThicknessProperty);
set => SetValue(StrokeThicknessProperty, value);
}
public SKColor Stroke
{
get
{
//IL_000b: Unknown result type (might be due to invalid IL or missing references)
return (SKColor)((BindableObject)this).GetValue(StrokeProperty);
}
set
{
//IL_0006: Unknown result type (might be due to invalid IL or missing references)
((BindableObject)this).SetValue(StrokeProperty, (object)value);
}
}
public float CornerRadius
{
get => (float)GetValue(CornerRadiusProperty);
set => SetValue(CornerRadiusProperty, value);
}
public float PaddingLeft
{
get
{
return (float)((BindableObject)this).GetValue(PaddingLeftProperty);
}
set
{
((BindableObject)this).SetValue(PaddingLeftProperty, (object)value);
}
}
public SKColor Stroke
{
get => (SKColor)GetValue(StrokeProperty);
set => SetValue(StrokeProperty, value);
}
public float PaddingTop
{
get
{
return (float)((BindableObject)this).GetValue(PaddingTopProperty);
}
set
{
((BindableObject)this).SetValue(PaddingTopProperty, (object)value);
}
}
public float PaddingLeft
{
get => (float)GetValue(PaddingLeftProperty);
set => SetValue(PaddingLeftProperty, value);
}
public float PaddingRight
{
get
{
return (float)((BindableObject)this).GetValue(PaddingRightProperty);
}
set
{
((BindableObject)this).SetValue(PaddingRightProperty, (object)value);
}
}
public float PaddingTop
{
get => (float)GetValue(PaddingTopProperty);
set => SetValue(PaddingTopProperty, value);
}
public float PaddingBottom
{
get
{
return (float)((BindableObject)this).GetValue(PaddingBottomProperty);
}
set
{
((BindableObject)this).SetValue(PaddingBottomProperty, (object)value);
}
}
public float PaddingRight
{
get => (float)GetValue(PaddingRightProperty);
set => SetValue(PaddingRightProperty, value);
}
public bool HasShadow
{
get
{
return (bool)((BindableObject)this).GetValue(HasShadowProperty);
}
set
{
((BindableObject)this).SetValue(HasShadowProperty, (object)value);
}
}
public float PaddingBottom
{
get => (float)GetValue(PaddingBottomProperty);
set => SetValue(PaddingBottomProperty, value);
}
public SKColor ShadowColor
{
get
{
//IL_000b: Unknown result type (might be due to invalid IL or missing references)
return (SKColor)((BindableObject)this).GetValue(ShadowColorProperty);
}
set
{
//IL_0006: Unknown result type (might be due to invalid IL or missing references)
((BindableObject)this).SetValue(ShadowColorProperty, (object)value);
}
}
public bool HasShadow
{
get => (bool)GetValue(HasShadowProperty);
set => SetValue(HasShadowProperty, value);
}
public float ShadowBlurRadius
{
get
{
return (float)((BindableObject)this).GetValue(ShadowBlurRadiusProperty);
}
set
{
((BindableObject)this).SetValue(ShadowBlurRadiusProperty, (object)value);
}
}
public SKColor ShadowColor
{
get => (SKColor)GetValue(ShadowColorProperty);
set => SetValue(ShadowColorProperty, value);
}
public float ShadowOffsetX
{
get
{
return (float)((BindableObject)this).GetValue(ShadowOffsetXProperty);
}
set
{
((BindableObject)this).SetValue(ShadowOffsetXProperty, (object)value);
}
}
public float ShadowBlurRadius
{
get => (float)GetValue(ShadowBlurRadiusProperty);
set => SetValue(ShadowBlurRadiusProperty, value);
}
public float ShadowOffsetY
{
get
{
return (float)((BindableObject)this).GetValue(ShadowOffsetYProperty);
}
set
{
((BindableObject)this).SetValue(ShadowOffsetYProperty, (object)value);
}
}
public float ShadowOffsetX
{
get => (float)GetValue(ShadowOffsetXProperty);
set => SetValue(ShadowOffsetXProperty, value);
}
public event EventHandler? Tapped;
public float ShadowOffsetY
{
get => (float)GetValue(ShadowOffsetYProperty);
set => SetValue(ShadowOffsetYProperty, value);
}
public void SetPadding(float all)
{
float num = (PaddingBottom = all);
float num3 = (PaddingRight = num);
float paddingLeft = (PaddingTop = num3);
PaddingLeft = paddingLeft;
}
#endregion
public void SetPadding(float horizontal, float vertical)
{
float paddingLeft = (PaddingRight = horizontal);
PaddingLeft = paddingLeft;
paddingLeft = (PaddingBottom = vertical);
PaddingTop = paddingLeft;
}
/// <summary>
/// Sets uniform padding on all sides.
/// </summary>
public void SetPadding(float all)
{
PaddingLeft = PaddingTop = PaddingRight = PaddingBottom = all;
}
public void SetPadding(float left, float top, float right, float bottom)
{
PaddingLeft = left;
PaddingTop = top;
PaddingRight = right;
PaddingBottom = bottom;
}
/// <summary>
/// Sets padding with horizontal and vertical values.
/// </summary>
public void SetPadding(float horizontal, float vertical)
{
PaddingLeft = PaddingRight = horizontal;
PaddingTop = PaddingBottom = vertical;
}
protected override void OnDraw(SKCanvas canvas, SKRect bounds)
{
//IL_00e5: Unknown result type (might be due to invalid IL or missing references)
//IL_00ea: Unknown result type (might be due to invalid IL or missing references)
//IL_00ec: Unknown result type (might be due to invalid IL or missing references)
//IL_00f6: Unknown result type (might be due to invalid IL or missing references)
//IL_00fd: Unknown result type (might be due to invalid IL or missing references)
//IL_0105: Expected O, but got Unknown
//IL_005c: Unknown result type (might be due to invalid IL or missing references)
//IL_0061: Unknown result type (might be due to invalid IL or missing references)
//IL_0063: Unknown result type (might be due to invalid IL or missing references)
//IL_006d: Unknown result type (might be due to invalid IL or missing references)
//IL_007f: Unknown result type (might be due to invalid IL or missing references)
//IL_0088: Expected O, but got Unknown
//IL_0106: Unknown result type (might be due to invalid IL or missing references)
//IL_0108: Unknown result type (might be due to invalid IL or missing references)
//IL_0113: Expected O, but got Unknown
//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
//IL_00c5: Unknown result type (might be due to invalid IL or missing references)
//IL_00c8: Unknown result type (might be due to invalid IL or missing references)
//IL_00cb: Unknown result type (might be due to invalid IL or missing references)
//IL_00d7: Expected O, but got Unknown
//IL_011b: Unknown result type (might be due to invalid IL or missing references)
//IL_0120: Unknown result type (might be due to invalid IL or missing references)
//IL_0122: Unknown result type (might be due to invalid IL or missing references)
//IL_012c: Unknown result type (might be due to invalid IL or missing references)
//IL_0133: Unknown result type (might be due to invalid IL or missing references)
//IL_013a: Unknown result type (might be due to invalid IL or missing references)
//IL_0143: Expected O, but got Unknown
//IL_0144: Unknown result type (might be due to invalid IL or missing references)
//IL_0146: Unknown result type (might be due to invalid IL or missing references)
//IL_0152: Expected O, but got Unknown
float strokeThickness = StrokeThickness;
float cornerRadius = CornerRadius;
SKRect val = default(SKRect);
((SKRect)(ref val))._002Ector(((SKRect)(ref bounds)).Left + strokeThickness / 2f, ((SKRect)(ref bounds)).Top + strokeThickness / 2f, ((SKRect)(ref bounds)).Right - strokeThickness / 2f, ((SKRect)(ref bounds)).Bottom - strokeThickness / 2f);
if (HasShadow)
{
SKPaint val2 = new SKPaint
{
Color = ShadowColor,
MaskFilter = SKMaskFilter.CreateBlur((SKBlurStyle)0, ShadowBlurRadius),
Style = (SKPaintStyle)0
};
try
{
SKRect val3 = new SKRect(((SKRect)(ref val)).Left + ShadowOffsetX, ((SKRect)(ref val)).Top + ShadowOffsetY, ((SKRect)(ref val)).Right + ShadowOffsetX, ((SKRect)(ref val)).Bottom + ShadowOffsetY);
canvas.DrawRoundRect(new SKRoundRect(val3, cornerRadius), val2);
}
finally
{
((IDisposable)val2)?.Dispose();
}
}
SKPaint val4 = new SKPaint
{
Color = base.BackgroundColor,
Style = (SKPaintStyle)0,
IsAntialias = true
};
try
{
canvas.DrawRoundRect(new SKRoundRect(val, cornerRadius), val4);
if (strokeThickness > 0f)
{
SKPaint val5 = new SKPaint
{
Color = Stroke,
Style = (SKPaintStyle)1,
StrokeWidth = strokeThickness,
IsAntialias = true
};
try
{
canvas.DrawRoundRect(new SKRoundRect(val, cornerRadius), val5);
}
finally
{
((IDisposable)val5)?.Dispose();
}
}
foreach (SkiaView child in base.Children)
{
if (child.IsVisible)
{
child.Draw(canvas);
}
}
}
finally
{
((IDisposable)val4)?.Dispose();
}
}
/// <summary>
/// Sets padding with individual values for each side.
/// </summary>
public void SetPadding(float left, float top, float right, float bottom)
{
PaddingLeft = left;
PaddingTop = top;
PaddingRight = right;
PaddingBottom = bottom;
}
protected override SKRect GetContentBounds()
{
//IL_0002: Unknown result type (might be due to invalid IL or missing references)
//IL_0007: Unknown result type (might be due to invalid IL or missing references)
return GetContentBounds(base.Bounds);
}
protected override void OnDraw(SKCanvas canvas, SKRect bounds)
{
var strokeThickness = StrokeThickness;
var cornerRadius = CornerRadius;
protected new SKRect GetContentBounds(SKRect bounds)
{
//IL_0047: Unknown result type (might be due to invalid IL or missing references)
float strokeThickness = StrokeThickness;
return new SKRect(((SKRect)(ref bounds)).Left + PaddingLeft + strokeThickness, ((SKRect)(ref bounds)).Top + PaddingTop + strokeThickness, ((SKRect)(ref bounds)).Right - PaddingRight - strokeThickness, ((SKRect)(ref bounds)).Bottom - PaddingBottom - strokeThickness);
}
var borderRect = new SKRect(
bounds.Left + strokeThickness / 2,
bounds.Top + strokeThickness / 2,
bounds.Right - strokeThickness / 2,
bounds.Bottom - strokeThickness / 2);
protected override SKSize MeasureOverride(SKSize availableSize)
{
//IL_009a: Unknown result type (might be due to invalid IL or missing references)
//IL_009f: Unknown result type (might be due to invalid IL or missing references)
//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
//IL_00be: Unknown result type (might be due to invalid IL or missing references)
//IL_00e6: Unknown result type (might be due to invalid IL or missing references)
//IL_00eb: Unknown result type (might be due to invalid IL or missing references)
//IL_014e: Unknown result type (might be due to invalid IL or missing references)
float strokeThickness = StrokeThickness;
float num = PaddingLeft + PaddingRight + strokeThickness * 2f;
float num2 = PaddingTop + PaddingBottom + strokeThickness * 2f;
float num3 = ((base.WidthRequest >= 0.0) ? ((float)base.WidthRequest) : ((SKSize)(ref availableSize)).Width);
float num4 = ((base.HeightRequest >= 0.0) ? ((float)base.HeightRequest) : ((SKSize)(ref availableSize)).Height);
SKSize availableSize2 = default(SKSize);
((SKSize)(ref availableSize2))._002Ector(Math.Max(0f, num3 - num), Math.Max(0f, num4 - num2));
SKSize val = SKSize.Empty;
foreach (SkiaView child in base.Children)
{
SKSize val2 = child.Measure(availableSize2);
val = new SKSize(Math.Max(((SKSize)(ref val)).Width, ((SKSize)(ref val2)).Width), Math.Max(((SKSize)(ref val)).Height, ((SKSize)(ref val2)).Height));
}
float num5 = ((base.WidthRequest >= 0.0) ? ((float)base.WidthRequest) : (((SKSize)(ref val)).Width + num));
float num6 = ((base.HeightRequest >= 0.0) ? ((float)base.HeightRequest) : (((SKSize)(ref val)).Height + num2));
return new SKSize(num5, num6);
}
// Draw shadow if enabled
if (HasShadow)
{
using var shadowPaint = new SKPaint
{
Color = ShadowColor,
MaskFilter = SKMaskFilter.CreateBlur(SKBlurStyle.Normal, ShadowBlurRadius),
Style = SKPaintStyle.Fill
};
var shadowRect = new SKRect(
borderRect.Left + ShadowOffsetX,
borderRect.Top + ShadowOffsetY,
borderRect.Right + ShadowOffsetX,
borderRect.Bottom + ShadowOffsetY);
canvas.DrawRoundRect(new SKRoundRect(shadowRect, cornerRadius), shadowPaint);
}
protected override SKRect ArrangeOverride(SKRect bounds)
{
//IL_0001: Unknown result type (might be due to invalid IL or missing references)
//IL_0002: Unknown result type (might be due to invalid IL or missing references)
//IL_0007: Unknown result type (might be due to invalid IL or missing references)
//IL_001d: Unknown result type (might be due to invalid IL or missing references)
//IL_0022: Unknown result type (might be due to invalid IL or missing references)
//IL_006a: Unknown result type (might be due to invalid IL or missing references)
//IL_0084: Unknown result type (might be due to invalid IL or missing references)
SKRect contentBounds = GetContentBounds(bounds);
SKRect bounds2 = default(SKRect);
foreach (SkiaView child in base.Children)
{
Thickness margin = child.Margin;
((SKRect)(ref bounds2))._002Ector(((SKRect)(ref contentBounds)).Left + (float)((Thickness)(ref margin)).Left, ((SKRect)(ref contentBounds)).Top + (float)((Thickness)(ref margin)).Top, ((SKRect)(ref contentBounds)).Right - (float)((Thickness)(ref margin)).Right, ((SKRect)(ref contentBounds)).Bottom - (float)((Thickness)(ref margin)).Bottom);
child.Arrange(bounds2);
}
return bounds;
}
// Draw background
using var bgPaint = new SKPaint
{
Color = BackgroundColor,
Style = SKPaintStyle.Fill,
IsAntialias = true
};
canvas.DrawRoundRect(new SKRoundRect(borderRect, cornerRadius), bgPaint);
private bool HasTapGestureRecognizers()
{
View? mauiView = base.MauiView;
if (((mauiView != null) ? mauiView.GestureRecognizers : null) == null)
{
return false;
}
foreach (IGestureRecognizer gestureRecognizer in base.MauiView.GestureRecognizers)
{
if (gestureRecognizer is TapGestureRecognizer)
{
return true;
}
}
return false;
}
// Draw border
if (strokeThickness > 0)
{
using var borderPaint = new SKPaint
{
Color = Stroke,
Style = SKPaintStyle.Stroke,
StrokeWidth = strokeThickness,
IsAntialias = true
};
canvas.DrawRoundRect(new SKRoundRect(borderRect, cornerRadius), borderPaint);
}
public override SkiaView? HitTest(float x, float y)
{
//IL_0011: Unknown result type (might be due to invalid IL or missing references)
//IL_0016: Unknown result type (might be due to invalid IL or missing references)
//IL_001b: Unknown result type (might be due to invalid IL or missing references)
if (base.IsVisible && base.IsEnabled)
{
SKRect bounds = base.Bounds;
if (((SKRect)(ref bounds)).Contains(new SKPoint(x, y)))
{
if (HasTapGestureRecognizers())
{
Console.WriteLine("[SkiaBorder.HitTest] Intercepting for gesture - returning self");
return this;
}
return base.HitTest(x, y);
}
}
return null;
}
// Draw children
foreach (var child in Children)
{
if (child.IsVisible)
{
child.Draw(canvas);
}
}
}
public override void OnPointerPressed(PointerEventArgs e)
{
if (HasTapGestureRecognizers())
{
_isPressed = true;
e.Handled = true;
Console.WriteLine("[SkiaBorder] OnPointerPressed INTERCEPTED for gesture, MauiView=" + ((object)base.MauiView)?.GetType().Name);
if (base.MauiView != null)
{
GestureManager.ProcessPointerDown(base.MauiView, e.X, e.Y);
}
}
else
{
base.OnPointerPressed(e);
}
}
protected override SKRect GetContentBounds()
{
return GetContentBounds(Bounds);
}
public override void OnPointerReleased(PointerEventArgs e)
{
if (_isPressed)
{
_isPressed = false;
e.Handled = true;
Console.WriteLine("[SkiaBorder] OnPointerReleased - processing gesture recognizers, MauiView=" + ((object)base.MauiView)?.GetType().Name);
if (base.MauiView != null)
{
GestureManager.ProcessPointerUp(base.MauiView, e.X, e.Y);
}
this.Tapped?.Invoke(this, EventArgs.Empty);
}
else
{
base.OnPointerReleased(e);
}
}
protected new SKRect GetContentBounds(SKRect bounds)
{
var strokeThickness = StrokeThickness;
return new SKRect(
bounds.Left + PaddingLeft + strokeThickness,
bounds.Top + PaddingTop + strokeThickness,
bounds.Right - PaddingRight - strokeThickness,
bounds.Bottom - PaddingBottom - strokeThickness);
}
protected override SKSize MeasureOverride(SKSize availableSize)
{
var strokeThickness = StrokeThickness;
var paddingWidth = PaddingLeft + PaddingRight + strokeThickness * 2;
var paddingHeight = PaddingTop + PaddingBottom + strokeThickness * 2;
// Respect explicit size requests
var requestedWidth = WidthRequest >= 0 ? (float)WidthRequest : availableSize.Width;
var requestedHeight = HeightRequest >= 0 ? (float)HeightRequest : availableSize.Height;
var childAvailable = new SKSize(
Math.Max(0, requestedWidth - paddingWidth),
Math.Max(0, requestedHeight - paddingHeight));
var maxChildSize = SKSize.Empty;
foreach (var child in Children)
{
var childSize = child.Measure(childAvailable);
maxChildSize = new SKSize(
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 ? (float)WidthRequest : maxChildSize.Width + paddingWidth;
var height = HeightRequest >= 0 ? (float)HeightRequest : maxChildSize.Height + paddingHeight;
return new SKSize(width, height);
}
protected override SKRect ArrangeOverride(SKRect bounds)
{
var contentBounds = GetContentBounds(bounds);
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);
child.Arrange(marginedBounds);
}
return bounds;
}
}
/// <summary>
/// Frame control - a Border with shadow enabled by default.
/// Mimics the MAUI Frame control appearance.
/// </summary>
public class SkiaFrame : SkiaBorder
{
public SkiaFrame()
{
HasShadow = true;
CornerRadius = 4;
SetPadding(10);
BackgroundColor = SKColors.White;
Stroke = SKColors.Transparent;
StrokeThickness = 0;
}
public override void OnPointerExited(PointerEventArgs e)
{
base.OnPointerExited(e);
_isPressed = false;
}
}

View File

@@ -1,66 +1,93 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System;
using Microsoft.Maui.Controls;
using SkiaSharp;
namespace Microsoft.Maui.Platform;
/// <summary>
/// Skia-rendered BoxView - a simple colored rectangle.
/// </summary>
public class SkiaBoxView : SkiaView
{
public static readonly BindableProperty ColorProperty =
BindableProperty.Create(nameof(Color), typeof(SKColor), typeof(SkiaBoxView), SKColors.Transparent,
propertyChanged: (b, o, n) => ((SkiaBoxView)b).Invalidate());
public static readonly BindableProperty ColorProperty = BindableProperty.Create("Color", typeof(SKColor), typeof(SkiaBoxView), (object)SKColors.Transparent, (BindingMode)2, (ValidateValueDelegate)null, (BindingPropertyChangedDelegate)delegate(BindableObject b, object o, object n)
{
((SkiaBoxView)(object)b).Invalidate();
}, (BindingPropertyChangingDelegate)null, (CoerceValueDelegate)null, (CreateDefaultValueDelegate)null);
public static readonly BindableProperty CornerRadiusProperty =
BindableProperty.Create(nameof(CornerRadius), typeof(float), typeof(SkiaBoxView), 0f,
propertyChanged: (b, o, n) => ((SkiaBoxView)b).Invalidate());
public static readonly BindableProperty CornerRadiusProperty = BindableProperty.Create("CornerRadius", typeof(float), typeof(SkiaBoxView), (object)0f, (BindingMode)2, (ValidateValueDelegate)null, (BindingPropertyChangedDelegate)delegate(BindableObject b, object o, object n)
{
((SkiaBoxView)(object)b).Invalidate();
}, (BindingPropertyChangingDelegate)null, (CoerceValueDelegate)null, (CreateDefaultValueDelegate)null);
public SKColor Color
{
get => (SKColor)GetValue(ColorProperty);
set => SetValue(ColorProperty, value);
}
public SKColor Color
{
get
{
//IL_000b: Unknown result type (might be due to invalid IL or missing references)
return (SKColor)((BindableObject)this).GetValue(ColorProperty);
}
set
{
//IL_0006: Unknown result type (might be due to invalid IL or missing references)
((BindableObject)this).SetValue(ColorProperty, (object)value);
}
}
public float CornerRadius
{
get => (float)GetValue(CornerRadiusProperty);
set => SetValue(CornerRadiusProperty, value);
}
public float CornerRadius
{
get
{
return (float)((BindableObject)this).GetValue(CornerRadiusProperty);
}
set
{
((BindableObject)this).SetValue(CornerRadiusProperty, (object)value);
}
}
protected override void OnDraw(SKCanvas canvas, SKRect bounds)
{
using var paint = new SKPaint
{
Color = Color,
Style = SKPaintStyle.Fill,
IsAntialias = true
};
protected override void OnDraw(SKCanvas canvas, SKRect bounds)
{
//IL_0000: Unknown result type (might be due to invalid IL or missing references)
//IL_0005: Unknown result type (might be due to invalid IL or missing references)
//IL_0007: Unknown result type (might be due to invalid IL or missing references)
//IL_0011: Unknown result type (might be due to invalid IL or missing references)
//IL_0018: Unknown result type (might be due to invalid IL or missing references)
//IL_0020: Expected O, but got Unknown
//IL_0044: Unknown result type (might be due to invalid IL or missing references)
//IL_002e: Unknown result type (might be due to invalid IL or missing references)
SKPaint val = new SKPaint
{
Color = Color,
Style = (SKPaintStyle)0,
IsAntialias = true
};
try
{
if (CornerRadius > 0f)
{
canvas.DrawRoundRect(bounds, CornerRadius, CornerRadius, val);
}
else
{
canvas.DrawRect(bounds, val);
}
}
finally
{
((IDisposable)val)?.Dispose();
}
}
if (CornerRadius > 0)
{
canvas.DrawRoundRect(bounds, CornerRadius, CornerRadius, paint);
}
else
{
canvas.DrawRect(bounds, paint);
}
}
protected override SKSize MeasureOverride(SKSize 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);
// Ensure no NaN values
if (float.IsNaN(width)) width = 40f;
if (float.IsNaN(height)) height = 40f;
return new SKSize(width, height);
}
protected override SKSize MeasureOverride(SKSize availableSize)
{
//IL_008c: Unknown result type (might be due to invalid IL or missing references)
float num = ((base.WidthRequest >= 0.0) ? ((float)base.WidthRequest) : (float.IsInfinity(((SKSize)(ref availableSize)).Width) ? 40f : ((SKSize)(ref availableSize)).Width));
float num2 = ((base.HeightRequest >= 0.0) ? ((float)base.HeightRequest) : (float.IsInfinity(((SKSize)(ref availableSize)).Height) ? 40f : ((SKSize)(ref availableSize)).Height));
if (float.IsNaN(num))
{
num = 40f;
}
if (float.IsNaN(num2))
{
num2 = 40f;
}
return new SKSize(num, num2);
}
}

View File

File diff suppressed because it is too large Load Diff

View File

@@ -1,403 +1,381 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System;
using System.Collections.Generic;
using SkiaSharp;
namespace Microsoft.Maui.Platform;
/// <summary>
/// A horizontally scrolling carousel view with snap-to-item behavior.
/// </summary>
public class SkiaCarouselView : SkiaLayoutView
{
private readonly List<SkiaView> _items = new();
private int _currentPosition = 0;
private float _scrollOffset = 0f;
private float _targetScrollOffset = 0f;
private bool _isDragging = false;
private float _dragStartX;
private float _dragStartOffset;
private float _velocity = 0f;
private DateTime _lastDragTime;
private float _lastDragX;
private readonly List<SkiaView> _items = new List<SkiaView>();
// Animation
private bool _isAnimating = false;
private float _animationStartOffset;
private float _animationTargetOffset;
private DateTime _animationStartTime;
private const float AnimationDurationMs = 300f;
private int _currentPosition;
/// <summary>
/// Gets or sets the current position (item index).
/// </summary>
public int Position
{
get => _currentPosition;
set
{
if (value >= 0 && value < _items.Count && value != _currentPosition)
{
int oldPosition = _currentPosition;
_currentPosition = value;
AnimateToPosition(value);
PositionChanged?.Invoke(this, new PositionChangedEventArgs(oldPosition, value));
}
}
}
private float _scrollOffset;
/// <summary>
/// Gets the item count.
/// </summary>
public int ItemCount => _items.Count;
private float _targetScrollOffset;
/// <summary>
/// Gets or sets whether looping is enabled.
/// </summary>
public bool Loop { get; set; } = false;
private bool _isDragging;
/// <summary>
/// Gets or sets the peek amount (how much of adjacent items to show).
/// </summary>
public float PeekAreaInsets { get; set; } = 0f;
private float _dragStartX;
/// <summary>
/// Gets or sets the spacing between items.
/// </summary>
public float ItemSpacing { get; set; } = 0f;
private float _dragStartOffset;
/// <summary>
/// Gets or sets whether swipe gestures are enabled.
/// </summary>
public bool IsSwipeEnabled { get; set; } = true;
private float _velocity;
/// <summary>
/// Gets or sets the indicator visibility.
/// </summary>
public bool ShowIndicators { get; set; } = true;
private DateTime _lastDragTime;
/// <summary>
/// Gets or sets the indicator color.
/// </summary>
public SKColor IndicatorColor { get; set; } = new SKColor(180, 180, 180);
private float _lastDragX;
/// <summary>
/// Gets or sets the selected indicator color.
/// </summary>
public SKColor SelectedIndicatorColor { get; set; } = new SKColor(33, 150, 243);
private bool _isAnimating;
/// <summary>
/// Event raised when position changes.
/// </summary>
public event EventHandler<PositionChangedEventArgs>? PositionChanged;
private float _animationStartOffset;
/// <summary>
/// Event raised when scrolling.
/// </summary>
public event EventHandler? Scrolled;
private float _animationTargetOffset;
/// <summary>
/// Adds an item to the carousel.
/// </summary>
public void AddItem(SkiaView item)
{
_items.Add(item);
AddChild(item);
InvalidateMeasure();
Invalidate();
}
private DateTime _animationStartTime;
/// <summary>
/// Removes an item from the carousel.
/// </summary>
public void RemoveItem(SkiaView item)
{
if (_items.Remove(item))
{
RemoveChild(item);
if (_currentPosition >= _items.Count)
{
_currentPosition = Math.Max(0, _items.Count - 1);
}
InvalidateMeasure();
Invalidate();
}
}
private const float AnimationDurationMs = 300f;
/// <summary>
/// Clears all items.
/// </summary>
public void ClearItems()
{
foreach (var item in _items)
{
RemoveChild(item);
}
_items.Clear();
_currentPosition = 0;
_scrollOffset = 0;
_targetScrollOffset = 0;
InvalidateMeasure();
Invalidate();
}
public int Position
{
get
{
return _currentPosition;
}
set
{
if (value >= 0 && value < _items.Count && value != _currentPosition)
{
int currentPosition = _currentPosition;
_currentPosition = value;
AnimateToPosition(value);
this.PositionChanged?.Invoke(this, new PositionChangedEventArgs(currentPosition, value));
}
}
}
/// <summary>
/// Scrolls to the specified position.
/// </summary>
public void ScrollTo(int position, bool animate = true)
{
if (position < 0 || position >= _items.Count) return;
public int ItemCount => _items.Count;
int oldPosition = _currentPosition;
_currentPosition = position;
public bool Loop { get; set; }
if (animate)
{
AnimateToPosition(position);
}
else
{
_scrollOffset = GetOffsetForPosition(position);
_targetScrollOffset = _scrollOffset;
Invalidate();
}
public float PeekAreaInsets { get; set; }
if (oldPosition != position)
{
PositionChanged?.Invoke(this, new PositionChangedEventArgs(oldPosition, position));
}
}
public float ItemSpacing { get; set; }
private void AnimateToPosition(int position)
{
_animationStartOffset = _scrollOffset;
_animationTargetOffset = GetOffsetForPosition(position);
_animationStartTime = DateTime.UtcNow;
_isAnimating = true;
Invalidate();
}
public bool IsSwipeEnabled { get; set; } = true;
private float GetOffsetForPosition(int position)
{
float itemWidth = Bounds.Width - PeekAreaInsets * 2;
return position * (itemWidth + ItemSpacing);
}
public bool ShowIndicators { get; set; } = true;
private int GetPositionForOffset(float offset)
{
float itemWidth = Bounds.Width - PeekAreaInsets * 2;
if (itemWidth <= 0) return 0;
return Math.Clamp((int)Math.Round(offset / (itemWidth + ItemSpacing)), 0, Math.Max(0, _items.Count - 1));
}
public SKColor IndicatorColor { get; set; } = new SKColor((byte)180, (byte)180, (byte)180);
protected override SKSize MeasureOverride(SKSize availableSize)
{
float itemWidth = availableSize.Width - PeekAreaInsets * 2;
float itemHeight = availableSize.Height - (ShowIndicators ? 30 : 0);
public SKColor SelectedIndicatorColor { get; set; } = new SKColor((byte)33, (byte)150, (byte)243);
foreach (var item in _items)
{
item.Measure(new SKSize(itemWidth, itemHeight));
}
public event EventHandler<PositionChangedEventArgs>? PositionChanged;
return availableSize;
}
public event EventHandler? Scrolled;
protected override SKRect ArrangeOverride(SKRect bounds)
{
float itemWidth = bounds.Width - PeekAreaInsets * 2;
float itemHeight = bounds.Height - (ShowIndicators ? 30 : 0);
public void AddItem(SkiaView item)
{
_items.Add(item);
AddChild(item);
InvalidateMeasure();
Invalidate();
}
for (int i = 0; i < _items.Count; i++)
{
float x = bounds.Left + PeekAreaInsets + i * (itemWidth + ItemSpacing) - _scrollOffset;
var itemBounds = new SKRect(x, bounds.Top, x + itemWidth, bounds.Top + itemHeight);
_items[i].Arrange(itemBounds);
}
public void RemoveItem(SkiaView item)
{
if (_items.Remove(item))
{
RemoveChild(item);
if (_currentPosition >= _items.Count)
{
_currentPosition = Math.Max(0, _items.Count - 1);
}
InvalidateMeasure();
Invalidate();
}
}
return bounds;
}
public void ClearItems()
{
foreach (SkiaView item in _items)
{
RemoveChild(item);
}
_items.Clear();
_currentPosition = 0;
_scrollOffset = 0f;
_targetScrollOffset = 0f;
InvalidateMeasure();
Invalidate();
}
protected override void OnDraw(SKCanvas canvas, SKRect bounds)
{
// Update animation
if (_isAnimating)
{
float elapsed = (float)(DateTime.UtcNow - _animationStartTime).TotalMilliseconds;
float progress = Math.Clamp(elapsed / AnimationDurationMs, 0f, 1f);
public void ScrollTo(int position, bool animate = true)
{
if (position >= 0 && position < _items.Count)
{
int currentPosition = _currentPosition;
_currentPosition = position;
if (animate)
{
AnimateToPosition(position);
}
else
{
_scrollOffset = GetOffsetForPosition(position);
_targetScrollOffset = _scrollOffset;
Invalidate();
}
if (currentPosition != position)
{
this.PositionChanged?.Invoke(this, new PositionChangedEventArgs(currentPosition, position));
}
}
}
// Ease out cubic
float t = 1f - (1f - progress) * (1f - progress) * (1f - progress);
private void AnimateToPosition(int position)
{
_animationStartOffset = _scrollOffset;
_animationTargetOffset = GetOffsetForPosition(position);
_animationStartTime = DateTime.UtcNow;
_isAnimating = true;
Invalidate();
}
_scrollOffset = _animationStartOffset + (_animationTargetOffset - _animationStartOffset) * t;
private float GetOffsetForPosition(int position)
{
//IL_0001: Unknown result type (might be due to invalid IL or missing references)
//IL_0006: Unknown result type (might be due to invalid IL or missing references)
SKRect bounds = base.Bounds;
float num = ((SKRect)(ref bounds)).Width - PeekAreaInsets * 2f;
return (float)position * (num + ItemSpacing);
}
if (progress >= 1f)
{
_isAnimating = false;
_scrollOffset = _animationTargetOffset;
}
else
{
Invalidate(); // Continue animation
}
}
private int GetPositionForOffset(float offset)
{
//IL_0001: Unknown result type (might be due to invalid IL or missing references)
//IL_0006: Unknown result type (might be due to invalid IL or missing references)
SKRect bounds = base.Bounds;
float num = ((SKRect)(ref bounds)).Width - PeekAreaInsets * 2f;
if (num <= 0f)
{
return 0;
}
return Math.Clamp((int)Math.Round(offset / (num + ItemSpacing)), 0, Math.Max(0, _items.Count - 1));
}
canvas.Save();
canvas.ClipRect(bounds);
protected override SKSize MeasureOverride(SKSize availableSize)
{
//IL_0043: Unknown result type (might be due to invalid IL or missing references)
//IL_0048: Unknown result type (might be due to invalid IL or missing references)
//IL_0067: Unknown result type (might be due to invalid IL or missing references)
float num = ((SKSize)(ref availableSize)).Width - PeekAreaInsets * 2f;
float num2 = ((SKSize)(ref availableSize)).Height - (float)(ShowIndicators ? 30 : 0);
foreach (SkiaView item in _items)
{
item.Measure(new SKSize(num, num2));
}
return availableSize;
}
// Draw visible items
float itemWidth = bounds.Width - PeekAreaInsets * 2;
float contentHeight = bounds.Height - (ShowIndicators ? 30 : 0);
protected override SKRect ArrangeOverride(SKRect bounds)
{
//IL_0079: Unknown result type (might be due to invalid IL or missing references)
//IL_0092: Unknown result type (might be due to invalid IL or missing references)
float num = ((SKRect)(ref bounds)).Width - PeekAreaInsets * 2f;
float num2 = ((SKRect)(ref bounds)).Height - (float)(ShowIndicators ? 30 : 0);
SKRect bounds2 = default(SKRect);
for (int i = 0; i < _items.Count; i++)
{
float num3 = ((SKRect)(ref bounds)).Left + PeekAreaInsets + (float)i * (num + ItemSpacing) - _scrollOffset;
((SKRect)(ref bounds2))._002Ector(num3, ((SKRect)(ref bounds)).Top, num3 + num, ((SKRect)(ref bounds)).Top + num2);
_items[i].Arrange(bounds2);
}
return bounds;
}
for (int i = 0; i < _items.Count; i++)
{
float x = bounds.Left + PeekAreaInsets + i * (itemWidth + ItemSpacing) - _scrollOffset;
protected override void OnDraw(SKCanvas canvas, SKRect bounds)
{
//IL_009f: Unknown result type (might be due to invalid IL or missing references)
//IL_014c: Unknown result type (might be due to invalid IL or missing references)
if (_isAnimating)
{
float num = Math.Clamp((float)(DateTime.UtcNow - _animationStartTime).TotalMilliseconds / 300f, 0f, 1f);
float num2 = 1f - (1f - num) * (1f - num) * (1f - num);
_scrollOffset = _animationStartOffset + (_animationTargetOffset - _animationStartOffset) * num2;
if (num >= 1f)
{
_isAnimating = false;
_scrollOffset = _animationTargetOffset;
}
else
{
Invalidate();
}
}
canvas.Save();
canvas.ClipRect(bounds, (SKClipOperation)1, false);
float num3 = ((SKRect)(ref bounds)).Width - PeekAreaInsets * 2f;
_ = ((SKRect)(ref bounds)).Height;
_ = ShowIndicators;
for (int i = 0; i < _items.Count; i++)
{
float num4 = ((SKRect)(ref bounds)).Left + PeekAreaInsets + (float)i * (num3 + ItemSpacing) - _scrollOffset;
if (num4 + num3 > ((SKRect)(ref bounds)).Left && num4 < ((SKRect)(ref bounds)).Right)
{
_items[i].Draw(canvas);
}
}
if (ShowIndicators && _items.Count > 1)
{
DrawIndicators(canvas, bounds);
}
canvas.Restore();
}
// Only draw visible items
if (x + itemWidth > bounds.Left && x < bounds.Right)
{
_items[i].Draw(canvas);
}
}
private void DrawIndicators(SKCanvas canvas, SKRect bounds)
{
//IL_004d: Unknown result type (might be due to invalid IL or missing references)
//IL_0052: Unknown result type (might be due to invalid IL or missing references)
//IL_0054: Unknown result type (might be due to invalid IL or missing references)
//IL_005e: Unknown result type (might be due to invalid IL or missing references)
//IL_0065: Unknown result type (might be due to invalid IL or missing references)
//IL_006e: Expected O, but got Unknown
//IL_006e: Unknown result type (might be due to invalid IL or missing references)
//IL_0073: Unknown result type (might be due to invalid IL or missing references)
//IL_0075: Unknown result type (might be due to invalid IL or missing references)
//IL_007f: Unknown result type (might be due to invalid IL or missing references)
//IL_0086: Unknown result type (might be due to invalid IL or missing references)
//IL_008f: Expected O, but got Unknown
float num = 8f;
float num2 = 12f;
float num3 = (float)_items.Count * num + (float)(_items.Count - 1) * (num2 - num);
float num4 = ((SKRect)(ref bounds)).MidX - num3 / 2f;
float num5 = ((SKRect)(ref bounds)).Bottom - 15f;
SKPaint val = new SKPaint
{
Color = IndicatorColor,
Style = (SKPaintStyle)0,
IsAntialias = true
};
try
{
SKPaint val2 = new SKPaint
{
Color = SelectedIndicatorColor,
Style = (SKPaintStyle)0,
IsAntialias = true
};
try
{
for (int i = 0; i < _items.Count; i++)
{
float num6 = num4 + (float)i * num2;
SKPaint val3 = ((i == _currentPosition) ? val2 : val);
canvas.DrawCircle(num6, num5, num / 2f, val3);
}
}
finally
{
((IDisposable)val2)?.Dispose();
}
}
finally
{
((IDisposable)val)?.Dispose();
}
}
// Draw indicators
if (ShowIndicators && _items.Count > 1)
{
DrawIndicators(canvas, bounds);
}
public override SkiaView? HitTest(float x, float y)
{
//IL_0009: Unknown result type (might be due to invalid IL or missing references)
//IL_000e: Unknown result type (might be due to invalid IL or missing references)
if (base.IsVisible)
{
SKRect bounds = base.Bounds;
if (((SKRect)(ref bounds)).Contains(x, y))
{
{
foreach (SkiaView item in _items)
{
SkiaView skiaView = item.HitTest(x, y);
if (skiaView != null)
{
return skiaView;
}
}
return this;
}
}
}
return null;
}
canvas.Restore();
}
public override void OnPointerPressed(PointerEventArgs e)
{
if (base.IsEnabled && IsSwipeEnabled)
{
_isDragging = true;
_dragStartX = e.X;
_dragStartOffset = _scrollOffset;
_lastDragX = e.X;
_lastDragTime = DateTime.UtcNow;
_velocity = 0f;
_isAnimating = false;
e.Handled = true;
base.OnPointerPressed(e);
}
}
private void DrawIndicators(SKCanvas canvas, SKRect bounds)
{
float indicatorSize = 8f;
float indicatorSpacing = 12f;
float totalWidth = _items.Count * indicatorSize + (_items.Count - 1) * (indicatorSpacing - indicatorSize);
float startX = bounds.MidX - totalWidth / 2;
float y = bounds.Bottom - 15;
public override void OnPointerMoved(PointerEventArgs e)
{
if (_isDragging)
{
float num = _dragStartX - e.X;
_scrollOffset = _dragStartOffset + num;
float offsetForPosition = GetOffsetForPosition(_items.Count - 1);
_scrollOffset = Math.Clamp(_scrollOffset, 0f, offsetForPosition);
DateTime utcNow = DateTime.UtcNow;
float num2 = (float)(utcNow - _lastDragTime).TotalSeconds;
if (num2 > 0f)
{
_velocity = (_lastDragX - e.X) / num2;
}
_lastDragX = e.X;
_lastDragTime = utcNow;
this.Scrolled?.Invoke(this, EventArgs.Empty);
Invalidate();
e.Handled = true;
base.OnPointerMoved(e);
}
}
using var normalPaint = new SKPaint
{
Color = IndicatorColor,
Style = SKPaintStyle.Fill,
IsAntialias = true
};
using var selectedPaint = new SKPaint
{
Color = SelectedIndicatorColor,
Style = SKPaintStyle.Fill,
IsAntialias = true
};
for (int i = 0; i < _items.Count; i++)
{
float x = startX + i * indicatorSpacing;
var paint = i == _currentPosition ? selectedPaint : normalPaint;
canvas.DrawCircle(x, y, indicatorSize / 2, paint);
}
}
public override SkiaView? HitTest(float x, float y)
{
if (!IsVisible || !Bounds.Contains(x, y)) return null;
// Check items
foreach (var item in _items)
{
var hit = item.HitTest(x, y);
if (hit != null) return hit;
}
return this;
}
public override void OnPointerPressed(PointerEventArgs e)
{
if (!IsEnabled || !IsSwipeEnabled) return;
_isDragging = true;
_dragStartX = e.X;
_dragStartOffset = _scrollOffset;
_lastDragX = e.X;
_lastDragTime = DateTime.UtcNow;
_velocity = 0;
_isAnimating = false;
e.Handled = true;
base.OnPointerPressed(e);
}
public override void OnPointerMoved(PointerEventArgs e)
{
if (!_isDragging) return;
float delta = _dragStartX - e.X;
_scrollOffset = _dragStartOffset + delta;
// Clamp scrolling
float maxOffset = GetOffsetForPosition(_items.Count - 1);
_scrollOffset = Math.Clamp(_scrollOffset, 0, maxOffset);
// Calculate velocity
var now = DateTime.UtcNow;
float timeDelta = (float)(now - _lastDragTime).TotalSeconds;
if (timeDelta > 0)
{
_velocity = (_lastDragX - e.X) / timeDelta;
}
_lastDragX = e.X;
_lastDragTime = now;
Scrolled?.Invoke(this, EventArgs.Empty);
Invalidate();
e.Handled = true;
base.OnPointerMoved(e);
}
public override void OnPointerReleased(PointerEventArgs e)
{
if (!_isDragging) return;
_isDragging = false;
// Determine target position based on velocity and position
float itemWidth = Bounds.Width - PeekAreaInsets * 2;
int targetPosition = GetPositionForOffset(_scrollOffset);
// Apply velocity influence
if (Math.Abs(_velocity) > 500)
{
if (_velocity > 0 && targetPosition < _items.Count - 1)
{
targetPosition++;
}
else if (_velocity < 0 && targetPosition > 0)
{
targetPosition--;
}
}
ScrollTo(targetPosition, true);
e.Handled = true;
base.OnPointerReleased(e);
}
}
/// <summary>
/// Event args for position changed events.
/// </summary>
public class PositionChangedEventArgs : EventArgs
{
public int PreviousPosition { get; }
public int CurrentPosition { get; }
public PositionChangedEventArgs(int previousPosition, int currentPosition)
{
PreviousPosition = previousPosition;
CurrentPosition = currentPosition;
}
public override void OnPointerReleased(PointerEventArgs e)
{
//IL_0011: Unknown result type (might be due to invalid IL or missing references)
//IL_0016: Unknown result type (might be due to invalid IL or missing references)
if (!_isDragging)
{
return;
}
_isDragging = false;
SKRect bounds = base.Bounds;
_ = ((SKRect)(ref bounds)).Width;
_ = PeekAreaInsets;
int num = GetPositionForOffset(_scrollOffset);
if (Math.Abs(_velocity) > 500f)
{
if (_velocity > 0f && num < _items.Count - 1)
{
num++;
}
else if (_velocity < 0f && num > 0)
{
num--;
}
}
ScrollTo(num);
e.Handled = true;
base.OnPointerReleased(e);
}
}

View File

@@ -1,413 +1,454 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System;
using System.Runtime.CompilerServices;
using Microsoft.Maui.Controls;
using SkiaSharp;
using Microsoft.Maui.Platform.Linux.Rendering;
namespace Microsoft.Maui.Platform;
/// <summary>
/// Skia-rendered checkbox control with full XAML styling support.
/// </summary>
public class SkiaCheckBox : SkiaView
{
#region BindableProperties
public static readonly BindableProperty IsCheckedProperty = BindableProperty.Create("IsChecked", typeof(bool), typeof(SkiaCheckBox), (object)false, (BindingMode)1, (ValidateValueDelegate)null, (BindingPropertyChangedDelegate)delegate(BindableObject b, object o, object n)
{
((SkiaCheckBox)(object)b).OnIsCheckedChanged();
}, (BindingPropertyChangingDelegate)null, (CoerceValueDelegate)null, (CreateDefaultValueDelegate)null);
/// <summary>
/// Bindable property for IsChecked.
/// </summary>
public static readonly BindableProperty IsCheckedProperty =
BindableProperty.Create(
nameof(IsChecked),
typeof(bool),
typeof(SkiaCheckBox),
false,
BindingMode.TwoWay,
propertyChanged: (b, o, n) => ((SkiaCheckBox)b).OnIsCheckedChanged());
public static readonly BindableProperty CheckColorProperty = BindableProperty.Create("CheckColor", typeof(SKColor), typeof(SkiaCheckBox), (object)SKColors.White, (BindingMode)2, (ValidateValueDelegate)null, (BindingPropertyChangedDelegate)delegate(BindableObject b, object o, object n)
{
((SkiaCheckBox)(object)b).Invalidate();
}, (BindingPropertyChangingDelegate)null, (CoerceValueDelegate)null, (CreateDefaultValueDelegate)null);
/// <summary>
/// Bindable property for CheckColor.
/// </summary>
public static readonly BindableProperty CheckColorProperty =
BindableProperty.Create(
nameof(CheckColor),
typeof(SKColor),
typeof(SkiaCheckBox),
SKColors.White,
propertyChanged: (b, o, n) => ((SkiaCheckBox)b).Invalidate());
public static readonly BindableProperty BoxColorProperty = BindableProperty.Create("BoxColor", typeof(SKColor), typeof(SkiaCheckBox), (object)new SKColor((byte)33, (byte)150, (byte)243), (BindingMode)2, (ValidateValueDelegate)null, (BindingPropertyChangedDelegate)delegate(BindableObject b, object o, object n)
{
((SkiaCheckBox)(object)b).Invalidate();
}, (BindingPropertyChangingDelegate)null, (CoerceValueDelegate)null, (CreateDefaultValueDelegate)null);
/// <summary>
/// Bindable property for BoxColor.
/// </summary>
public static readonly BindableProperty BoxColorProperty =
BindableProperty.Create(
nameof(BoxColor),
typeof(SKColor),
typeof(SkiaCheckBox),
new SKColor(0x21, 0x96, 0xF3),
propertyChanged: (b, o, n) => ((SkiaCheckBox)b).Invalidate());
public static readonly BindableProperty UncheckedBoxColorProperty = BindableProperty.Create("UncheckedBoxColor", typeof(SKColor), typeof(SkiaCheckBox), (object)SKColors.White, (BindingMode)2, (ValidateValueDelegate)null, (BindingPropertyChangedDelegate)delegate(BindableObject b, object o, object n)
{
((SkiaCheckBox)(object)b).Invalidate();
}, (BindingPropertyChangingDelegate)null, (CoerceValueDelegate)null, (CreateDefaultValueDelegate)null);
/// <summary>
/// Bindable property for UncheckedBoxColor.
/// </summary>
public static readonly BindableProperty UncheckedBoxColorProperty =
BindableProperty.Create(
nameof(UncheckedBoxColor),
typeof(SKColor),
typeof(SkiaCheckBox),
SKColors.White,
propertyChanged: (b, o, n) => ((SkiaCheckBox)b).Invalidate());
public static readonly BindableProperty BorderColorProperty = BindableProperty.Create("BorderColor", typeof(SKColor), typeof(SkiaCheckBox), (object)new SKColor((byte)117, (byte)117, (byte)117), (BindingMode)2, (ValidateValueDelegate)null, (BindingPropertyChangedDelegate)delegate(BindableObject b, object o, object n)
{
((SkiaCheckBox)(object)b).Invalidate();
}, (BindingPropertyChangingDelegate)null, (CoerceValueDelegate)null, (CreateDefaultValueDelegate)null);
/// <summary>
/// Bindable property for BorderColor.
/// </summary>
public static readonly BindableProperty BorderColorProperty =
BindableProperty.Create(
nameof(BorderColor),
typeof(SKColor),
typeof(SkiaCheckBox),
new SKColor(0x75, 0x75, 0x75),
propertyChanged: (b, o, n) => ((SkiaCheckBox)b).Invalidate());
public static readonly BindableProperty DisabledColorProperty = BindableProperty.Create("DisabledColor", typeof(SKColor), typeof(SkiaCheckBox), (object)new SKColor((byte)189, (byte)189, (byte)189), (BindingMode)2, (ValidateValueDelegate)null, (BindingPropertyChangedDelegate)delegate(BindableObject b, object o, object n)
{
((SkiaCheckBox)(object)b).Invalidate();
}, (BindingPropertyChangingDelegate)null, (CoerceValueDelegate)null, (CreateDefaultValueDelegate)null);
/// <summary>
/// Bindable property for DisabledColor.
/// </summary>
public static readonly BindableProperty DisabledColorProperty =
BindableProperty.Create(
nameof(DisabledColor),
typeof(SKColor),
typeof(SkiaCheckBox),
new SKColor(0xBD, 0xBD, 0xBD),
propertyChanged: (b, o, n) => ((SkiaCheckBox)b).Invalidate());
public static readonly BindableProperty HoveredBorderColorProperty = BindableProperty.Create("HoveredBorderColor", typeof(SKColor), typeof(SkiaCheckBox), (object)new SKColor((byte)33, (byte)150, (byte)243), (BindingMode)2, (ValidateValueDelegate)null, (BindingPropertyChangedDelegate)delegate(BindableObject b, object o, object n)
{
((SkiaCheckBox)(object)b).Invalidate();
}, (BindingPropertyChangingDelegate)null, (CoerceValueDelegate)null, (CreateDefaultValueDelegate)null);
/// <summary>
/// Bindable property for HoveredBorderColor.
/// </summary>
public static readonly BindableProperty HoveredBorderColorProperty =
BindableProperty.Create(
nameof(HoveredBorderColor),
typeof(SKColor),
typeof(SkiaCheckBox),
new SKColor(0x21, 0x96, 0xF3),
propertyChanged: (b, o, n) => ((SkiaCheckBox)b).Invalidate());
public static readonly BindableProperty BoxSizeProperty = BindableProperty.Create("BoxSize", typeof(float), typeof(SkiaCheckBox), (object)20f, (BindingMode)2, (ValidateValueDelegate)null, (BindingPropertyChangedDelegate)delegate(BindableObject b, object o, object n)
{
((SkiaCheckBox)(object)b).InvalidateMeasure();
}, (BindingPropertyChangingDelegate)null, (CoerceValueDelegate)null, (CreateDefaultValueDelegate)null);
/// <summary>
/// Bindable property for BoxSize.
/// </summary>
public static readonly BindableProperty BoxSizeProperty =
BindableProperty.Create(
nameof(BoxSize),
typeof(float),
typeof(SkiaCheckBox),
20f,
propertyChanged: (b, o, n) => ((SkiaCheckBox)b).InvalidateMeasure());
public static readonly BindableProperty CornerRadiusProperty = BindableProperty.Create("CornerRadius", typeof(float), typeof(SkiaCheckBox), (object)3f, (BindingMode)2, (ValidateValueDelegate)null, (BindingPropertyChangedDelegate)delegate(BindableObject b, object o, object n)
{
((SkiaCheckBox)(object)b).Invalidate();
}, (BindingPropertyChangingDelegate)null, (CoerceValueDelegate)null, (CreateDefaultValueDelegate)null);
/// <summary>
/// Bindable property for CornerRadius.
/// </summary>
public static readonly BindableProperty CornerRadiusProperty =
BindableProperty.Create(
nameof(CornerRadius),
typeof(float),
typeof(SkiaCheckBox),
3f,
propertyChanged: (b, o, n) => ((SkiaCheckBox)b).Invalidate());
public static readonly BindableProperty BorderWidthProperty = BindableProperty.Create("BorderWidth", typeof(float), typeof(SkiaCheckBox), (object)2f, (BindingMode)2, (ValidateValueDelegate)null, (BindingPropertyChangedDelegate)delegate(BindableObject b, object o, object n)
{
((SkiaCheckBox)(object)b).Invalidate();
}, (BindingPropertyChangingDelegate)null, (CoerceValueDelegate)null, (CreateDefaultValueDelegate)null);
/// <summary>
/// Bindable property for BorderWidth.
/// </summary>
public static readonly BindableProperty BorderWidthProperty =
BindableProperty.Create(
nameof(BorderWidth),
typeof(float),
typeof(SkiaCheckBox),
2f,
propertyChanged: (b, o, n) => ((SkiaCheckBox)b).Invalidate());
public static readonly BindableProperty CheckStrokeWidthProperty = BindableProperty.Create("CheckStrokeWidth", typeof(float), typeof(SkiaCheckBox), (object)2.5f, (BindingMode)2, (ValidateValueDelegate)null, (BindingPropertyChangedDelegate)delegate(BindableObject b, object o, object n)
{
((SkiaCheckBox)(object)b).Invalidate();
}, (BindingPropertyChangingDelegate)null, (CoerceValueDelegate)null, (CreateDefaultValueDelegate)null);
/// <summary>
/// Bindable property for CheckStrokeWidth.
/// </summary>
public static readonly BindableProperty CheckStrokeWidthProperty =
BindableProperty.Create(
nameof(CheckStrokeWidth),
typeof(float),
typeof(SkiaCheckBox),
2.5f,
propertyChanged: (b, o, n) => ((SkiaCheckBox)b).Invalidate());
public bool IsChecked
{
get
{
return (bool)((BindableObject)this).GetValue(IsCheckedProperty);
}
set
{
((BindableObject)this).SetValue(IsCheckedProperty, (object)value);
}
}
#endregion
public SKColor CheckColor
{
get
{
//IL_000b: Unknown result type (might be due to invalid IL or missing references)
return (SKColor)((BindableObject)this).GetValue(CheckColorProperty);
}
set
{
//IL_0006: Unknown result type (might be due to invalid IL or missing references)
((BindableObject)this).SetValue(CheckColorProperty, (object)value);
}
}
#region Properties
public SKColor BoxColor
{
get
{
//IL_000b: Unknown result type (might be due to invalid IL or missing references)
return (SKColor)((BindableObject)this).GetValue(BoxColorProperty);
}
set
{
//IL_0006: Unknown result type (might be due to invalid IL or missing references)
((BindableObject)this).SetValue(BoxColorProperty, (object)value);
}
}
/// <summary>
/// Gets or sets whether the checkbox is checked.
/// </summary>
public bool IsChecked
{
get => (bool)GetValue(IsCheckedProperty);
set => SetValue(IsCheckedProperty, value);
}
public SKColor UncheckedBoxColor
{
get
{
//IL_000b: Unknown result type (might be due to invalid IL or missing references)
return (SKColor)((BindableObject)this).GetValue(UncheckedBoxColorProperty);
}
set
{
//IL_0006: Unknown result type (might be due to invalid IL or missing references)
((BindableObject)this).SetValue(UncheckedBoxColorProperty, (object)value);
}
}
/// <summary>
/// Gets or sets the check color.
/// </summary>
public SKColor CheckColor
{
get => (SKColor)GetValue(CheckColorProperty);
set => SetValue(CheckColorProperty, value);
}
public SKColor BorderColor
{
get
{
//IL_000b: Unknown result type (might be due to invalid IL or missing references)
return (SKColor)((BindableObject)this).GetValue(BorderColorProperty);
}
set
{
//IL_0006: Unknown result type (might be due to invalid IL or missing references)
((BindableObject)this).SetValue(BorderColorProperty, (object)value);
}
}
/// <summary>
/// Gets or sets the box color when checked.
/// </summary>
public SKColor BoxColor
{
get => (SKColor)GetValue(BoxColorProperty);
set => SetValue(BoxColorProperty, value);
}
public SKColor DisabledColor
{
get
{
//IL_000b: Unknown result type (might be due to invalid IL or missing references)
return (SKColor)((BindableObject)this).GetValue(DisabledColorProperty);
}
set
{
//IL_0006: Unknown result type (might be due to invalid IL or missing references)
((BindableObject)this).SetValue(DisabledColorProperty, (object)value);
}
}
/// <summary>
/// Gets or sets the box color when unchecked.
/// </summary>
public SKColor UncheckedBoxColor
{
get => (SKColor)GetValue(UncheckedBoxColorProperty);
set => SetValue(UncheckedBoxColorProperty, value);
}
public SKColor HoveredBorderColor
{
get
{
//IL_000b: Unknown result type (might be due to invalid IL or missing references)
return (SKColor)((BindableObject)this).GetValue(HoveredBorderColorProperty);
}
set
{
//IL_0006: Unknown result type (might be due to invalid IL or missing references)
((BindableObject)this).SetValue(HoveredBorderColorProperty, (object)value);
}
}
/// <summary>
/// Gets or sets the border color.
/// </summary>
public SKColor BorderColor
{
get => (SKColor)GetValue(BorderColorProperty);
set => SetValue(BorderColorProperty, value);
}
public float BoxSize
{
get
{
return (float)((BindableObject)this).GetValue(BoxSizeProperty);
}
set
{
((BindableObject)this).SetValue(BoxSizeProperty, (object)value);
}
}
/// <summary>
/// Gets or sets the disabled color.
/// </summary>
public SKColor DisabledColor
{
get => (SKColor)GetValue(DisabledColorProperty);
set => SetValue(DisabledColorProperty, value);
}
public float CornerRadius
{
get
{
return (float)((BindableObject)this).GetValue(CornerRadiusProperty);
}
set
{
((BindableObject)this).SetValue(CornerRadiusProperty, (object)value);
}
}
/// <summary>
/// Gets or sets the hovered border color.
/// </summary>
public SKColor HoveredBorderColor
{
get => (SKColor)GetValue(HoveredBorderColorProperty);
set => SetValue(HoveredBorderColorProperty, value);
}
public float BorderWidth
{
get
{
return (float)((BindableObject)this).GetValue(BorderWidthProperty);
}
set
{
((BindableObject)this).SetValue(BorderWidthProperty, (object)value);
}
}
/// <summary>
/// Gets or sets the box size.
/// </summary>
public float BoxSize
{
get => (float)GetValue(BoxSizeProperty);
set => SetValue(BoxSizeProperty, value);
}
public float CheckStrokeWidth
{
get
{
return (float)((BindableObject)this).GetValue(CheckStrokeWidthProperty);
}
set
{
((BindableObject)this).SetValue(CheckStrokeWidthProperty, (object)value);
}
}
/// <summary>
/// Gets or sets the corner radius.
/// </summary>
public float CornerRadius
{
get => (float)GetValue(CornerRadiusProperty);
set => SetValue(CornerRadiusProperty, value);
}
public bool IsHovered { get; private set; }
/// <summary>
/// Gets or sets the border width.
/// </summary>
public float BorderWidth
{
get => (float)GetValue(BorderWidthProperty);
set => SetValue(BorderWidthProperty, value);
}
public event EventHandler<CheckedChangedEventArgs>? CheckedChanged;
/// <summary>
/// Gets or sets the check stroke width.
/// </summary>
public float CheckStrokeWidth
{
get => (float)GetValue(CheckStrokeWidthProperty);
set => SetValue(CheckStrokeWidthProperty, value);
}
public SkiaCheckBox()
{
base.IsFocusable = true;
}
/// <summary>
/// Gets whether the pointer is over the checkbox.
/// </summary>
public bool IsHovered { get; private set; }
private void OnIsCheckedChanged()
{
this.CheckedChanged?.Invoke(this, new CheckedChangedEventArgs(IsChecked));
SkiaVisualStateManager.GoToState(this, IsChecked ? "Checked" : "Unchecked");
Invalidate();
}
#endregion
protected override void OnDraw(SKCanvas canvas, SKRect bounds)
{
//IL_0085: Unknown result type (might be due to invalid IL or missing references)
//IL_008c: Unknown result type (might be due to invalid IL or missing references)
//IL_0092: Expected O, but got Unknown
//IL_018b: Unknown result type (might be due to invalid IL or missing references)
//IL_0190: Unknown result type (might be due to invalid IL or missing references)
//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
//IL_00dd: Unknown result type (might be due to invalid IL or missing references)
//IL_00fa: Unknown result type (might be due to invalid IL or missing references)
//IL_00ff: Unknown result type (might be due to invalid IL or missing references)
//IL_011c: Unknown result type (might be due to invalid IL or missing references)
//IL_0121: Unknown result type (might be due to invalid IL or missing references)
//IL_013e: Unknown result type (might be due to invalid IL or missing references)
//IL_0143: Unknown result type (might be due to invalid IL or missing references)
//IL_0160: Unknown result type (might be due to invalid IL or missing references)
//IL_0165: Unknown result type (might be due to invalid IL or missing references)
//IL_01b2: Unknown result type (might be due to invalid IL or missing references)
//IL_01bc: Unknown result type (might be due to invalid IL or missing references)
//IL_01c3: Unknown result type (might be due to invalid IL or missing references)
//IL_01cb: Expected O, but got Unknown
//IL_01aa: Unknown result type (might be due to invalid IL or missing references)
//IL_01a2: Unknown result type (might be due to invalid IL or missing references)
//IL_01d3: Unknown result type (might be due to invalid IL or missing references)
//IL_01d8: Unknown result type (might be due to invalid IL or missing references)
//IL_020a: Unknown result type (might be due to invalid IL or missing references)
//IL_0214: Unknown result type (might be due to invalid IL or missing references)
//IL_021b: Unknown result type (might be due to invalid IL or missing references)
//IL_0222: Unknown result type (might be due to invalid IL or missing references)
//IL_022f: Expected O, but got Unknown
//IL_0202: Unknown result type (might be due to invalid IL or missing references)
//IL_01fa: Unknown result type (might be due to invalid IL or missing references)
//IL_01f2: Unknown result type (might be due to invalid IL or missing references)
//IL_023f: Unknown result type (might be due to invalid IL or missing references)
//IL_0244: Unknown result type (might be due to invalid IL or missing references)
//IL_0246: Unknown result type (might be due to invalid IL or missing references)
//IL_024b: Unknown result type (might be due to invalid IL or missing references)
//IL_0251: Unknown result type (might be due to invalid IL or missing references)
//IL_025b: Unknown result type (might be due to invalid IL or missing references)
//IL_0262: Unknown result type (might be due to invalid IL or missing references)
//IL_0269: Unknown result type (might be due to invalid IL or missing references)
//IL_0276: Expected O, but got Unknown
//IL_02b7: Unknown result type (might be due to invalid IL or missing references)
//IL_0276: Unknown result type (might be due to invalid IL or missing references)
//IL_027d: Unknown result type (might be due to invalid IL or missing references)
//IL_0284: Expected O, but got Unknown
SKRect val = default(SKRect);
((SKRect)(ref val))._002Ector(((SKRect)(ref bounds)).Left + (((SKRect)(ref bounds)).Width - BoxSize) / 2f, ((SKRect)(ref bounds)).Top + (((SKRect)(ref bounds)).Height - BoxSize) / 2f, ((SKRect)(ref bounds)).Left + (((SKRect)(ref bounds)).Width - BoxSize) / 2f + BoxSize, ((SKRect)(ref bounds)).Top + (((SKRect)(ref bounds)).Height - BoxSize) / 2f + BoxSize);
SKRoundRect val2 = new SKRoundRect(val, CornerRadius);
SKColor val3;
if (IsChecked)
{
DefaultInterpolatedStringHandler defaultInterpolatedStringHandler = new DefaultInterpolatedStringHandler(69, 6);
defaultInterpolatedStringHandler.AppendLiteral("[SkiaCheckBox] OnDraw CHECKED - BoxColor=(");
val3 = BoxColor;
defaultInterpolatedStringHandler.AppendFormatted(((SKColor)(ref val3)).Red);
defaultInterpolatedStringHandler.AppendLiteral(",");
val3 = BoxColor;
defaultInterpolatedStringHandler.AppendFormatted(((SKColor)(ref val3)).Green);
defaultInterpolatedStringHandler.AppendLiteral(",");
val3 = BoxColor;
defaultInterpolatedStringHandler.AppendFormatted(((SKColor)(ref val3)).Blue);
defaultInterpolatedStringHandler.AppendLiteral("), UncheckedBoxColor=(");
val3 = UncheckedBoxColor;
defaultInterpolatedStringHandler.AppendFormatted(((SKColor)(ref val3)).Red);
defaultInterpolatedStringHandler.AppendLiteral(",");
val3 = UncheckedBoxColor;
defaultInterpolatedStringHandler.AppendFormatted(((SKColor)(ref val3)).Green);
defaultInterpolatedStringHandler.AppendLiteral(",");
val3 = UncheckedBoxColor;
defaultInterpolatedStringHandler.AppendFormatted(((SKColor)(ref val3)).Blue);
defaultInterpolatedStringHandler.AppendLiteral(")");
Console.WriteLine(defaultInterpolatedStringHandler.ToStringAndClear());
}
SKPaint val4 = new SKPaint
{
Color = ((!base.IsEnabled) ? DisabledColor : (IsChecked ? BoxColor : UncheckedBoxColor)),
IsAntialias = true,
Style = (SKPaintStyle)0
};
try
{
canvas.DrawRoundRect(val2, val4);
SKPaint val5 = new SKPaint
{
Color = ((!base.IsEnabled) ? DisabledColor : (IsChecked ? BoxColor : (IsHovered ? HoveredBorderColor : BorderColor))),
IsAntialias = true,
Style = (SKPaintStyle)1,
StrokeWidth = BorderWidth
};
try
{
canvas.DrawRoundRect(val2, val5);
if (base.IsFocused)
{
SKPaint val6 = new SKPaint();
val3 = BoxColor;
val6.Color = ((SKColor)(ref val3)).WithAlpha((byte)80);
val6.IsAntialias = true;
val6.Style = (SKPaintStyle)1;
val6.StrokeWidth = 3f;
SKPaint val7 = val6;
try
{
SKRoundRect val8 = new SKRoundRect(val, CornerRadius);
val8.Inflate(4f, 4f);
canvas.DrawRoundRect(val8, val7);
}
finally
{
((IDisposable)val7)?.Dispose();
}
}
if (IsChecked)
{
DrawCheckmark(canvas, val);
}
}
finally
{
((IDisposable)val5)?.Dispose();
}
}
finally
{
((IDisposable)val4)?.Dispose();
}
}
/// <summary>
/// Event raised when checked state changes.
/// </summary>
public event EventHandler<CheckedChangedEventArgs>? CheckedChanged;
private void DrawCheckmark(SKCanvas canvas, SKRect boxRect)
{
//IL_0000: Unknown result type (might be due to invalid IL or missing references)
//IL_0005: Unknown result type (might be due to invalid IL or missing references)
//IL_0006: Unknown result type (might be due to invalid IL or missing references)
//IL_0010: Unknown result type (might be due to invalid IL or missing references)
//IL_0017: Unknown result type (might be due to invalid IL or missing references)
//IL_001e: Unknown result type (might be due to invalid IL or missing references)
//IL_002a: Unknown result type (might be due to invalid IL or missing references)
//IL_0031: Unknown result type (might be due to invalid IL or missing references)
//IL_0039: Expected O, but got Unknown
//IL_0070: Unknown result type (might be due to invalid IL or missing references)
//IL_0077: Expected O, but got Unknown
SKPaint val = new SKPaint
{
Color = SKColors.White,
IsAntialias = true,
Style = (SKPaintStyle)1,
StrokeWidth = CheckStrokeWidth,
StrokeCap = (SKStrokeCap)1,
StrokeJoin = (SKStrokeJoin)1
};
try
{
float num = BoxSize * 0.2f;
float num2 = ((SKRect)(ref boxRect)).Left + num;
float num3 = ((SKRect)(ref boxRect)).Right - num;
float num4 = ((SKRect)(ref boxRect)).Top + num;
float num5 = ((SKRect)(ref boxRect)).Bottom - num;
SKPath val2 = new SKPath();
try
{
val2.MoveTo(num2, ((SKRect)(ref boxRect)).MidY);
val2.LineTo(((SKRect)(ref boxRect)).MidX - num * 0.3f, num5 - num * 0.5f);
val2.LineTo(num3, num4 + num * 0.3f);
canvas.DrawPath(val2, val);
}
finally
{
((IDisposable)val2)?.Dispose();
}
}
finally
{
((IDisposable)val)?.Dispose();
}
}
public SkiaCheckBox()
{
IsFocusable = true;
}
public override void OnPointerEntered(PointerEventArgs e)
{
if (base.IsEnabled)
{
IsHovered = true;
SkiaVisualStateManager.GoToState(this, "PointerOver");
Invalidate();
}
}
private void OnIsCheckedChanged()
{
CheckedChanged?.Invoke(this, new CheckedChangedEventArgs(IsChecked));
SkiaVisualStateManager.GoToState(this, IsChecked ? SkiaVisualStateManager.CommonStates.Checked : SkiaVisualStateManager.CommonStates.Unchecked);
Invalidate();
}
public override void OnPointerExited(PointerEventArgs e)
{
IsHovered = false;
SkiaVisualStateManager.GoToState(this, base.IsEnabled ? "Normal" : "Disabled");
Invalidate();
}
protected override void OnDraw(SKCanvas canvas, SKRect bounds)
{
// Center the checkbox box in bounds
var boxRect = new SKRect(
bounds.Left + (bounds.Width - BoxSize) / 2,
bounds.Top + (bounds.Height - BoxSize) / 2,
bounds.Left + (bounds.Width - BoxSize) / 2 + BoxSize,
bounds.Top + (bounds.Height - BoxSize) / 2 + BoxSize);
public override void OnPointerPressed(PointerEventArgs e)
{
if (base.IsEnabled)
{
IsChecked = !IsChecked;
e.Handled = true;
}
}
var roundRect = new SKRoundRect(boxRect, CornerRadius);
public override void OnPointerReleased(PointerEventArgs e)
{
}
// Draw background
using var bgPaint = new SKPaint
{
Color = !IsEnabled ? DisabledColor
: IsChecked ? BoxColor
: UncheckedBoxColor,
IsAntialias = true,
Style = SKPaintStyle.Fill
};
canvas.DrawRoundRect(roundRect, bgPaint);
public override void OnKeyDown(KeyEventArgs e)
{
if (base.IsEnabled && e.Key == Key.Space)
{
IsChecked = !IsChecked;
e.Handled = true;
}
}
// Draw border
using var borderPaint = new SKPaint
{
Color = !IsEnabled ? DisabledColor
: IsChecked ? BoxColor
: IsHovered ? HoveredBorderColor
: BorderColor,
IsAntialias = true,
Style = SKPaintStyle.Stroke,
StrokeWidth = BorderWidth
};
canvas.DrawRoundRect(roundRect, borderPaint);
protected override void OnEnabledChanged()
{
base.OnEnabledChanged();
SkiaVisualStateManager.GoToState(this, base.IsEnabled ? "Normal" : "Disabled");
}
// Draw focus ring
if (IsFocused)
{
using var focusPaint = new SKPaint
{
Color = BoxColor.WithAlpha(80),
IsAntialias = true,
Style = SKPaintStyle.Stroke,
StrokeWidth = 3
};
var focusRect = new SKRoundRect(boxRect, CornerRadius);
focusRect.Inflate(4, 4);
canvas.DrawRoundRect(focusRect, focusPaint);
}
// Draw checkmark
if (IsChecked)
{
DrawCheckmark(canvas, boxRect);
}
}
private void DrawCheckmark(SKCanvas canvas, SKRect boxRect)
{
using var paint = new SKPaint
{
Color = CheckColor,
IsAntialias = true,
Style = SKPaintStyle.Stroke,
StrokeWidth = CheckStrokeWidth,
StrokeCap = SKStrokeCap.Round,
StrokeJoin = SKStrokeJoin.Round
};
// Checkmark path - a simple check
var padding = BoxSize * 0.2f;
var left = boxRect.Left + padding;
var right = boxRect.Right - padding;
var top = boxRect.Top + padding;
var bottom = boxRect.Bottom - padding;
// Check starts from bottom-left, goes to middle-bottom, then to top-right
using var path = new SKPath();
path.MoveTo(left, boxRect.MidY);
path.LineTo(boxRect.MidX - padding * 0.3f, bottom - padding * 0.5f);
path.LineTo(right, top + padding * 0.3f);
canvas.DrawPath(path, paint);
}
public override void OnPointerEntered(PointerEventArgs e)
{
if (!IsEnabled) return;
IsHovered = true;
SkiaVisualStateManager.GoToState(this, SkiaVisualStateManager.CommonStates.PointerOver);
Invalidate();
}
public override void OnPointerExited(PointerEventArgs e)
{
IsHovered = false;
SkiaVisualStateManager.GoToState(this, IsEnabled ? SkiaVisualStateManager.CommonStates.Normal : SkiaVisualStateManager.CommonStates.Disabled);
Invalidate();
}
public override void OnPointerPressed(PointerEventArgs e)
{
if (!IsEnabled) return;
IsChecked = !IsChecked;
e.Handled = true;
}
public override void OnPointerReleased(PointerEventArgs e)
{
// Toggle handled in OnPointerPressed
}
public override void OnKeyDown(KeyEventArgs e)
{
if (!IsEnabled) return;
// Toggle on Space
if (e.Key == Key.Space)
{
IsChecked = !IsChecked;
e.Handled = true;
}
}
protected override void OnEnabledChanged()
{
base.OnEnabledChanged();
SkiaVisualStateManager.GoToState(this, IsEnabled ? SkiaVisualStateManager.CommonStates.Normal : SkiaVisualStateManager.CommonStates.Disabled);
}
protected override SKSize MeasureOverride(SKSize availableSize)
{
// Add some padding around the box for touch targets
return new SKSize(BoxSize + 8, BoxSize + 8);
}
}
/// <summary>
/// Event args for checked changed events.
/// </summary>
public class CheckedChangedEventArgs : EventArgs
{
public bool IsChecked { get; }
public CheckedChangedEventArgs(bool isChecked)
{
IsChecked = isChecked;
}
protected override SKSize MeasureOverride(SKSize availableSize)
{
//IL_0018: Unknown result type (might be due to invalid IL or missing references)
return new SKSize(BoxSize + 8f, BoxSize + 8f);
}
}

View File

File diff suppressed because it is too large Load Diff

207
Views/SkiaContentPage.cs Normal file
View File

@@ -0,0 +1,207 @@
using System;
using System.Collections.Generic;
using System.Linq;
using SkiaSharp;
namespace Microsoft.Maui.Platform;
public class SkiaContentPage : SkiaPage
{
private readonly List<SkiaToolbarItem> _toolbarItems = new List<SkiaToolbarItem>();
public IList<SkiaToolbarItem> ToolbarItems => _toolbarItems;
protected override void DrawNavigationBar(SKCanvas canvas, SKRect bounds)
{
//IL_0000: Unknown result type (might be due to invalid IL or missing references)
//IL_0005: Unknown result type (might be due to invalid IL or missing references)
//IL_0007: Unknown result type (might be due to invalid IL or missing references)
//IL_0011: Unknown result type (might be due to invalid IL or missing references)
//IL_0019: Expected O, but got Unknown
//IL_001a: Unknown result type (might be due to invalid IL or missing references)
//IL_00c5: Unknown result type (might be due to invalid IL or missing references)
//IL_00cb: Unknown result type (might be due to invalid IL or missing references)
//IL_00d0: Unknown result type (might be due to invalid IL or missing references)
//IL_00d6: Unknown result type (might be due to invalid IL or missing references)
//IL_00e0: Unknown result type (might be due to invalid IL or missing references)
//IL_00e7: Unknown result type (might be due to invalid IL or missing references)
//IL_00f9: Expected O, but got Unknown
//IL_0045: Unknown result type (might be due to invalid IL or missing references)
//IL_004b: Expected O, but got Unknown
//IL_011c: Unknown result type (might be due to invalid IL or missing references)
//IL_004c: Unknown result type (might be due to invalid IL or missing references)
//IL_0051: Unknown result type (might be due to invalid IL or missing references)
//IL_0053: Unknown result type (might be due to invalid IL or missing references)
//IL_005d: Unknown result type (might be due to invalid IL or missing references)
//IL_0065: Expected O, but got Unknown
//IL_0067: Unknown result type (might be due to invalid IL or missing references)
SKPaint val = new SKPaint
{
Color = base.TitleBarColor,
Style = (SKPaintStyle)0
};
try
{
canvas.DrawRect(bounds, val);
if (!string.IsNullOrEmpty(base.Title))
{
SKFont val2 = new SKFont(SKTypeface.Default, 20f, 1f, 0f);
try
{
SKPaint val3 = new SKPaint(val2)
{
Color = base.TitleTextColor,
IsAntialias = true
};
try
{
SKRect val4 = default(SKRect);
val3.MeasureText(base.Title, ref val4);
float num = ((SKRect)(ref bounds)).Left + 56f;
float num2 = ((SKRect)(ref bounds)).MidY - ((SKRect)(ref val4)).MidY;
canvas.DrawText(base.Title, num, num2, val3);
}
finally
{
((IDisposable)val3)?.Dispose();
}
}
finally
{
((IDisposable)val2)?.Dispose();
}
}
DrawToolbarItems(canvas, bounds);
SKPaint val5 = new SKPaint
{
Color = new SKColor((byte)0, (byte)0, (byte)0, (byte)30),
Style = (SKPaintStyle)0,
MaskFilter = SKMaskFilter.CreateBlur((SKBlurStyle)0, 2f)
};
try
{
canvas.DrawRect(new SKRect(((SKRect)(ref bounds)).Left, ((SKRect)(ref bounds)).Bottom, ((SKRect)(ref bounds)).Right, ((SKRect)(ref bounds)).Bottom + 4f), val5);
}
finally
{
((IDisposable)val5)?.Dispose();
}
}
finally
{
((IDisposable)val)?.Dispose();
}
}
private void DrawToolbarItems(SKCanvas canvas, SKRect navBarBounds)
{
//IL_0061: Unknown result type (might be due to invalid IL or missing references)
//IL_0090: Unknown result type (might be due to invalid IL or missing references)
//IL_0096: Expected O, but got Unknown
//IL_0097: Unknown result type (might be due to invalid IL or missing references)
//IL_009c: Unknown result type (might be due to invalid IL or missing references)
//IL_009e: Unknown result type (might be due to invalid IL or missing references)
//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
//IL_00b0: Expected O, but got Unknown
//IL_0183: Unknown result type (might be due to invalid IL or missing references)
//IL_01c1: Unknown result type (might be due to invalid IL or missing references)
//IL_010a: Unknown result type (might be due to invalid IL or missing references)
//IL_0151: Unknown result type (might be due to invalid IL or missing references)
//IL_0156: Unknown result type (might be due to invalid IL or missing references)
//IL_015f: Expected O, but got Unknown
//IL_022c: Unknown result type (might be due to invalid IL or missing references)
//IL_0167: Unknown result type (might be due to invalid IL or missing references)
List<SkiaToolbarItem> list = _toolbarItems.Where((SkiaToolbarItem t) => t.Order == SkiaToolbarItemOrder.Primary).ToList();
Console.WriteLine($"[SkiaContentPage] DrawToolbarItems: {list.Count} primary items, navBarBounds={navBarBounds}");
if (list.Count == 0)
{
return;
}
SKFont val = new SKFont(SKTypeface.Default, 14f, 1f, 0f);
try
{
SKPaint val2 = new SKPaint(val)
{
Color = base.TitleTextColor,
IsAntialias = true
};
try
{
float num = ((SKRect)(ref navBarBounds)).Right - 16f;
SKRect val3 = default(SKRect);
foreach (SkiaToolbarItem item in list.AsEnumerable().Reverse())
{
float num3;
if (item.Icon != null)
{
float num2 = 40f;
num3 = num - num2;
item.HitBounds = new SKRect(num3, ((SKRect)(ref navBarBounds)).Top, num, ((SKRect)(ref navBarBounds)).Bottom);
float num4 = num3 + (num2 - 24f) / 2f;
float num5 = ((SKRect)(ref navBarBounds)).MidY - 12f;
((SKRect)(ref val3))._002Ector(num4, num5, num4 + 24f, num5 + 24f);
SKPaint val4 = new SKPaint
{
IsAntialias = true
};
try
{
canvas.DrawBitmap(item.Icon, val3, val4);
}
finally
{
((IDisposable)val4)?.Dispose();
}
}
else
{
SKRect val5 = default(SKRect);
val2.MeasureText(item.Text, ref val5);
float num2 = ((SKRect)(ref val5)).Width + 24f;
num3 = num - num2;
item.HitBounds = new SKRect(num3, ((SKRect)(ref navBarBounds)).Top, num, ((SKRect)(ref navBarBounds)).Bottom);
float num6 = num3 + 12f;
float num7 = ((SKRect)(ref navBarBounds)).MidY - ((SKRect)(ref val5)).MidY;
canvas.DrawText(item.Text, num6, num7, val2);
}
Console.WriteLine($"[SkiaContentPage] Toolbar item '{item.Text}' HitBounds set to {item.HitBounds}");
num = num3 - 8f;
}
}
finally
{
((IDisposable)val2)?.Dispose();
}
}
finally
{
((IDisposable)val)?.Dispose();
}
}
public override void OnPointerPressed(PointerEventArgs e)
{
//IL_0111: Unknown result type (might be due to invalid IL or missing references)
//IL_0116: Unknown result type (might be due to invalid IL or missing references)
Console.WriteLine($"[SkiaContentPage] OnPointerPressed at ({e.X}, {e.Y}), ShowNavigationBar={base.ShowNavigationBar}, NavigationBarHeight={base.NavigationBarHeight}");
Console.WriteLine($"[SkiaContentPage] ToolbarItems count: {_toolbarItems.Count}");
if (base.ShowNavigationBar && e.Y < base.NavigationBarHeight)
{
Console.WriteLine("[SkiaContentPage] In navigation bar area, checking toolbar items");
foreach (SkiaToolbarItem item in _toolbarItems.Where((SkiaToolbarItem t) => t.Order == SkiaToolbarItemOrder.Primary))
{
SKRect hitBounds = item.HitBounds;
bool flag = ((SKRect)(ref hitBounds)).Contains(e.X, e.Y);
Console.WriteLine($"[SkiaContentPage] Checking item '{item.Text}', HitBounds=({((SKRect)(ref hitBounds)).Left},{((SKRect)(ref hitBounds)).Top},{((SKRect)(ref hitBounds)).Right},{((SKRect)(ref hitBounds)).Bottom}), Click=({e.X},{e.Y}), Contains={flag}, Command={item.Command != null}");
if (flag)
{
Console.WriteLine("[SkiaContentPage] Toolbar item clicked: " + item.Text);
item.Command?.Execute(null);
return;
}
}
Console.WriteLine("[SkiaContentPage] No toolbar item hit");
}
base.OnPointerPressed(e);
}
}

View File

@@ -1,257 +1,242 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System;
using Microsoft.Maui.Controls;
using SkiaSharp;
namespace Microsoft.Maui.Platform;
/// <summary>
/// Presents content within a ControlTemplate.
/// This control acts as a placeholder that gets replaced with the actual content
/// when the template is applied to a control.
/// </summary>
public class SkiaContentPresenter : SkiaView
{
#region BindableProperties
public static readonly BindableProperty ContentProperty = BindableProperty.Create("Content", typeof(SkiaView), typeof(SkiaContentPresenter), (object)null, (BindingMode)2, (ValidateValueDelegate)null, (BindingPropertyChangedDelegate)delegate(BindableObject b, object o, object n)
{
((SkiaContentPresenter)(object)b).OnContentChanged((SkiaView)o, (SkiaView)n);
}, (BindingPropertyChangingDelegate)null, (CoerceValueDelegate)null, (CreateDefaultValueDelegate)null);
public static readonly BindableProperty ContentProperty =
BindableProperty.Create(nameof(Content), typeof(SkiaView), typeof(SkiaContentPresenter), null,
propertyChanged: (b, o, n) => ((SkiaContentPresenter)b).OnContentChanged((SkiaView?)o, (SkiaView?)n));
public static readonly BindableProperty HorizontalContentAlignmentProperty = BindableProperty.Create("HorizontalContentAlignment", typeof(LayoutAlignment), typeof(SkiaContentPresenter), (object)LayoutAlignment.Fill, (BindingMode)2, (ValidateValueDelegate)null, (BindingPropertyChangedDelegate)delegate(BindableObject b, object o, object n)
{
((SkiaContentPresenter)(object)b).InvalidateMeasure();
}, (BindingPropertyChangingDelegate)null, (CoerceValueDelegate)null, (CreateDefaultValueDelegate)null);
public static readonly BindableProperty HorizontalContentAlignmentProperty =
BindableProperty.Create(nameof(HorizontalContentAlignment), typeof(LayoutAlignment), typeof(SkiaContentPresenter), LayoutAlignment.Fill,
propertyChanged: (b, o, n) => ((SkiaContentPresenter)b).InvalidateMeasure());
public static readonly BindableProperty VerticalContentAlignmentProperty = BindableProperty.Create("VerticalContentAlignment", typeof(LayoutAlignment), typeof(SkiaContentPresenter), (object)LayoutAlignment.Fill, (BindingMode)2, (ValidateValueDelegate)null, (BindingPropertyChangedDelegate)delegate(BindableObject b, object o, object n)
{
((SkiaContentPresenter)(object)b).InvalidateMeasure();
}, (BindingPropertyChangingDelegate)null, (CoerceValueDelegate)null, (CreateDefaultValueDelegate)null);
public static readonly BindableProperty VerticalContentAlignmentProperty =
BindableProperty.Create(nameof(VerticalContentAlignment), typeof(LayoutAlignment), typeof(SkiaContentPresenter), LayoutAlignment.Fill,
propertyChanged: (b, o, n) => ((SkiaContentPresenter)b).InvalidateMeasure());
public static readonly BindableProperty PaddingProperty = BindableProperty.Create("Padding", typeof(SKRect), typeof(SkiaContentPresenter), (object)SKRect.Empty, (BindingMode)2, (ValidateValueDelegate)null, (BindingPropertyChangedDelegate)delegate(BindableObject b, object o, object n)
{
((SkiaContentPresenter)(object)b).InvalidateMeasure();
}, (BindingPropertyChangingDelegate)null, (CoerceValueDelegate)null, (CreateDefaultValueDelegate)null);
public static readonly BindableProperty PaddingProperty =
BindableProperty.Create(nameof(Padding), typeof(SKRect), typeof(SkiaContentPresenter), SKRect.Empty,
propertyChanged: (b, o, n) => ((SkiaContentPresenter)b).InvalidateMeasure());
public SkiaView? Content
{
get
{
return (SkiaView)((BindableObject)this).GetValue(ContentProperty);
}
set
{
((BindableObject)this).SetValue(ContentProperty, (object)value);
}
}
#endregion
public LayoutAlignment HorizontalContentAlignment
{
get
{
return (LayoutAlignment)((BindableObject)this).GetValue(HorizontalContentAlignmentProperty);
}
set
{
((BindableObject)this).SetValue(HorizontalContentAlignmentProperty, (object)value);
}
}
#region Properties
public LayoutAlignment VerticalContentAlignment
{
get
{
return (LayoutAlignment)((BindableObject)this).GetValue(VerticalContentAlignmentProperty);
}
set
{
((BindableObject)this).SetValue(VerticalContentAlignmentProperty, (object)value);
}
}
/// <summary>
/// Gets or sets the content to present.
/// </summary>
public SkiaView? Content
{
get => (SkiaView?)GetValue(ContentProperty);
set => SetValue(ContentProperty, value);
}
public SKRect Padding
{
get
{
//IL_000b: Unknown result type (might be due to invalid IL or missing references)
return (SKRect)((BindableObject)this).GetValue(PaddingProperty);
}
set
{
//IL_0006: Unknown result type (might be due to invalid IL or missing references)
((BindableObject)this).SetValue(PaddingProperty, (object)value);
}
}
/// <summary>
/// Gets or sets the horizontal alignment of the content.
/// </summary>
public LayoutAlignment HorizontalContentAlignment
{
get => (LayoutAlignment)GetValue(HorizontalContentAlignmentProperty);
set => SetValue(HorizontalContentAlignmentProperty, value);
}
private void OnContentChanged(SkiaView? oldContent, SkiaView? newContent)
{
if (oldContent != null)
{
oldContent.Parent = null;
}
if (newContent != null)
{
newContent.Parent = this;
if (((BindableObject)this).BindingContext != null)
{
BindableObject.SetInheritedBindingContext((BindableObject)(object)newContent, ((BindableObject)this).BindingContext);
}
}
InvalidateMeasure();
}
/// <summary>
/// Gets or sets the vertical alignment of the content.
/// </summary>
public LayoutAlignment VerticalContentAlignment
{
get => (LayoutAlignment)GetValue(VerticalContentAlignmentProperty);
set => SetValue(VerticalContentAlignmentProperty, value);
}
protected override void OnBindingContextChanged()
{
base.OnBindingContextChanged();
if (Content != null)
{
BindableObject.SetInheritedBindingContext((BindableObject)(object)Content, ((BindableObject)this).BindingContext);
}
}
/// <summary>
/// Gets or sets the padding around the content.
/// </summary>
public SKRect Padding
{
get => (SKRect)GetValue(PaddingProperty);
set => SetValue(PaddingProperty, value);
}
protected override void OnDraw(SKCanvas canvas, SKRect bounds)
{
//IL_0001: Unknown result type (might be due to invalid IL or missing references)
//IL_0006: Unknown result type (might be due to invalid IL or missing references)
//IL_0012: Unknown result type (might be due to invalid IL or missing references)
//IL_0017: Unknown result type (might be due to invalid IL or missing references)
//IL_0019: Unknown result type (might be due to invalid IL or missing references)
//IL_0023: Unknown result type (might be due to invalid IL or missing references)
//IL_002b: Expected O, but got Unknown
//IL_002c: Unknown result type (might be due to invalid IL or missing references)
if (base.BackgroundColor != SKColors.Transparent)
{
SKPaint val = new SKPaint
{
Color = base.BackgroundColor,
Style = (SKPaintStyle)0
};
try
{
canvas.DrawRect(bounds, val);
}
finally
{
((IDisposable)val)?.Dispose();
}
}
Content?.Draw(canvas);
}
#endregion
protected override SKSize MeasureOverride(SKSize availableSize)
{
//IL_0001: Unknown result type (might be due to invalid IL or missing references)
//IL_0006: Unknown result type (might be due to invalid IL or missing references)
//IL_002d: Unknown result type (might be due to invalid IL or missing references)
//IL_009d: Unknown result type (might be due to invalid IL or missing references)
//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
//IL_00d6: Unknown result type (might be due to invalid IL or missing references)
SKRect padding = Padding;
if (Content == null)
{
return new SKSize(((SKRect)(ref padding)).Left + ((SKRect)(ref padding)).Right, ((SKRect)(ref padding)).Top + ((SKRect)(ref padding)).Bottom);
}
float num = ((HorizontalContentAlignment == LayoutAlignment.Fill) ? Math.Max(0f, ((SKSize)(ref availableSize)).Width - ((SKRect)(ref padding)).Left - ((SKRect)(ref padding)).Right) : float.PositiveInfinity);
float num2 = ((VerticalContentAlignment == LayoutAlignment.Fill) ? Math.Max(0f, ((SKSize)(ref availableSize)).Height - ((SKRect)(ref padding)).Top - ((SKRect)(ref padding)).Bottom) : float.PositiveInfinity);
SKSize val = Content.Measure(new SKSize(num, num2));
return new SKSize(((SKSize)(ref val)).Width + ((SKRect)(ref padding)).Left + ((SKRect)(ref padding)).Right, ((SKSize)(ref val)).Height + ((SKRect)(ref padding)).Top + ((SKRect)(ref padding)).Bottom);
}
private void OnContentChanged(SkiaView? oldContent, SkiaView? newContent)
{
if (oldContent != null)
{
oldContent.Parent = null;
}
protected override SKRect ArrangeOverride(SKRect bounds)
{
//IL_007b: Unknown result type (might be due to invalid IL or missing references)
//IL_0009: Unknown result type (might be due to invalid IL or missing references)
//IL_000e: Unknown result type (might be due to invalid IL or missing references)
//IL_004b: Unknown result type (might be due to invalid IL or missing references)
//IL_0056: Unknown result type (might be due to invalid IL or missing references)
//IL_005b: Unknown result type (might be due to invalid IL or missing references)
//IL_005c: Unknown result type (might be due to invalid IL or missing references)
//IL_0069: Unknown result type (might be due to invalid IL or missing references)
//IL_006e: Unknown result type (might be due to invalid IL or missing references)
//IL_0075: Unknown result type (might be due to invalid IL or missing references)
if (Content != null)
{
SKRect padding = Padding;
SKRect availableBounds = new SKRect(((SKRect)(ref bounds)).Left + ((SKRect)(ref padding)).Left, ((SKRect)(ref bounds)).Top + ((SKRect)(ref padding)).Top, ((SKRect)(ref bounds)).Right - ((SKRect)(ref padding)).Right, ((SKRect)(ref bounds)).Bottom - ((SKRect)(ref padding)).Bottom);
SKSize desiredSize = Content.DesiredSize;
SKRect bounds2 = ApplyAlignment(availableBounds, desiredSize, HorizontalContentAlignment, VerticalContentAlignment);
Content.Arrange(bounds2);
}
return bounds;
}
if (newContent != null)
{
newContent.Parent = this;
private static SKRect ApplyAlignment(SKRect availableBounds, SKSize contentSize, LayoutAlignment horizontal, LayoutAlignment vertical)
{
//IL_009c: Unknown result type (might be due to invalid IL or missing references)
float num = ((SKRect)(ref availableBounds)).Left;
float num2 = ((SKRect)(ref availableBounds)).Top;
float num3 = ((horizontal == LayoutAlignment.Fill) ? ((SKRect)(ref availableBounds)).Width : ((SKSize)(ref contentSize)).Width);
float num4 = ((vertical == LayoutAlignment.Fill) ? ((SKRect)(ref availableBounds)).Height : ((SKSize)(ref contentSize)).Height);
switch (horizontal)
{
case LayoutAlignment.Center:
num = ((SKRect)(ref availableBounds)).Left + (((SKRect)(ref availableBounds)).Width - num3) / 2f;
break;
case LayoutAlignment.End:
num = ((SKRect)(ref availableBounds)).Right - num3;
break;
}
switch (vertical)
{
case LayoutAlignment.Center:
num2 = ((SKRect)(ref availableBounds)).Top + (((SKRect)(ref availableBounds)).Height - num4) / 2f;
break;
case LayoutAlignment.End:
num2 = ((SKRect)(ref availableBounds)).Bottom - num4;
break;
}
return new SKRect(num, num2, num + num3, num2 + num4);
}
// Propagate binding context to new content
if (BindingContext != null)
{
SetInheritedBindingContext(newContent, BindingContext);
}
}
public override SkiaView? HitTest(float x, float y)
{
//IL_0009: Unknown result type (might be due to invalid IL or missing references)
//IL_000e: Unknown result type (might be due to invalid IL or missing references)
if (base.IsVisible)
{
SKRect bounds = base.Bounds;
if (((SKRect)(ref bounds)).Contains(x, y))
{
if (Content != null)
{
SkiaView skiaView = Content.HitTest(x, y);
if (skiaView != null)
{
return skiaView;
}
}
return this;
}
}
return null;
}
InvalidateMeasure();
}
public override void OnPointerPressed(PointerEventArgs e)
{
Content?.OnPointerPressed(e);
}
/// <summary>
/// Called when binding context changes. Propagates to content.
/// </summary>
protected override void OnBindingContextChanged()
{
base.OnBindingContextChanged();
public override void OnPointerMoved(PointerEventArgs e)
{
Content?.OnPointerMoved(e);
}
// Propagate binding context to content
if (Content != null)
{
SetInheritedBindingContext(Content, BindingContext);
}
}
protected override void OnDraw(SKCanvas canvas, SKRect bounds)
{
// Draw background if set
if (BackgroundColor != SKColors.Transparent)
{
using var bgPaint = new SKPaint
{
Color = BackgroundColor,
Style = SKPaintStyle.Fill
};
canvas.DrawRect(bounds, bgPaint);
}
// Draw content
Content?.Draw(canvas);
}
protected override SKSize MeasureOverride(SKSize availableSize)
{
var padding = Padding;
if (Content == null)
return new SKSize(padding.Left + padding.Right, padding.Top + padding.Bottom);
// 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 - padding.Left - padding.Right)
: float.PositiveInfinity;
var measureHeight = VerticalContentAlignment == LayoutAlignment.Fill
? Math.Max(0, availableSize.Height - padding.Top - padding.Bottom)
: float.PositiveInfinity;
var contentSize = Content.Measure(new SKSize(measureWidth, measureHeight));
return new SKSize(
contentSize.Width + padding.Left + padding.Right,
contentSize.Height + padding.Top + padding.Bottom);
}
protected override SKRect ArrangeOverride(SKRect bounds)
{
if (Content != null)
{
var padding = Padding;
var contentBounds = new SKRect(
bounds.Left + padding.Left,
bounds.Top + padding.Top,
bounds.Right - padding.Right,
bounds.Bottom - padding.Bottom);
// Apply alignment
var contentSize = Content.DesiredSize;
var arrangedBounds = ApplyAlignment(contentBounds, contentSize, HorizontalContentAlignment, VerticalContentAlignment);
Content.Arrange(arrangedBounds);
}
return bounds;
}
private static SKRect ApplyAlignment(SKRect availableBounds, SKSize 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;
// Horizontal alignment
switch (horizontal)
{
case LayoutAlignment.Center:
x = availableBounds.Left + (availableBounds.Width - width) / 2;
break;
case LayoutAlignment.End:
x = availableBounds.Right - width;
break;
}
// Vertical alignment
switch (vertical)
{
case LayoutAlignment.Center:
y = availableBounds.Top + (availableBounds.Height - height) / 2;
break;
case LayoutAlignment.End:
y = availableBounds.Bottom - height;
break;
}
return new SKRect(x, y, x + width, y + height);
}
public override SkiaView? HitTest(float x, float y)
{
if (!IsVisible || !Bounds.Contains(x, y))
return null;
// Check content first
if (Content != null)
{
var hit = Content.HitTest(x, y);
if (hit != null)
return hit;
}
return this;
}
public override void OnPointerPressed(PointerEventArgs e)
{
Content?.OnPointerPressed(e);
}
public override void OnPointerMoved(PointerEventArgs e)
{
Content?.OnPointerMoved(e);
}
public override void OnPointerReleased(PointerEventArgs e)
{
Content?.OnPointerReleased(e);
}
}
/// <summary>
/// Layout alignment options.
/// </summary>
public enum LayoutAlignment
{
/// <summary>
/// Fill the available space.
/// </summary>
Fill,
/// <summary>
/// Align to the start (left or top).
/// </summary>
Start,
/// <summary>
/// Align to the center.
/// </summary>
Center,
/// <summary>
/// Align to the end (right or bottom).
/// </summary>
End
public override void OnPointerReleased(PointerEventArgs e)
{
Content?.OnPointerReleased(e);
}
}

312
Views/SkiaContextMenu.cs Normal file
View File

@@ -0,0 +1,312 @@
using System;
using System.Collections.Generic;
using SkiaSharp;
namespace Microsoft.Maui.Platform;
public class SkiaContextMenu : SkiaView
{
private readonly List<ContextMenuItem> _items;
private readonly float _x;
private readonly float _y;
private int _hoveredIndex = -1;
private SKRect[] _itemBounds = Array.Empty<SKRect>();
private static readonly SKColor MenuBackground = new SKColor(byte.MaxValue, byte.MaxValue, byte.MaxValue);
private static readonly SKColor MenuBackgroundDark = new SKColor((byte)48, (byte)48, (byte)48);
private static readonly SKColor ItemHoverBackground = new SKColor((byte)227, (byte)242, (byte)253);
private static readonly SKColor ItemHoverBackgroundDark = new SKColor((byte)80, (byte)80, (byte)80);
private static readonly SKColor ItemTextColor = new SKColor((byte)33, (byte)33, (byte)33);
private static readonly SKColor ItemTextColorDark = new SKColor((byte)224, (byte)224, (byte)224);
private static readonly SKColor DisabledTextColor = new SKColor((byte)158, (byte)158, (byte)158);
private static readonly SKColor SeparatorColor = new SKColor((byte)224, (byte)224, (byte)224);
private static readonly SKColor ShadowColor = new SKColor((byte)0, (byte)0, (byte)0, (byte)40);
private const float MenuPadding = 4f;
private const float ItemHeight = 32f;
private const float ItemPaddingH = 16f;
private const float SeparatorHeight = 9f;
private const float CornerRadius = 4f;
private const float MinWidth = 120f;
private bool _isDarkTheme;
public SkiaContextMenu(float x, float y, List<ContextMenuItem> items, bool isDarkTheme = false)
{
_x = x;
_y = y;
_items = items;
_isDarkTheme = isDarkTheme;
base.IsFocusable = true;
}
public override void Draw(SKCanvas canvas)
{
//IL_0070: Unknown result type (might be due to invalid IL or missing references)
//IL_0075: Unknown result type (might be due to invalid IL or missing references)
//IL_0076: Unknown result type (might be due to invalid IL or missing references)
//IL_0080: Unknown result type (might be due to invalid IL or missing references)
//IL_0093: Expected O, but got Unknown
//IL_00c1: Unknown result type (might be due to invalid IL or missing references)
//IL_00c6: Unknown result type (might be due to invalid IL or missing references)
//IL_00d6: Unknown result type (might be due to invalid IL or missing references)
//IL_00cf: Unknown result type (might be due to invalid IL or missing references)
//IL_00e0: Unknown result type (might be due to invalid IL or missing references)
//IL_00e9: Expected O, but got Unknown
//IL_00ea: Unknown result type (might be due to invalid IL or missing references)
//IL_00fd: Unknown result type (might be due to invalid IL or missing references)
//IL_0102: Unknown result type (might be due to invalid IL or missing references)
//IL_0103: Unknown result type (might be due to invalid IL or missing references)
//IL_010d: Unknown result type (might be due to invalid IL or missing references)
//IL_0114: Unknown result type (might be due to invalid IL or missing references)
//IL_011f: Unknown result type (might be due to invalid IL or missing references)
//IL_0128: Expected O, but got Unknown
//IL_0129: Unknown result type (might be due to invalid IL or missing references)
//IL_0222: Unknown result type (might be due to invalid IL or missing references)
//IL_0224: Unknown result type (might be due to invalid IL or missing references)
//IL_0185: Unknown result type (might be due to invalid IL or missing references)
//IL_018a: Unknown result type (might be due to invalid IL or missing references)
//IL_018b: Unknown result type (might be due to invalid IL or missing references)
//IL_0195: Unknown result type (might be due to invalid IL or missing references)
//IL_01a2: Expected O, but got Unknown
//IL_0286: Unknown result type (might be due to invalid IL or missing references)
//IL_028b: Unknown result type (might be due to invalid IL or missing references)
//IL_01d4: Unknown result type (might be due to invalid IL or missing references)
//IL_01d9: Unknown result type (might be due to invalid IL or missing references)
//IL_0295: Unknown result type (might be due to invalid IL or missing references)
//IL_023c: Unknown result type (might be due to invalid IL or missing references)
//IL_0241: Unknown result type (might be due to invalid IL or missing references)
//IL_02ab: Unknown result type (might be due to invalid IL or missing references)
//IL_02a4: Unknown result type (might be due to invalid IL or missing references)
//IL_02b5: Unknown result type (might be due to invalid IL or missing references)
//IL_02c0: Unknown result type (might be due to invalid IL or missing references)
//IL_02c7: Unknown result type (might be due to invalid IL or missing references)
//IL_02d4: Expected O, but got Unknown
//IL_0251: Unknown result type (might be due to invalid IL or missing references)
//IL_024a: Unknown result type (might be due to invalid IL or missing references)
//IL_025b: Unknown result type (might be due to invalid IL or missing references)
//IL_0264: Expected O, but got Unknown
//IL_0265: Unknown result type (might be due to invalid IL or missing references)
float num = CalculateMenuWidth();
float num2 = CalculateMenuHeight();
float num3 = _x;
float num4 = _y;
SKRectI val = default(SKRectI);
canvas.GetDeviceClipBounds(ref val);
if (num3 + num > (float)((SKRectI)(ref val)).Right)
{
num3 = (float)((SKRectI)(ref val)).Right - num - 4f;
}
if (num4 + num2 > (float)((SKRectI)(ref val)).Bottom)
{
num4 = (float)((SKRectI)(ref val)).Bottom - num2 - 4f;
}
SKRect val2 = default(SKRect);
((SKRect)(ref val2))._002Ector(num3, num4, num3 + num, num4 + num2);
SKPaint val3 = new SKPaint
{
Color = ShadowColor,
MaskFilter = SKMaskFilter.CreateBlur((SKBlurStyle)0, 4f)
};
try
{
canvas.DrawRoundRect(((SKRect)(ref val2)).Left + 2f, ((SKRect)(ref val2)).Top + 2f, num, num2, 4f, 4f, val3);
SKPaint val4 = new SKPaint
{
Color = (_isDarkTheme ? MenuBackgroundDark : MenuBackground),
IsAntialias = true
};
try
{
canvas.DrawRoundRect(val2, 4f, 4f, val4);
SKPaint val5 = new SKPaint
{
Color = SeparatorColor,
Style = (SKPaintStyle)1,
StrokeWidth = 1f,
IsAntialias = true
};
try
{
canvas.DrawRoundRect(val2, 4f, 4f, val5);
_itemBounds = (SKRect[])(object)new SKRect[_items.Count];
float num5 = num4 + 4f;
SKRect val7 = default(SKRect);
for (int i = 0; i < _items.Count; i++)
{
ContextMenuItem contextMenuItem = _items[i];
if (contextMenuItem.IsSeparator)
{
float num6 = num5 + 4.5f;
SKPaint val6 = new SKPaint
{
Color = SeparatorColor,
StrokeWidth = 1f
};
try
{
canvas.DrawLine(num3 + 8f, num6, num3 + num - 8f, num6, val6);
_itemBounds[i] = new SKRect(num3, num5, num3 + num, num5 + 9f);
num5 += 9f;
}
finally
{
((IDisposable)val6)?.Dispose();
}
continue;
}
((SKRect)(ref val7))._002Ector(num3 + 4f, num5, num3 + num - 4f, num5 + 32f);
_itemBounds[i] = val7;
if (i == _hoveredIndex && contextMenuItem.IsEnabled)
{
SKPaint val8 = new SKPaint
{
Color = (_isDarkTheme ? ItemHoverBackgroundDark : ItemHoverBackground),
IsAntialias = true
};
try
{
canvas.DrawRoundRect(val7, 4f, 4f, val8);
}
finally
{
((IDisposable)val8)?.Dispose();
}
}
SKPaint val9 = new SKPaint
{
Color = ((!contextMenuItem.IsEnabled) ? DisabledTextColor : (_isDarkTheme ? ItemTextColorDark : ItemTextColor)),
TextSize = 14f,
IsAntialias = true,
Typeface = SKTypeface.Default
};
try
{
float num7 = ((SKRect)(ref val7)).MidY + val9.TextSize / 3f;
canvas.DrawText(contextMenuItem.Text, ((SKRect)(ref val7)).Left + 16f, num7, val9);
num5 += 32f;
}
finally
{
((IDisposable)val9)?.Dispose();
}
}
}
finally
{
((IDisposable)val5)?.Dispose();
}
}
finally
{
((IDisposable)val4)?.Dispose();
}
}
finally
{
((IDisposable)val3)?.Dispose();
}
}
private float CalculateMenuWidth()
{
//IL_0006: Unknown result type (might be due to invalid IL or missing references)
//IL_000b: Unknown result type (might be due to invalid IL or missing references)
//IL_0016: Unknown result type (might be due to invalid IL or missing references)
//IL_0022: Expected O, but got Unknown
float num = 120f;
SKPaint val = new SKPaint
{
TextSize = 14f,
Typeface = SKTypeface.Default
};
try
{
foreach (ContextMenuItem item in _items)
{
if (!item.IsSeparator)
{
float val2 = val.MeasureText(item.Text) + 32f;
num = Math.Max(num, val2);
}
}
return num + 8f;
}
finally
{
((IDisposable)val)?.Dispose();
}
}
private float CalculateMenuHeight()
{
float num = 8f;
foreach (ContextMenuItem item in _items)
{
num += (item.IsSeparator ? 9f : 32f);
}
return num;
}
public override void OnPointerMoved(PointerEventArgs e)
{
int hoveredIndex = _hoveredIndex;
_hoveredIndex = -1;
for (int i = 0; i < _itemBounds.Length; i++)
{
if (((SKRect)(ref _itemBounds[i])).Contains(e.X, e.Y) && !_items[i].IsSeparator)
{
_hoveredIndex = i;
break;
}
}
if (hoveredIndex != _hoveredIndex)
{
Invalidate();
}
}
public override void OnPointerPressed(PointerEventArgs e)
{
for (int i = 0; i < _itemBounds.Length; i++)
{
if (((SKRect)(ref _itemBounds[i])).Contains(e.X, e.Y))
{
ContextMenuItem contextMenuItem = _items[i];
if (contextMenuItem.IsEnabled && !contextMenuItem.IsSeparator && contextMenuItem.Action != null)
{
LinuxDialogService.HideContextMenu();
contextMenuItem.Action();
return;
}
}
}
LinuxDialogService.HideContextMenu();
}
public override void OnKeyDown(KeyEventArgs e)
{
if (e.Key == Key.Escape)
{
LinuxDialogService.HideContextMenu();
e.Handled = true;
}
}
}

View File

File diff suppressed because it is too large Load Diff

View File

File diff suppressed because it is too large Load Diff

View File

File diff suppressed because it is too large Load Diff

346
Views/SkiaFlexLayout.cs Normal file
View File

@@ -0,0 +1,346 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Maui.Controls;
using SkiaSharp;
namespace Microsoft.Maui.Platform;
public class SkiaFlexLayout : SkiaLayoutView
{
public static readonly BindableProperty DirectionProperty = BindableProperty.Create("Direction", typeof(FlexDirection), typeof(SkiaFlexLayout), (object)FlexDirection.Row, (BindingMode)2, (ValidateValueDelegate)null, (BindingPropertyChangedDelegate)delegate(BindableObject b, object o, object n)
{
((SkiaFlexLayout)(object)b).InvalidateMeasure();
}, (BindingPropertyChangingDelegate)null, (CoerceValueDelegate)null, (CreateDefaultValueDelegate)null);
public static readonly BindableProperty WrapProperty = BindableProperty.Create("Wrap", typeof(FlexWrap), typeof(SkiaFlexLayout), (object)FlexWrap.NoWrap, (BindingMode)2, (ValidateValueDelegate)null, (BindingPropertyChangedDelegate)delegate(BindableObject b, object o, object n)
{
((SkiaFlexLayout)(object)b).InvalidateMeasure();
}, (BindingPropertyChangingDelegate)null, (CoerceValueDelegate)null, (CreateDefaultValueDelegate)null);
public static readonly BindableProperty JustifyContentProperty = BindableProperty.Create("JustifyContent", typeof(FlexJustify), typeof(SkiaFlexLayout), (object)FlexJustify.Start, (BindingMode)2, (ValidateValueDelegate)null, (BindingPropertyChangedDelegate)delegate(BindableObject b, object o, object n)
{
((SkiaFlexLayout)(object)b).InvalidateMeasure();
}, (BindingPropertyChangingDelegate)null, (CoerceValueDelegate)null, (CreateDefaultValueDelegate)null);
public static readonly BindableProperty AlignItemsProperty = BindableProperty.Create("AlignItems", typeof(FlexAlignItems), typeof(SkiaFlexLayout), (object)FlexAlignItems.Stretch, (BindingMode)2, (ValidateValueDelegate)null, (BindingPropertyChangedDelegate)delegate(BindableObject b, object o, object n)
{
((SkiaFlexLayout)(object)b).InvalidateMeasure();
}, (BindingPropertyChangingDelegate)null, (CoerceValueDelegate)null, (CreateDefaultValueDelegate)null);
public static readonly BindableProperty AlignContentProperty = BindableProperty.Create("AlignContent", typeof(FlexAlignContent), typeof(SkiaFlexLayout), (object)FlexAlignContent.Stretch, (BindingMode)2, (ValidateValueDelegate)null, (BindingPropertyChangedDelegate)delegate(BindableObject b, object o, object n)
{
((SkiaFlexLayout)(object)b).InvalidateMeasure();
}, (BindingPropertyChangingDelegate)null, (CoerceValueDelegate)null, (CreateDefaultValueDelegate)null);
public static readonly BindableProperty OrderProperty = BindableProperty.CreateAttached("Order", typeof(int), typeof(SkiaFlexLayout), (object)0, (BindingMode)2, (ValidateValueDelegate)null, (BindingPropertyChangedDelegate)null, (BindingPropertyChangingDelegate)null, (CoerceValueDelegate)null, (CreateDefaultValueDelegate)null);
public static readonly BindableProperty GrowProperty = BindableProperty.CreateAttached("Grow", typeof(float), typeof(SkiaFlexLayout), (object)0f, (BindingMode)2, (ValidateValueDelegate)null, (BindingPropertyChangedDelegate)null, (BindingPropertyChangingDelegate)null, (CoerceValueDelegate)null, (CreateDefaultValueDelegate)null);
public static readonly BindableProperty ShrinkProperty = BindableProperty.CreateAttached("Shrink", typeof(float), typeof(SkiaFlexLayout), (object)1f, (BindingMode)2, (ValidateValueDelegate)null, (BindingPropertyChangedDelegate)null, (BindingPropertyChangingDelegate)null, (CoerceValueDelegate)null, (CreateDefaultValueDelegate)null);
public static readonly BindableProperty BasisProperty = BindableProperty.CreateAttached("Basis", typeof(FlexBasis), typeof(SkiaFlexLayout), (object)FlexBasis.Auto, (BindingMode)2, (ValidateValueDelegate)null, (BindingPropertyChangedDelegate)null, (BindingPropertyChangingDelegate)null, (CoerceValueDelegate)null, (CreateDefaultValueDelegate)null);
public static readonly BindableProperty AlignSelfProperty = BindableProperty.CreateAttached("AlignSelf", typeof(FlexAlignSelf), typeof(SkiaFlexLayout), (object)FlexAlignSelf.Auto, (BindingMode)2, (ValidateValueDelegate)null, (BindingPropertyChangedDelegate)null, (BindingPropertyChangingDelegate)null, (CoerceValueDelegate)null, (CreateDefaultValueDelegate)null);
public FlexDirection Direction
{
get
{
return (FlexDirection)((BindableObject)this).GetValue(DirectionProperty);
}
set
{
((BindableObject)this).SetValue(DirectionProperty, (object)value);
}
}
public FlexWrap Wrap
{
get
{
return (FlexWrap)((BindableObject)this).GetValue(WrapProperty);
}
set
{
((BindableObject)this).SetValue(WrapProperty, (object)value);
}
}
public FlexJustify JustifyContent
{
get
{
return (FlexJustify)((BindableObject)this).GetValue(JustifyContentProperty);
}
set
{
((BindableObject)this).SetValue(JustifyContentProperty, (object)value);
}
}
public FlexAlignItems AlignItems
{
get
{
return (FlexAlignItems)((BindableObject)this).GetValue(AlignItemsProperty);
}
set
{
((BindableObject)this).SetValue(AlignItemsProperty, (object)value);
}
}
public FlexAlignContent AlignContent
{
get
{
return (FlexAlignContent)((BindableObject)this).GetValue(AlignContentProperty);
}
set
{
((BindableObject)this).SetValue(AlignContentProperty, (object)value);
}
}
public static int GetOrder(SkiaView view)
{
return (int)((BindableObject)view).GetValue(OrderProperty);
}
public static void SetOrder(SkiaView view, int value)
{
((BindableObject)view).SetValue(OrderProperty, (object)value);
}
public static float GetGrow(SkiaView view)
{
return (float)((BindableObject)view).GetValue(GrowProperty);
}
public static void SetGrow(SkiaView view, float value)
{
((BindableObject)view).SetValue(GrowProperty, (object)value);
}
public static float GetShrink(SkiaView view)
{
return (float)((BindableObject)view).GetValue(ShrinkProperty);
}
public static void SetShrink(SkiaView view, float value)
{
((BindableObject)view).SetValue(ShrinkProperty, (object)value);
}
public static FlexBasis GetBasis(SkiaView view)
{
return (FlexBasis)((BindableObject)view).GetValue(BasisProperty);
}
public static void SetBasis(SkiaView view, FlexBasis value)
{
((BindableObject)view).SetValue(BasisProperty, (object)value);
}
public static FlexAlignSelf GetAlignSelf(SkiaView view)
{
return (FlexAlignSelf)((BindableObject)view).GetValue(AlignSelfProperty);
}
public static void SetAlignSelf(SkiaView view, FlexAlignSelf value)
{
((BindableObject)view).SetValue(AlignSelfProperty, (object)value);
}
protected override SKSize MeasureOverride(SKSize availableSize)
{
//IL_0042: Unknown result type (might be due to invalid IL or missing references)
//IL_0043: Unknown result type (might be due to invalid IL or missing references)
//IL_0048: Unknown result type (might be due to invalid IL or missing references)
//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
//IL_0098: Unknown result type (might be due to invalid IL or missing references)
bool flag = Direction == FlexDirection.Row || Direction == FlexDirection.RowReverse;
float num = 0f;
float num2 = 0f;
foreach (SkiaView child in base.Children)
{
if (child.IsVisible)
{
SKSize val = child.Measure(availableSize);
if (flag)
{
num += ((SKSize)(ref val)).Width;
num2 = Math.Max(num2, ((SKSize)(ref val)).Height);
}
else
{
num += ((SKSize)(ref val)).Height;
num2 = Math.Max(num2, ((SKSize)(ref val)).Width);
}
}
}
if (!flag)
{
return new SKSize(num2, num);
}
return new SKSize(num, num2);
}
protected override SKRect ArrangeOverride(SKRect bounds)
{
//IL_000d: Unknown result type (might be due to invalid IL or missing references)
//IL_0096: Unknown result type (might be due to invalid IL or missing references)
//IL_0127: Unknown result type (might be due to invalid IL or missing references)
//IL_012c: Unknown result type (might be due to invalid IL or missing references)
//IL_0131: Unknown result type (might be due to invalid IL or missing references)
//IL_0163: Unknown result type (might be due to invalid IL or missing references)
//IL_0168: Unknown result type (might be due to invalid IL or missing references)
//IL_014c: Unknown result type (might be due to invalid IL or missing references)
//IL_0151: Unknown result type (might be due to invalid IL or missing references)
//IL_0173: Unknown result type (might be due to invalid IL or missing references)
//IL_016d: Unknown result type (might be due to invalid IL or missing references)
//IL_01f0: Unknown result type (might be due to invalid IL or missing references)
//IL_01f5: Unknown result type (might be due to invalid IL or missing references)
//IL_04b4: Unknown result type (might be due to invalid IL or missing references)
//IL_0489: Unknown result type (might be due to invalid IL or missing references)
if (base.Children.Count == 0)
{
return bounds;
}
bool flag = Direction == FlexDirection.Row || Direction == FlexDirection.RowReverse;
bool flag2 = Direction == FlexDirection.RowReverse || Direction == FlexDirection.ColumnReverse;
List<SkiaView> list = (from c in base.Children
where c.IsVisible
orderby GetOrder(c)
select c).ToList();
if (list.Count == 0)
{
return bounds;
}
float num = (flag ? ((SKRect)(ref bounds)).Width : ((SKRect)(ref bounds)).Height);
float num2 = (flag ? ((SKRect)(ref bounds)).Height : ((SKRect)(ref bounds)).Width);
List<(SkiaView, SKSize, float, float)> list2 = new List<(SkiaView, SKSize, float, float)>();
float num3 = 0f;
float num4 = 0f;
float num5 = 0f;
foreach (SkiaView item10 in list)
{
FlexBasis basis = GetBasis(item10);
float grow = GetGrow(item10);
float shrink = GetShrink(item10);
SKSize item;
if (basis.IsAuto)
{
item = item10.Measure(new SKSize(((SKRect)(ref bounds)).Width, ((SKRect)(ref bounds)).Height));
}
else
{
float length = basis.Length;
item = (flag ? item10.Measure(new SKSize(length, ((SKRect)(ref bounds)).Height)) : item10.Measure(new SKSize(((SKRect)(ref bounds)).Width, length)));
}
list2.Add((item10, item, grow, shrink));
num3 += (flag ? ((SKSize)(ref item)).Width : ((SKSize)(ref item)).Height);
num4 += grow;
num5 += shrink;
}
float num6 = num - num3;
List<(SkiaView, float, float)> list3 = new List<(SkiaView, float, float)>();
foreach (var item11 in list2)
{
SkiaView item2 = item11.Item1;
SKSize item3 = item11.Item2;
float item4 = item11.Item3;
float item5 = item11.Item4;
float num7 = (flag ? ((SKSize)(ref item3)).Width : ((SKSize)(ref item3)).Height);
float item6 = (flag ? ((SKSize)(ref item3)).Height : ((SKSize)(ref item3)).Width);
if (num6 > 0f && num4 > 0f)
{
num7 += num6 * (item4 / num4);
}
else if (num6 < 0f && num5 > 0f)
{
num7 += num6 * (item5 / num5);
}
list3.Add((item2, Math.Max(0f, num7), item6));
}
float num8 = list3.Sum<(SkiaView, float, float)>(((SkiaView child, float mainSize, float crossSize) s) => s.mainSize);
float num9 = Math.Max(0f, num - num8);
float num10 = (flag ? ((SKRect)(ref bounds)).Left : ((SKRect)(ref bounds)).Top);
float num11 = 0f;
switch (JustifyContent)
{
case FlexJustify.Center:
num10 += num9 / 2f;
break;
case FlexJustify.End:
num10 += num9;
break;
case FlexJustify.SpaceBetween:
if (list3.Count > 1)
{
num11 = num9 / (float)(list3.Count - 1);
}
break;
case FlexJustify.SpaceAround:
if (list3.Count > 0)
{
num11 = num9 / (float)list3.Count;
num10 += num11 / 2f;
}
break;
case FlexJustify.SpaceEvenly:
if (list3.Count > 0)
{
num11 = num9 / (float)(list3.Count + 1);
num10 += num11;
}
break;
}
float num12 = num10;
IEnumerable<(SkiaView, float, float)> enumerable2;
if (!flag2)
{
IEnumerable<(SkiaView, float, float)> enumerable = list3;
enumerable2 = enumerable;
}
else
{
enumerable2 = list3.AsEnumerable().Reverse();
}
SKRect bounds2 = default(SKRect);
foreach (var item12 in enumerable2)
{
SkiaView item7 = item12.Item1;
float item8 = item12.Item2;
float item9 = item12.Item3;
FlexAlignSelf alignSelf = GetAlignSelf(item7);
FlexAlignItems flexAlignItems = ((alignSelf == FlexAlignSelf.Auto) ? AlignItems : ((FlexAlignItems)alignSelf));
float num13 = (flag ? ((SKRect)(ref bounds)).Top : ((SKRect)(ref bounds)).Left);
float num14 = item9;
switch (flexAlignItems)
{
case FlexAlignItems.End:
num13 = (flag ? ((SKRect)(ref bounds)).Bottom : ((SKRect)(ref bounds)).Right) - num14;
break;
case FlexAlignItems.Center:
num13 += (num2 - num14) / 2f;
break;
case FlexAlignItems.Stretch:
num14 = num2;
break;
}
if (flag)
{
((SKRect)(ref bounds2))._002Ector(num12, num13, num12 + item8, num13 + num14);
}
else
{
((SKRect)(ref bounds2))._002Ector(num13, num12, num13 + num14, num12 + item8);
}
item7.Arrange(bounds2);
num12 += item8 + num11;
}
return bounds;
}
}

View File

@@ -1,381 +1,360 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System;
using SkiaSharp;
namespace Microsoft.Maui.Platform;
/// <summary>
/// A page that displays a flyout menu and detail content.
/// </summary>
public class SkiaFlyoutPage : SkiaLayoutView
{
private SkiaView? _flyout;
private SkiaView? _detail;
private bool _isPresented = false;
private float _flyoutWidth = 300f;
private float _flyoutAnimationProgress = 0f;
private bool _gestureEnabled = true;
private SkiaView? _flyout;
// Gesture tracking
private bool _isDragging = false;
private float _dragStartX;
private float _dragCurrentX;
private SkiaView? _detail;
/// <summary>
/// Gets or sets the flyout content (menu).
/// </summary>
public SkiaView? Flyout
{
get => _flyout;
set
{
if (_flyout != value)
{
if (_flyout != null)
{
RemoveChild(_flyout);
}
private bool _isPresented;
_flyout = value;
private float _flyoutWidth = 300f;
if (_flyout != null)
{
AddChild(_flyout);
}
private float _flyoutAnimationProgress;
Invalidate();
}
}
}
private bool _gestureEnabled = true;
/// <summary>
/// Gets or sets the detail content (main content).
/// </summary>
public SkiaView? Detail
{
get => _detail;
set
{
if (_detail != value)
{
if (_detail != null)
{
RemoveChild(_detail);
}
private bool _isDragging;
_detail = value;
private float _dragStartX;
if (_detail != null)
{
AddChild(_detail);
}
private float _dragCurrentX;
Invalidate();
}
}
}
public SkiaView? Flyout
{
get
{
return _flyout;
}
set
{
if (_flyout != value)
{
if (_flyout != null)
{
RemoveChild(_flyout);
}
_flyout = value;
if (_flyout != null)
{
AddChild(_flyout);
}
Invalidate();
}
}
}
/// <summary>
/// Gets or sets whether the flyout is currently presented.
/// </summary>
public bool IsPresented
{
get => _isPresented;
set
{
if (_isPresented != value)
{
_isPresented = value;
_flyoutAnimationProgress = value ? 1f : 0f;
IsPresentedChanged?.Invoke(this, EventArgs.Empty);
Invalidate();
}
}
}
public SkiaView? Detail
{
get
{
return _detail;
}
set
{
if (_detail != value)
{
if (_detail != null)
{
RemoveChild(_detail);
}
_detail = value;
if (_detail != null)
{
AddChild(_detail);
}
Invalidate();
}
}
}
/// <summary>
/// Gets or sets the width of the flyout panel.
/// </summary>
public float FlyoutWidth
{
get => _flyoutWidth;
set
{
if (_flyoutWidth != value)
{
_flyoutWidth = Math.Max(100, value);
InvalidateMeasure();
Invalidate();
}
}
}
public bool IsPresented
{
get
{
return _isPresented;
}
set
{
if (_isPresented != value)
{
_isPresented = value;
_flyoutAnimationProgress = (value ? 1f : 0f);
this.IsPresentedChanged?.Invoke(this, EventArgs.Empty);
Invalidate();
}
}
}
/// <summary>
/// Gets or sets whether swipe gestures are enabled.
/// </summary>
public bool GestureEnabled
{
get => _gestureEnabled;
set => _gestureEnabled = value;
}
public float FlyoutWidth
{
get
{
return _flyoutWidth;
}
set
{
if (_flyoutWidth != value)
{
_flyoutWidth = Math.Max(100f, value);
InvalidateMeasure();
Invalidate();
}
}
}
/// <summary>
/// The flyout layout behavior.
/// </summary>
public FlyoutLayoutBehavior FlyoutLayoutBehavior { get; set; } = FlyoutLayoutBehavior.Default;
public bool GestureEnabled
{
get
{
return _gestureEnabled;
}
set
{
_gestureEnabled = value;
}
}
/// <summary>
/// Background color of the scrim when flyout is open.
/// </summary>
public SKColor ScrimColor { get; set; } = new SKColor(0, 0, 0, 100);
public FlyoutLayoutBehavior FlyoutLayoutBehavior { get; set; }
/// <summary>
/// Shadow width for the flyout.
/// </summary>
public float ShadowWidth { get; set; } = 8f;
public SKColor ScrimColor { get; set; } = new SKColor((byte)0, (byte)0, (byte)0, (byte)100);
/// <summary>
/// Event raised when IsPresented changes.
/// </summary>
public event EventHandler? IsPresentedChanged;
public float ShadowWidth { get; set; } = 8f;
protected override SKSize MeasureOverride(SKSize availableSize)
{
// Measure flyout
if (_flyout != null)
{
_flyout.Measure(new SKSize(FlyoutWidth, availableSize.Height));
}
public event EventHandler? IsPresentedChanged;
// Measure detail to full size
if (_detail != null)
{
_detail.Measure(availableSize);
}
protected override SKSize MeasureOverride(SKSize availableSize)
{
//IL_001b: Unknown result type (might be due to invalid IL or missing references)
//IL_0020: Unknown result type (might be due to invalid IL or missing references)
//IL_003b: Unknown result type (might be due to invalid IL or missing references)
//IL_0034: Unknown result type (might be due to invalid IL or missing references)
//IL_0035: Unknown result type (might be due to invalid IL or missing references)
if (_flyout != null)
{
_flyout.Measure(new SKSize(FlyoutWidth, ((SKSize)(ref availableSize)).Height));
}
if (_detail != null)
{
_detail.Measure(availableSize);
}
return availableSize;
}
return availableSize;
}
protected override SKRect ArrangeOverride(SKRect bounds)
{
//IL_000e: Unknown result type (might be due to invalid IL or missing references)
//IL_0063: Unknown result type (might be due to invalid IL or missing references)
//IL_005d: Unknown result type (might be due to invalid IL or missing references)
if (_detail != null)
{
_detail.Arrange(bounds);
}
if (_flyout != null)
{
float num = ((SKRect)(ref bounds)).Left - FlyoutWidth + FlyoutWidth * _flyoutAnimationProgress;
SKRect bounds2 = default(SKRect);
((SKRect)(ref bounds2))._002Ector(num, ((SKRect)(ref bounds)).Top, num + FlyoutWidth, ((SKRect)(ref bounds)).Bottom);
_flyout.Arrange(bounds2);
}
return bounds;
}
protected override SKRect ArrangeOverride(SKRect bounds)
{
// Arrange detail to fill the entire area
if (_detail != null)
{
_detail.Arrange(bounds);
}
protected override void OnDraw(SKCanvas canvas, SKRect bounds)
{
//IL_0008: Unknown result type (might be due to invalid IL or missing references)
//IL_002f: Unknown result type (might be due to invalid IL or missing references)
//IL_0034: Unknown result type (might be due to invalid IL or missing references)
//IL_0036: Unknown result type (might be due to invalid IL or missing references)
//IL_003b: Unknown result type (might be due to invalid IL or missing references)
//IL_003f: Unknown result type (might be due to invalid IL or missing references)
//IL_0044: Unknown result type (might be due to invalid IL or missing references)
//IL_0055: Unknown result type (might be due to invalid IL or missing references)
//IL_005f: Unknown result type (might be due to invalid IL or missing references)
//IL_0067: Expected O, but got Unknown
//IL_0069: Unknown result type (might be due to invalid IL or missing references)
canvas.Save();
canvas.ClipRect(bounds, (SKClipOperation)1, false);
_detail?.Draw(canvas);
if (_flyoutAnimationProgress > 0f)
{
SKPaint val = new SKPaint();
SKColor scrimColor = ScrimColor;
SKColor scrimColor2 = ScrimColor;
val.Color = ((SKColor)(ref scrimColor)).WithAlpha((byte)((float)(int)((SKColor)(ref scrimColor2)).Alpha * _flyoutAnimationProgress));
val.Style = (SKPaintStyle)0;
SKPaint val2 = val;
try
{
canvas.DrawRect(base.Bounds, val2);
if (_flyout != null && ShadowWidth > 0f)
{
DrawFlyoutShadow(canvas);
}
_flyout?.Draw(canvas);
}
finally
{
((IDisposable)val2)?.Dispose();
}
}
canvas.Restore();
}
// 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);
_flyout.Arrange(flyoutBounds);
}
private void DrawFlyoutShadow(SKCanvas canvas)
{
//IL_000f: Unknown result type (might be due to invalid IL or missing references)
//IL_0014: Unknown result type (might be due to invalid IL or missing references)
//IL_0021: Unknown result type (might be due to invalid IL or missing references)
//IL_0026: Unknown result type (might be due to invalid IL or missing references)
//IL_0037: Unknown result type (might be due to invalid IL or missing references)
//IL_003c: Unknown result type (might be due to invalid IL or missing references)
//IL_0049: Unknown result type (might be due to invalid IL or missing references)
//IL_0050: Expected O, but got Unknown
//IL_0060: Unknown result type (might be due to invalid IL or missing references)
//IL_0073: Unknown result type (might be due to invalid IL or missing references)
//IL_0085: Unknown result type (might be due to invalid IL or missing references)
//IL_008a: Unknown result type (might be due to invalid IL or missing references)
//IL_0091: Unknown result type (might be due to invalid IL or missing references)
//IL_0096: Unknown result type (might be due to invalid IL or missing references)
//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
if (_flyout == null)
{
return;
}
SKRect bounds = _flyout.Bounds;
float right = ((SKRect)(ref bounds)).Right;
bounds = base.Bounds;
float top = ((SKRect)(ref bounds)).Top;
float num = right + ShadowWidth;
bounds = base.Bounds;
SKRect val = default(SKRect);
((SKRect)(ref val))._002Ector(right, top, num, ((SKRect)(ref bounds)).Bottom);
SKPaint val2 = new SKPaint();
val2.Shader = SKShader.CreateLinearGradient(new SKPoint(((SKRect)(ref val)).Left, ((SKRect)(ref val)).MidY), new SKPoint(((SKRect)(ref val)).Right, ((SKRect)(ref val)).MidY), (SKColor[])(object)new SKColor[2]
{
new SKColor((byte)0, (byte)0, (byte)0, (byte)60),
SKColors.Transparent
}, (float[])null, (SKShaderTileMode)0);
SKPaint val3 = val2;
try
{
canvas.DrawRect(val, val3);
}
finally
{
((IDisposable)val3)?.Dispose();
}
}
return bounds;
}
public override SkiaView? HitTest(float x, float y)
{
//IL_0009: Unknown result type (might be due to invalid IL or missing references)
//IL_000e: Unknown result type (might be due to invalid IL or missing references)
if (base.IsVisible)
{
SKRect bounds = base.Bounds;
if (((SKRect)(ref bounds)).Contains(x, y))
{
if (_flyoutAnimationProgress > 0f && _flyout != null)
{
SkiaView skiaView = _flyout.HitTest(x, y);
if (skiaView != null)
{
return skiaView;
}
if (_isPresented)
{
return this;
}
}
if (_detail != null)
{
SkiaView skiaView2 = _detail.HitTest(x, y);
if (skiaView2 != null)
{
return skiaView2;
}
}
return this;
}
}
return null;
}
protected override void OnDraw(SKCanvas canvas, SKRect bounds)
{
canvas.Save();
canvas.ClipRect(bounds);
public override void OnPointerPressed(PointerEventArgs e)
{
//IL_001f: Unknown result type (might be due to invalid IL or missing references)
//IL_0024: Unknown result type (might be due to invalid IL or missing references)
if (!base.IsEnabled)
{
return;
}
if (_isPresented && _flyout != null)
{
SKRect bounds = _flyout.Bounds;
if (!((SKRect)(ref bounds)).Contains(e.X, e.Y))
{
IsPresented = false;
e.Handled = true;
return;
}
}
if (_gestureEnabled)
{
_isDragging = true;
_dragStartX = e.X;
_dragCurrentX = e.X;
}
base.OnPointerPressed(e);
}
// Draw detail content first
_detail?.Draw(canvas);
public override void OnPointerMoved(PointerEventArgs e)
{
if (_isDragging && _gestureEnabled)
{
_dragCurrentX = e.X;
float num = _dragCurrentX - _dragStartX;
if (_isPresented)
{
_flyoutAnimationProgress = Math.Clamp(1f + num / FlyoutWidth, 0f, 1f);
}
else if (_dragStartX < 30f)
{
_flyoutAnimationProgress = Math.Clamp(num / FlyoutWidth, 0f, 1f);
}
Invalidate();
e.Handled = true;
}
base.OnPointerMoved(e);
}
// If flyout is visible, draw scrim and flyout
if (_flyoutAnimationProgress > 0)
{
// Draw scrim (semi-transparent overlay)
using var scrimPaint = new SKPaint
{
Color = ScrimColor.WithAlpha((byte)(ScrimColor.Alpha * _flyoutAnimationProgress)),
Style = SKPaintStyle.Fill
};
canvas.DrawRect(Bounds, scrimPaint);
public override void OnPointerReleased(PointerEventArgs e)
{
if (_isDragging)
{
_isDragging = false;
if (_flyoutAnimationProgress > 0.5f)
{
_isPresented = true;
_flyoutAnimationProgress = 1f;
}
else
{
_isPresented = false;
_flyoutAnimationProgress = 0f;
}
this.IsPresentedChanged?.Invoke(this, EventArgs.Empty);
Invalidate();
}
base.OnPointerReleased(e);
}
// Draw flyout shadow
if (_flyout != null && ShadowWidth > 0)
{
DrawFlyoutShadow(canvas);
}
// Draw flyout
_flyout?.Draw(canvas);
}
canvas.Restore();
}
private void DrawFlyoutShadow(SKCanvas canvas)
{
if (_flyout == null) return;
float shadowRight = _flyout.Bounds.Right;
var shadowRect = new SKRect(
shadowRight,
Bounds.Top,
shadowRight + ShadowWidth,
Bounds.Bottom);
using var shadowPaint = new SKPaint
{
Shader = SKShader.CreateLinearGradient(
new SKPoint(shadowRect.Left, shadowRect.MidY),
new SKPoint(shadowRect.Right, shadowRect.MidY),
new SKColor[] { new SKColor(0, 0, 0, 60), SKColors.Transparent },
null,
SKShaderTileMode.Clamp)
};
canvas.DrawRect(shadowRect, shadowPaint);
}
public override SkiaView? HitTest(float x, float y)
{
if (!IsVisible || !Bounds.Contains(x, y)) return null;
// If flyout is presented, check if hit is in flyout
if (_flyoutAnimationProgress > 0 && _flyout != null)
{
var flyoutHit = _flyout.HitTest(x, y);
if (flyoutHit != null) return flyoutHit;
// Hit on scrim closes flyout
if (_isPresented)
{
return this; // Return self to handle scrim tap
}
}
// Check detail content
if (_detail != null)
{
var detailHit = _detail.HitTest(x, y);
if (detailHit != null) return detailHit;
}
return this;
}
public override void OnPointerPressed(PointerEventArgs e)
{
if (!IsEnabled) return;
// Check if tap is on scrim (outside flyout but flyout is open)
if (_isPresented && _flyout != null && !_flyout.Bounds.Contains(e.X, e.Y))
{
IsPresented = false;
e.Handled = true;
return;
}
// Start drag gesture
if (_gestureEnabled)
{
_isDragging = true;
_dragStartX = e.X;
_dragCurrentX = e.X;
}
base.OnPointerPressed(e);
}
public override void OnPointerMoved(PointerEventArgs e)
{
if (_isDragging && _gestureEnabled)
{
_dragCurrentX = e.X;
float delta = _dragCurrentX - _dragStartX;
// Calculate new animation progress
if (_isPresented)
{
// Dragging to close
_flyoutAnimationProgress = Math.Clamp(1f + (delta / FlyoutWidth), 0f, 1f);
}
else
{
// Dragging to open (only from left edge)
if (_dragStartX < 30)
{
_flyoutAnimationProgress = Math.Clamp(delta / FlyoutWidth, 0f, 1f);
}
}
Invalidate();
e.Handled = true;
}
base.OnPointerMoved(e);
}
public override void OnPointerReleased(PointerEventArgs e)
{
if (_isDragging)
{
_isDragging = false;
// Determine final state based on progress
if (_flyoutAnimationProgress > 0.5f)
{
_isPresented = true;
_flyoutAnimationProgress = 1f;
}
else
{
_isPresented = false;
_flyoutAnimationProgress = 0f;
}
IsPresentedChanged?.Invoke(this, EventArgs.Empty);
Invalidate();
}
base.OnPointerReleased(e);
}
/// <summary>
/// Toggles the flyout presentation state.
/// </summary>
public void ToggleFlyout()
{
IsPresented = !IsPresented;
}
}
/// <summary>
/// Defines how the flyout behaves.
/// </summary>
public enum FlyoutLayoutBehavior
{
/// <summary>
/// Default behavior based on device/window size.
/// </summary>
Default,
/// <summary>
/// Flyout slides over the detail content.
/// </summary>
Popover,
/// <summary>
/// Flyout and detail are shown side by side.
/// </summary>
Split,
/// <summary>
/// Flyout pushes the detail content.
/// </summary>
SplitOnLandscape,
/// <summary>
/// Flyout is always shown in portrait, side by side in landscape.
/// </summary>
SplitOnPortrait
public void ToggleFlyout()
{
IsPresented = !IsPresented;
}
}

18
Views/SkiaFrame.cs Normal file
View File

@@ -0,0 +1,18 @@
using SkiaSharp;
namespace Microsoft.Maui.Platform;
public class SkiaFrame : SkiaBorder
{
public SkiaFrame()
{
//IL_0024: Unknown result type (might be due to invalid IL or missing references)
//IL_002f: Unknown result type (might be due to invalid IL or missing references)
base.HasShadow = true;
base.CornerRadius = 4f;
SetPadding(10f);
base.BackgroundColor = SKColors.White;
base.Stroke = SKColors.Transparent;
base.StrokeThickness = 0f;
}
}

View File

@@ -1,65 +1,81 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using SkiaSharp;
using System;
using Microsoft.Maui.Graphics;
using Microsoft.Maui.Graphics.Skia;
using SkiaSharp;
namespace Microsoft.Maui.Platform;
/// <summary>
/// Skia-rendered graphics view that supports IDrawable for custom drawing.
/// </summary>
public class SkiaGraphicsView : SkiaView
{
private IDrawable? _drawable;
private IDrawable? _drawable;
public IDrawable? Drawable
{
get => _drawable;
set
{
_drawable = value;
Invalidate();
}
}
public IDrawable? Drawable
{
get
{
return _drawable;
}
set
{
_drawable = value;
Invalidate();
}
}
protected override void OnDraw(SKCanvas canvas, SKRect bounds)
{
// Draw background
if (BackgroundColor != SKColors.Transparent)
{
using var bgPaint = new SKPaint
{
Color = BackgroundColor,
Style = SKPaintStyle.Fill
};
canvas.DrawRect(bounds, bgPaint);
}
protected override void OnDraw(SKCanvas canvas, SKRect bounds)
{
//IL_0001: Unknown result type (might be due to invalid IL or missing references)
//IL_0006: Unknown result type (might be due to invalid IL or missing references)
//IL_0012: Unknown result type (might be due to invalid IL or missing references)
//IL_0017: Unknown result type (might be due to invalid IL or missing references)
//IL_0019: Unknown result type (might be due to invalid IL or missing references)
//IL_0023: Unknown result type (might be due to invalid IL or missing references)
//IL_002b: Expected O, but got Unknown
//IL_006a: Unknown result type (might be due to invalid IL or missing references)
//IL_0070: Expected O, but got Unknown
//IL_002c: Unknown result type (might be due to invalid IL or missing references)
//IL_007e: Unknown result type (might be due to invalid IL or missing references)
if (base.BackgroundColor != SKColors.Transparent)
{
SKPaint val = new SKPaint
{
Color = base.BackgroundColor,
Style = (SKPaintStyle)0
};
try
{
canvas.DrawRect(bounds, val);
}
finally
{
((IDisposable)val)?.Dispose();
}
}
if (_drawable != null)
{
RectF val2 = default(RectF);
((RectF)(ref val2))._002Ector(((SKRect)(ref bounds)).Left, ((SKRect)(ref bounds)).Top, ((SKRect)(ref bounds)).Width, ((SKRect)(ref bounds)).Height);
SkiaCanvas val3 = new SkiaCanvas();
try
{
val3.Canvas = canvas;
_drawable.Draw((ICanvas)(object)val3, val2);
}
finally
{
((IDisposable)val3)?.Dispose();
}
}
}
// Draw using IDrawable
if (_drawable != null)
{
var dirtyRect = new RectF(bounds.Left, bounds.Top, bounds.Width, bounds.Height);
using var skiaCanvas = new SkiaCanvas();
skiaCanvas.Canvas = canvas;
_drawable.Draw(skiaCanvas, dirtyRect);
}
}
protected override SKSize MeasureOverride(SKSize availableSize)
{
// Graphics view takes all available space by default
if (availableSize.Width < float.MaxValue && availableSize.Height < float.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);
}
protected override SKSize MeasureOverride(SKSize availableSize)
{
//IL_001c: Unknown result type (might be due to invalid IL or missing references)
//IL_0056: Unknown result type (might be due to invalid IL or missing references)
if (((SKSize)(ref availableSize)).Width < float.MaxValue && ((SKSize)(ref availableSize)).Height < float.MaxValue)
{
return availableSize;
}
return new SKSize((((SKSize)(ref availableSize)).Width < float.MaxValue) ? ((SKSize)(ref availableSize)).Width : 100f, (((SKSize)(ref availableSize)).Height < float.MaxValue) ? ((SKSize)(ref availableSize)).Height : 100f);
}
}

406
Views/SkiaGrid.cs Normal file
View File

@@ -0,0 +1,406 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Maui.Controls;
using SkiaSharp;
namespace Microsoft.Maui.Platform;
public class SkiaGrid : SkiaLayoutView
{
public static readonly BindableProperty RowSpacingProperty = BindableProperty.Create("RowSpacing", typeof(float), typeof(SkiaGrid), (object)0f, (BindingMode)2, (ValidateValueDelegate)null, (BindingPropertyChangedDelegate)delegate(BindableObject b, object o, object n)
{
((SkiaGrid)(object)b).InvalidateMeasure();
}, (BindingPropertyChangingDelegate)null, (CoerceValueDelegate)null, (CreateDefaultValueDelegate)null);
public static readonly BindableProperty ColumnSpacingProperty = BindableProperty.Create("ColumnSpacing", typeof(float), typeof(SkiaGrid), (object)0f, (BindingMode)2, (ValidateValueDelegate)null, (BindingPropertyChangedDelegate)delegate(BindableObject b, object o, object n)
{
((SkiaGrid)(object)b).InvalidateMeasure();
}, (BindingPropertyChangingDelegate)null, (CoerceValueDelegate)null, (CreateDefaultValueDelegate)null);
private readonly List<GridLength> _rowDefinitions = new List<GridLength>();
private readonly List<GridLength> _columnDefinitions = new List<GridLength>();
private readonly Dictionary<SkiaView, GridPosition> _childPositions = new Dictionary<SkiaView, GridPosition>();
private float[] _rowHeights = Array.Empty<float>();
private float[] _columnWidths = Array.Empty<float>();
public IList<GridLength> RowDefinitions => _rowDefinitions;
public IList<GridLength> ColumnDefinitions => _columnDefinitions;
public float RowSpacing
{
get
{
return (float)((BindableObject)this).GetValue(RowSpacingProperty);
}
set
{
((BindableObject)this).SetValue(RowSpacingProperty, (object)value);
}
}
public float ColumnSpacing
{
get
{
return (float)((BindableObject)this).GetValue(ColumnSpacingProperty);
}
set
{
((BindableObject)this).SetValue(ColumnSpacingProperty, (object)value);
}
}
public void AddChild(SkiaView child, int row, int column, int rowSpan = 1, int columnSpan = 1)
{
base.AddChild(child);
_childPositions[child] = new GridPosition(row, column, rowSpan, columnSpan);
}
public override void RemoveChild(SkiaView child)
{
base.RemoveChild(child);
_childPositions.Remove(child);
}
public GridPosition GetPosition(SkiaView child)
{
if (!_childPositions.TryGetValue(child, out var value))
{
return new GridPosition(0, 0);
}
return value;
}
public void SetPosition(SkiaView child, int row, int column, int rowSpan = 1, int columnSpan = 1)
{
_childPositions[child] = new GridPosition(row, column, rowSpan, columnSpan);
InvalidateMeasure();
Invalidate();
}
protected override SKSize MeasureOverride(SKSize availableSize)
{
//IL_0008: Unknown result type (might be due to invalid IL or missing references)
//IL_000d: Unknown result type (might be due to invalid IL or missing references)
//IL_0018: Unknown result type (might be due to invalid IL or missing references)
//IL_001d: Unknown result type (might be due to invalid IL or missing references)
//IL_0030: Unknown result type (might be due to invalid IL or missing references)
//IL_0035: Unknown result type (might be due to invalid IL or missing references)
//IL_0040: Unknown result type (might be due to invalid IL or missing references)
//IL_0045: Unknown result type (might be due to invalid IL or missing references)
//IL_015f: Unknown result type (might be due to invalid IL or missing references)
//IL_0164: Unknown result type (might be due to invalid IL or missing references)
//IL_0169: Unknown result type (might be due to invalid IL or missing references)
//IL_022a: Unknown result type (might be due to invalid IL or missing references)
//IL_022f: Unknown result type (might be due to invalid IL or missing references)
//IL_0234: Unknown result type (might be due to invalid IL or missing references)
//IL_0333: Unknown result type (might be due to invalid IL or missing references)
//IL_0338: Unknown result type (might be due to invalid IL or missing references)
//IL_0392: Unknown result type (might be due to invalid IL or missing references)
//IL_0397: Unknown result type (might be due to invalid IL or missing references)
//IL_03a2: Unknown result type (might be due to invalid IL or missing references)
//IL_03a7: Unknown result type (might be due to invalid IL or missing references)
//IL_03b4: Unknown result type (might be due to invalid IL or missing references)
//IL_03b9: Unknown result type (might be due to invalid IL or missing references)
//IL_03c4: Unknown result type (might be due to invalid IL or missing references)
//IL_03c9: Unknown result type (might be due to invalid IL or missing references)
//IL_03d3: Unknown result type (might be due to invalid IL or missing references)
float width = ((SKSize)(ref availableSize)).Width;
SKRect padding = base.Padding;
float num = width - ((SKRect)(ref padding)).Left;
padding = base.Padding;
float num2 = num - ((SKRect)(ref padding)).Right;
float height = ((SKSize)(ref availableSize)).Height;
padding = base.Padding;
float num3 = height - ((SKRect)(ref padding)).Top;
padding = base.Padding;
float num4 = num3 - ((SKRect)(ref padding)).Bottom;
if (float.IsNaN(num2) || float.IsInfinity(num2))
{
num2 = 800f;
}
if (float.IsNaN(num4) || float.IsInfinity(num4))
{
num4 = float.PositiveInfinity;
}
int num5 = Math.Max(1, (_rowDefinitions.Count > 0) ? _rowDefinitions.Count : (GetMaxRow() + 1));
int num6 = Math.Max(1, (_columnDefinitions.Count > 0) ? _columnDefinitions.Count : (GetMaxColumn() + 1));
float[] array = new float[num6];
float[] array2 = new float[num5];
foreach (SkiaView child in base.Children)
{
if (child.IsVisible)
{
GridPosition position = GetPosition(child);
if (((position.Column < _columnDefinitions.Count) ? _columnDefinitions[position.Column] : GridLength.Star).IsAuto && position.ColumnSpan == 1)
{
SKSize val = child.Measure(new SKSize(float.PositiveInfinity, float.PositiveInfinity));
float val2 = (float.IsNaN(((SKSize)(ref val)).Width) ? 0f : ((SKSize)(ref val)).Width);
array[position.Column] = Math.Max(array[position.Column], val2);
}
}
}
_columnWidths = CalculateSizesWithAuto(_columnDefinitions, num2, ColumnSpacing, num6, array);
foreach (SkiaView child2 in base.Children)
{
if (child2.IsVisible)
{
GridPosition position2 = GetPosition(child2);
float cellWidth = GetCellWidth(position2.Column, position2.ColumnSpan);
SKSize val3 = child2.Measure(new SKSize(cellWidth, float.PositiveInfinity));
float num7 = ((SKSize)(ref val3)).Height;
if (float.IsNaN(num7) || float.IsInfinity(num7) || num7 > 100000f)
{
num7 = 44f;
}
if (position2.RowSpan == 1)
{
array2[position2.Row] = Math.Max(array2[position2.Row], num7);
}
}
}
if (float.IsInfinity(num4) || num4 > 100000f)
{
_rowHeights = array2;
}
else
{
_rowHeights = CalculateSizesWithAuto(_rowDefinitions, num4, RowSpacing, num5, array2);
}
foreach (SkiaView child3 in base.Children)
{
if (child3.IsVisible)
{
GridPosition position3 = GetPosition(child3);
float cellWidth2 = GetCellWidth(position3.Column, position3.ColumnSpan);
float cellHeight = GetCellHeight(position3.Row, position3.RowSpan);
child3.Measure(new SKSize(cellWidth2, cellHeight));
}
}
float num8 = _columnWidths.Sum() + (float)Math.Max(0, num6 - 1) * ColumnSpacing;
float num9 = _rowHeights.Sum() + (float)Math.Max(0, num5 - 1) * RowSpacing;
padding = base.Padding;
float num10 = num8 + ((SKRect)(ref padding)).Left;
padding = base.Padding;
float num11 = num10 + ((SKRect)(ref padding)).Right;
padding = base.Padding;
float num12 = num9 + ((SKRect)(ref padding)).Top;
padding = base.Padding;
return new SKSize(num11, num12 + ((SKRect)(ref padding)).Bottom);
}
private int GetMaxRow()
{
int num = 0;
foreach (GridPosition value in _childPositions.Values)
{
num = Math.Max(num, value.Row + value.RowSpan - 1);
}
return num;
}
private int GetMaxColumn()
{
int num = 0;
foreach (GridPosition value in _childPositions.Values)
{
num = Math.Max(num, value.Column + value.ColumnSpan - 1);
}
return num;
}
private float[] CalculateSizesWithAuto(List<GridLength> definitions, float available, float spacing, int count, float[] naturalSizes)
{
if (count == 0)
{
return new float[1] { available };
}
float[] array = new float[count];
float num = (float)Math.Max(0, count - 1) * spacing;
float num2 = available - num;
float num3 = 0f;
for (int i = 0; i < count; i++)
{
GridLength gridLength = ((i < definitions.Count) ? definitions[i] : GridLength.Star);
if (gridLength.IsAbsolute)
{
array[i] = gridLength.Value;
num2 -= gridLength.Value;
}
else if (gridLength.IsAuto)
{
array[i] = naturalSizes[i];
num2 -= array[i];
}
else if (gridLength.IsStar)
{
num3 += gridLength.Value;
}
}
if (num3 > 0f && num2 > 0f)
{
for (int j = 0; j < count; j++)
{
GridLength gridLength2 = ((j < definitions.Count) ? definitions[j] : GridLength.Star);
if (gridLength2.IsStar)
{
array[j] = gridLength2.Value / num3 * num2;
}
}
}
return array;
}
private float GetCellWidth(int column, int span)
{
float num = 0f;
for (int i = column; i < Math.Min(column + span, _columnWidths.Length); i++)
{
num += _columnWidths[i];
if (i > column)
{
num += ColumnSpacing;
}
}
return num;
}
private float GetCellHeight(int row, int span)
{
float num = 0f;
for (int i = row; i < Math.Min(row + span, _rowHeights.Length); i++)
{
num += _rowHeights[i];
if (i > row)
{
num += RowSpacing;
}
}
return num;
}
private float GetColumnOffset(int column)
{
float num = 0f;
for (int i = 0; i < Math.Min(column, _columnWidths.Length); i++)
{
num += _columnWidths[i] + ColumnSpacing;
}
return num;
}
private float GetRowOffset(int row)
{
float num = 0f;
for (int i = 0; i < Math.Min(row, _rowHeights.Length); i++)
{
num += _rowHeights[i] + RowSpacing;
}
return num;
}
protected override SKRect ArrangeOverride(SKRect bounds)
{
//IL_0001: Unknown result type (might be due to invalid IL or missing references)
//IL_0002: Unknown result type (might be due to invalid IL or missing references)
//IL_0007: Unknown result type (might be due to invalid IL or missing references)
//IL_0349: Unknown result type (might be due to invalid IL or missing references)
//IL_0300: Unknown result type (might be due to invalid IL or missing references)
//IL_0301: Unknown result type (might be due to invalid IL or missing references)
//IL_03ca: Unknown result type (might be due to invalid IL or missing references)
//IL_029d: Unknown result type (might be due to invalid IL or missing references)
//IL_02a2: Unknown result type (might be due to invalid IL or missing references)
//IL_02df: Unknown result type (might be due to invalid IL or missing references)
try
{
SKRect contentBounds = GetContentBounds(bounds);
int num = ((_rowHeights.Length == 0) ? 1 : _rowHeights.Length);
if (_columnWidths.Length != 0)
{
_ = _columnWidths.Length;
}
float[] array = _rowHeights;
if (((SKRect)(ref contentBounds)).Height > 0f && !float.IsInfinity(((SKRect)(ref contentBounds)).Height))
{
float num2 = _rowHeights.Sum() + (float)Math.Max(0, num - 1) * RowSpacing;
if (((SKRect)(ref contentBounds)).Height > num2 + 1f)
{
array = new float[num];
float num3 = ((SKRect)(ref contentBounds)).Height - num2;
float num4 = 0f;
for (int i = 0; i < num; i++)
{
GridLength gridLength = ((i < _rowDefinitions.Count) ? _rowDefinitions[i] : GridLength.Star);
if (gridLength.IsStar)
{
num4 += gridLength.Value;
}
}
for (int j = 0; j < num; j++)
{
GridLength gridLength2 = ((j < _rowDefinitions.Count) ? _rowDefinitions[j] : GridLength.Star);
array[j] = ((j < _rowHeights.Length) ? _rowHeights[j] : 0f);
if (gridLength2.IsStar && num4 > 0f)
{
array[j] += num3 * (gridLength2.Value / num4);
}
}
}
else
{
array = _rowHeights;
}
}
SKRect bounds2 = default(SKRect);
foreach (SkiaView child in base.Children)
{
if (!child.IsVisible)
{
continue;
}
GridPosition position = GetPosition(child);
float num5 = ((SKRect)(ref contentBounds)).Left + GetColumnOffset(position.Column);
float num6 = ((SKRect)(ref contentBounds)).Top;
for (int k = 0; k < Math.Min(position.Row, array.Length); k++)
{
num6 += array[k] + RowSpacing;
}
float num7 = GetCellWidth(position.Column, position.ColumnSpan);
float num8 = 0f;
for (int l = position.Row; l < Math.Min(position.Row + position.RowSpan, array.Length); l++)
{
num8 += array[l];
if (l > position.Row)
{
num8 += RowSpacing;
}
}
if (float.IsInfinity(num7) || float.IsNaN(num7))
{
num7 = ((SKRect)(ref contentBounds)).Width;
}
if (float.IsInfinity(num8) || float.IsNaN(num8) || num8 <= 0f)
{
num8 = ((SKRect)(ref contentBounds)).Height;
}
Thickness margin = child.Margin;
((SKRect)(ref bounds2))._002Ector(num5 + (float)((Thickness)(ref margin)).Left, num6 + (float)((Thickness)(ref margin)).Top, num5 + num7 - (float)((Thickness)(ref margin)).Right, num6 + num8 - (float)((Thickness)(ref margin)).Bottom);
child.Arrange(bounds2);
}
return bounds;
}
catch (Exception ex)
{
Console.WriteLine("[SkiaGrid] EXCEPTION in ArrangeOverride: " + ex.GetType().Name + ": " + ex.Message);
Console.WriteLine($"[SkiaGrid] Bounds: {bounds}, RowHeights: {_rowHeights.Length}, RowDefs: {_rowDefinitions.Count}, Children: {base.Children.Count}");
Console.WriteLine("[SkiaGrid] Stack trace: " + ex.StackTrace);
throw;
}
}
}

View File

@@ -1,263 +1,553 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System;
using System.Collections.Generic;
using System.IO;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
using SkiaSharp;
using Microsoft.Maui.Graphics;
using Svg.Skia;
namespace Microsoft.Maui.Platform;
/// <summary>
/// Skia-rendered image control.
/// </summary>
public class SkiaImage : SkiaView
{
private SKBitmap? _bitmap;
private SKImage? _image;
private bool _isLoading;
private SKBitmap? _bitmap;
public SKBitmap? Bitmap
{
get => _bitmap;
set
{
_bitmap?.Dispose();
_bitmap = value;
_image?.Dispose();
_image = value != null ? SKImage.FromBitmap(value) : null;
Invalidate();
}
}
private SKImage? _image;
public Aspect Aspect { get; set; } = Aspect.AspectFit;
public bool IsOpaque { get; set; }
public bool IsLoading => _isLoading;
public bool IsAnimationPlaying { get; set; }
private bool _isLoading;
public event EventHandler? ImageLoaded;
public event EventHandler<ImageLoadingErrorEventArgs>? ImageLoadingError;
private string? _currentFilePath;
protected override void OnDraw(SKCanvas canvas, SKRect bounds)
{
// Draw background if not opaque
if (!IsOpaque && BackgroundColor != SKColors.Transparent)
{
using var bgPaint = new SKPaint
{
Color = BackgroundColor,
Style = SKPaintStyle.Fill
};
canvas.DrawRect(bounds, bgPaint);
}
private bool _isSvg;
if (_image == null) return;
private CancellationTokenSource? _loadCts;
var imageWidth = _image.Width;
var imageHeight = _image.Height;
private readonly object _loadLock = new object();
if (imageWidth <= 0 || imageHeight <= 0) return;
private double _svgLoadedWidth;
var destRect = CalculateDestRect(bounds, imageWidth, imageHeight);
private double _svgLoadedHeight;
using var paint = new SKPaint
{
IsAntialias = true,
FilterQuality = SKFilterQuality.High
};
private bool _pendingSvgReload;
canvas.DrawImage(_image, destRect, paint);
}
private SKRect _lastArrangedBounds;
private SKRect CalculateDestRect(SKRect bounds, float imageWidth, float imageHeight)
{
float destX, destY, destWidth, destHeight;
public SKBitmap? Bitmap
{
get
{
return _bitmap;
}
set
{
SKBitmap? bitmap = _bitmap;
if (bitmap != null)
{
((SKNativeObject)bitmap).Dispose();
}
_bitmap = value;
SKImage? image = _image;
if (image != null)
{
((SKNativeObject)image).Dispose();
}
_image = ((value != null) ? SKImage.FromBitmap(value) : null);
Invalidate();
}
}
switch (Aspect)
{
case Aspect.Fill:
// Stretch to fill entire bounds
return bounds;
public Aspect Aspect { get; set; }
case Aspect.AspectFit:
// Scale to fit while maintaining aspect ratio
var fitScale = Math.Min(bounds.Width / imageWidth, bounds.Height / imageHeight);
destWidth = imageWidth * fitScale;
destHeight = imageHeight * fitScale;
destX = bounds.Left + (bounds.Width - destWidth) / 2;
destY = bounds.Top + (bounds.Height - destHeight) / 2;
return new SKRect(destX, destY, destX + destWidth, destY + destHeight);
public bool IsOpaque { get; set; }
case Aspect.AspectFill:
// Scale to fill while maintaining aspect ratio (may crop)
var fillScale = Math.Max(bounds.Width / imageWidth, bounds.Height / imageHeight);
destWidth = imageWidth * fillScale;
destHeight = imageHeight * fillScale;
destX = bounds.Left + (bounds.Width - destWidth) / 2;
destY = bounds.Top + (bounds.Height - destHeight) / 2;
return new SKRect(destX, destY, destX + destWidth, destY + destHeight);
public bool IsLoading => _isLoading;
case Aspect.Center:
// Center without scaling
destX = bounds.Left + (bounds.Width - imageWidth) / 2;
destY = bounds.Top + (bounds.Height - imageHeight) / 2;
return new SKRect(destX, destY, destX + imageWidth, destY + imageHeight);
public bool IsAnimationPlaying { get; set; }
default:
return bounds;
}
}
public new double WidthRequest
{
get
{
return base.WidthRequest;
}
set
{
base.WidthRequest = value;
ScheduleSvgReloadIfNeeded();
}
}
public async Task LoadFromFileAsync(string filePath)
{
_isLoading = true;
Invalidate();
public new double HeightRequest
{
get
{
return base.HeightRequest;
}
set
{
base.HeightRequest = value;
ScheduleSvgReloadIfNeeded();
}
}
try
{
await Task.Run(() =>
{
using var stream = File.OpenRead(filePath);
var bitmap = SKBitmap.Decode(stream);
if (bitmap != null)
{
Bitmap = bitmap;
}
});
public event EventHandler? ImageLoaded;
_isLoading = false;
ImageLoaded?.Invoke(this, EventArgs.Empty);
}
catch (Exception ex)
{
_isLoading = false;
ImageLoadingError?.Invoke(this, new ImageLoadingErrorEventArgs(ex));
}
public event EventHandler<ImageLoadingErrorEventArgs>? ImageLoadingError;
Invalidate();
}
private void ScheduleSvgReloadIfNeeded()
{
if (_isSvg && !string.IsNullOrEmpty(_currentFilePath))
{
double widthRequest = WidthRequest;
double heightRequest = HeightRequest;
if (widthRequest > 0.0 && heightRequest > 0.0 && (Math.Abs(_svgLoadedWidth - widthRequest) > 0.5 || Math.Abs(_svgLoadedHeight - heightRequest) > 0.5) && !_pendingSvgReload)
{
_pendingSvgReload = true;
ReloadSvgDebounced();
}
}
}
public async Task LoadFromStreamAsync(Stream stream)
{
_isLoading = true;
Invalidate();
private async Task ReloadSvgDebounced()
{
await Task.Delay(10);
_pendingSvgReload = false;
if (!string.IsNullOrEmpty(_currentFilePath) && WidthRequest > 0.0 && HeightRequest > 0.0)
{
Console.WriteLine($"[SkiaImage] Reloading SVG at {WidthRequest}x{HeightRequest} (was {_svgLoadedWidth}x{_svgLoadedHeight})");
await LoadSvgAtSizeAsync(_currentFilePath, WidthRequest, HeightRequest);
}
}
try
{
await Task.Run(() =>
{
var bitmap = SKBitmap.Decode(stream);
if (bitmap != null)
{
Bitmap = bitmap;
}
});
protected override void OnDraw(SKCanvas canvas, SKRect bounds)
{
//IL_0009: Unknown result type (might be due to invalid IL or missing references)
//IL_000e: Unknown result type (might be due to invalid IL or missing references)
//IL_001a: Unknown result type (might be due to invalid IL or missing references)
//IL_001f: Unknown result type (might be due to invalid IL or missing references)
//IL_0021: Unknown result type (might be due to invalid IL or missing references)
//IL_002b: Unknown result type (might be due to invalid IL or missing references)
//IL_0034: Expected O, but got Unknown
//IL_0035: Unknown result type (might be due to invalid IL or missing references)
//IL_0076: Unknown result type (might be due to invalid IL or missing references)
//IL_007b: Unknown result type (might be due to invalid IL or missing references)
//IL_0080: Unknown result type (might be due to invalid IL or missing references)
//IL_0081: Unknown result type (might be due to invalid IL or missing references)
//IL_0086: Unknown result type (might be due to invalid IL or missing references)
//IL_008d: Unknown result type (might be due to invalid IL or missing references)
//IL_0095: Expected O, but got Unknown
//IL_009c: Unknown result type (might be due to invalid IL or missing references)
if (!IsOpaque && base.BackgroundColor != SKColors.Transparent)
{
SKPaint val = new SKPaint
{
Color = base.BackgroundColor,
Style = (SKPaintStyle)0
};
try
{
canvas.DrawRect(bounds, val);
}
finally
{
((IDisposable)val)?.Dispose();
}
}
if (_image == null)
{
return;
}
int width = _image.Width;
int height = _image.Height;
if (width <= 0 || height <= 0)
{
return;
}
SKRect val2 = CalculateDestRect(bounds, width, height);
SKPaint val3 = new SKPaint
{
IsAntialias = true,
FilterQuality = (SKFilterQuality)3
};
try
{
canvas.DrawImage(_image, val2, val3);
}
finally
{
((IDisposable)val3)?.Dispose();
}
}
_isLoading = false;
ImageLoaded?.Invoke(this, EventArgs.Empty);
}
catch (Exception ex)
{
_isLoading = false;
ImageLoadingError?.Invoke(this, new ImageLoadingErrorEventArgs(ex));
}
private SKRect CalculateDestRect(SKRect bounds, float imageWidth, float imageHeight)
{
//IL_0001: Unknown result type (might be due to invalid IL or missing references)
//IL_0006: Unknown result type (might be due to invalid IL or missing references)
//IL_0008: Unknown result type (might be due to invalid IL or missing references)
//IL_001f: Expected I4, but got Unknown
//IL_0081: Unknown result type (might be due to invalid IL or missing references)
//IL_00e2: Unknown result type (might be due to invalid IL or missing references)
//IL_0024: Unknown result type (might be due to invalid IL or missing references)
//IL_0120: Unknown result type (might be due to invalid IL or missing references)
//IL_0126: Unknown result type (might be due to invalid IL or missing references)
Aspect aspect = Aspect;
switch ((int)aspect)
{
case 2:
return bounds;
case 0:
{
float num6 = Math.Min(((SKRect)(ref bounds)).Width / imageWidth, ((SKRect)(ref bounds)).Height / imageHeight);
float num4 = imageWidth * num6;
float num5 = imageHeight * num6;
float num = ((SKRect)(ref bounds)).Left + (((SKRect)(ref bounds)).Width - num4) / 2f;
float num2 = ((SKRect)(ref bounds)).Top + (((SKRect)(ref bounds)).Height - num5) / 2f;
return new SKRect(num, num2, num + num4, num2 + num5);
}
case 1:
{
float num3 = Math.Max(((SKRect)(ref bounds)).Width / imageWidth, ((SKRect)(ref bounds)).Height / imageHeight);
float num4 = imageWidth * num3;
float num5 = imageHeight * num3;
float num = ((SKRect)(ref bounds)).Left + (((SKRect)(ref bounds)).Width - num4) / 2f;
float num2 = ((SKRect)(ref bounds)).Top + (((SKRect)(ref bounds)).Height - num5) / 2f;
return new SKRect(num, num2, num + num4, num2 + num5);
}
case 3:
{
float num = ((SKRect)(ref bounds)).Left + (((SKRect)(ref bounds)).Width - imageWidth) / 2f;
float num2 = ((SKRect)(ref bounds)).Top + (((SKRect)(ref bounds)).Height - imageHeight) / 2f;
return new SKRect(num, num2, num + imageWidth, num2 + imageHeight);
}
default:
return bounds;
}
}
Invalidate();
}
public async Task LoadFromFileAsync(string filePath)
{
_isLoading = true;
Invalidate();
Console.WriteLine($"[SkiaImage] LoadFromFileAsync: {filePath}, WidthRequest={WidthRequest}, HeightRequest={HeightRequest}");
try
{
List<string> list = new List<string>
{
filePath,
Path.Combine(AppContext.BaseDirectory, filePath),
Path.Combine(AppContext.BaseDirectory, "Resources", "Images", filePath),
Path.Combine(AppContext.BaseDirectory, "Resources", filePath)
};
if (filePath.EndsWith(".png", StringComparison.OrdinalIgnoreCase))
{
string text = Path.ChangeExtension(filePath, ".svg");
list.Add(text);
list.Add(Path.Combine(AppContext.BaseDirectory, text));
list.Add(Path.Combine(AppContext.BaseDirectory, "Resources", "Images", text));
list.Add(Path.Combine(AppContext.BaseDirectory, "Resources", text));
}
string foundPath = null;
foreach (string item in list)
{
if (File.Exists(item))
{
foundPath = item;
Console.WriteLine("[SkiaImage] Found file at: " + item);
break;
}
}
if (foundPath == null)
{
Console.WriteLine("[SkiaImage] File not found: " + filePath);
_isLoading = false;
_isSvg = false;
_currentFilePath = null;
this.ImageLoadingError?.Invoke(this, new ImageLoadingErrorEventArgs(new FileNotFoundException(filePath)));
return;
}
_isSvg = foundPath.EndsWith(".svg", StringComparison.OrdinalIgnoreCase);
_currentFilePath = foundPath;
if (!_isSvg)
{
await Task.Run(delegate
{
using FileStream fileStream = File.OpenRead(foundPath);
SKBitmap val = SKBitmap.Decode((Stream)fileStream);
if (val != null)
{
Bitmap = val;
Console.WriteLine("[SkiaImage] Loaded image: " + foundPath);
}
});
}
else
{
await LoadSvgAtSizeAsync(foundPath, WidthRequest, HeightRequest);
}
_isLoading = false;
this.ImageLoaded?.Invoke(this, EventArgs.Empty);
}
catch (Exception exception)
{
_isLoading = false;
this.ImageLoadingError?.Invoke(this, new ImageLoadingErrorEventArgs(exception));
}
Invalidate();
}
public async Task LoadFromUriAsync(Uri uri)
{
_isLoading = true;
Invalidate();
private async Task LoadSvgAtSizeAsync(string svgPath, double targetWidth, double targetHeight)
{
_loadCts?.Cancel();
CancellationTokenSource cts = new CancellationTokenSource();
_loadCts = cts;
try
{
SKBitmap newBitmap = null;
await Task.Run(delegate
{
//IL_0016: Unknown result type (might be due to invalid IL or missing references)
//IL_001c: Expected O, but got Unknown
//IL_0052: Unknown result type (might be due to invalid IL or missing references)
//IL_0057: Unknown result type (might be due to invalid IL or missing references)
//IL_0109: Unknown result type (might be due to invalid IL or missing references)
//IL_0113: Expected O, but got Unknown
//IL_0119: Unknown result type (might be due to invalid IL or missing references)
//IL_0120: Expected O, but got Unknown
//IL_0122: Unknown result type (might be due to invalid IL or missing references)
if (cts.Token.IsCancellationRequested)
{
return;
}
SKSvg val = new SKSvg();
try
{
val.Load(svgPath);
if (val.Picture != null && !cts.Token.IsCancellationRequested)
{
SKRect cullRect = val.Picture.CullRect;
float num = ((targetWidth > 0.0) ? ((float)targetWidth) : ((((SKRect)(ref cullRect)).Width <= 24f) ? 24f : ((SKRect)(ref cullRect)).Width));
float num2 = Math.Min(val2: ((targetHeight > 0.0) ? ((float)targetHeight) : ((((SKRect)(ref cullRect)).Height <= 24f) ? 24f : ((SKRect)(ref cullRect)).Height)) / ((SKRect)(ref cullRect)).Height, val1: num / ((SKRect)(ref cullRect)).Width);
int num3 = Math.Max(1, (int)(((SKRect)(ref cullRect)).Width * num2));
int num4 = Math.Max(1, (int)(((SKRect)(ref cullRect)).Height * num2));
newBitmap = new SKBitmap(num3, num4, false);
SKCanvas val2 = new SKCanvas(newBitmap);
try
{
val2.Clear(SKColors.Transparent);
val2.Scale(num2);
val2.DrawPicture(val.Picture, (SKPaint)null);
Console.WriteLine($"[SkiaImage] Loaded SVG: {svgPath} at {num3}x{num4} (requested {targetWidth}x{targetHeight})");
return;
}
finally
{
((IDisposable)val2)?.Dispose();
}
}
}
finally
{
((IDisposable)val)?.Dispose();
}
}, cts.Token);
if (!cts.Token.IsCancellationRequested && newBitmap != null)
{
_svgLoadedWidth = ((targetWidth > 0.0) ? targetWidth : ((double)newBitmap.Width));
_svgLoadedHeight = ((targetHeight > 0.0) ? targetHeight : ((double)newBitmap.Height));
Bitmap = newBitmap;
return;
}
SKBitmap obj = newBitmap;
if (obj != null)
{
((SKNativeObject)obj).Dispose();
}
}
catch (OperationCanceledException)
{
}
}
try
{
using var httpClient = new HttpClient();
var data = await httpClient.GetByteArrayAsync(uri);
public async Task LoadFromStreamAsync(Stream stream)
{
_isLoading = true;
Invalidate();
try
{
await Task.Run(delegate
{
SKBitmap val = SKBitmap.Decode(stream);
if (val != null)
{
Bitmap = val;
}
});
_isLoading = false;
this.ImageLoaded?.Invoke(this, EventArgs.Empty);
}
catch (Exception exception)
{
_isLoading = false;
this.ImageLoadingError?.Invoke(this, new ImageLoadingErrorEventArgs(exception));
}
Invalidate();
}
using var stream = new MemoryStream(data);
var bitmap = SKBitmap.Decode(stream);
if (bitmap != null)
{
Bitmap = bitmap;
}
public async Task LoadFromUriAsync(Uri uri)
{
_isLoading = true;
Invalidate();
try
{
using HttpClient httpClient = new HttpClient();
using MemoryStream memoryStream = new MemoryStream(await httpClient.GetByteArrayAsync(uri));
SKBitmap val = SKBitmap.Decode((Stream)memoryStream);
if (val != null)
{
Bitmap = val;
}
_isLoading = false;
this.ImageLoaded?.Invoke(this, EventArgs.Empty);
}
catch (Exception exception)
{
_isLoading = false;
this.ImageLoadingError?.Invoke(this, new ImageLoadingErrorEventArgs(exception));
}
Invalidate();
}
_isLoading = false;
ImageLoaded?.Invoke(this, EventArgs.Empty);
}
catch (Exception ex)
{
_isLoading = false;
ImageLoadingError?.Invoke(this, new ImageLoadingErrorEventArgs(ex));
}
public void LoadFromData(byte[] data)
{
try
{
using MemoryStream memoryStream = new MemoryStream(data);
SKBitmap val = SKBitmap.Decode((Stream)memoryStream);
if (val != null)
{
Bitmap = val;
}
this.ImageLoaded?.Invoke(this, EventArgs.Empty);
}
catch (Exception exception)
{
this.ImageLoadingError?.Invoke(this, new ImageLoadingErrorEventArgs(exception));
}
}
Invalidate();
}
public void LoadFromBitmap(SKBitmap bitmap)
{
try
{
_isSvg = false;
_currentFilePath = null;
Bitmap = bitmap;
_isLoading = false;
this.ImageLoaded?.Invoke(this, EventArgs.Empty);
}
catch (Exception exception)
{
_isLoading = false;
this.ImageLoadingError?.Invoke(this, new ImageLoadingErrorEventArgs(exception));
}
Invalidate();
}
public void LoadFromData(byte[] data)
{
try
{
using var stream = new MemoryStream(data);
var bitmap = SKBitmap.Decode(stream);
if (bitmap != null)
{
Bitmap = bitmap;
}
ImageLoaded?.Invoke(this, EventArgs.Empty);
}
catch (Exception ex)
{
ImageLoadingError?.Invoke(this, new ImageLoadingErrorEventArgs(ex));
}
}
public override void Arrange(SKRect bounds)
{
//IL_0001: Unknown result type (might be due to invalid IL or missing references)
//IL_00c1: Unknown result type (might be due to invalid IL or missing references)
//IL_00c2: Unknown result type (might be due to invalid IL or missing references)
base.Arrange(bounds);
if ((!(base.WidthRequest > 0.0) || !(base.HeightRequest > 0.0)) && _isSvg && !string.IsNullOrEmpty(_currentFilePath) && !_isLoading)
{
float width = ((SKRect)(ref bounds)).Width;
float height = ((SKRect)(ref bounds)).Height;
if (((double)width > _svgLoadedWidth * 1.1 || (double)height > _svgLoadedHeight * 1.1) && width > 0f && height > 0f && (width != ((SKRect)(ref _lastArrangedBounds)).Width || height != ((SKRect)(ref _lastArrangedBounds)).Height))
{
_lastArrangedBounds = bounds;
Console.WriteLine($"[SkiaImage] Arrange detected larger bounds: {width}x{height} vs loaded {_svgLoadedWidth}x{_svgLoadedHeight}");
LoadSvgAtSizeAsync(_currentFilePath, width, height);
}
}
}
protected override SKSize MeasureOverride(SKSize availableSize)
{
if (_image == null)
return new SKSize(100, 100); // Default size
protected override SKSize MeasureOverride(SKSize availableSize)
{
//IL_002a: Unknown result type (might be due to invalid IL or missing references)
//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
//IL_0048: Unknown result type (might be due to invalid IL or missing references)
//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
//IL_006e: Unknown result type (might be due to invalid IL or missing references)
//IL_005e: Unknown result type (might be due to invalid IL or missing references)
//IL_0131: Unknown result type (might be due to invalid IL or missing references)
//IL_0107: Unknown result type (might be due to invalid IL or missing references)
//IL_0163: Unknown result type (might be due to invalid IL or missing references)
//IL_015b: Unknown result type (might be due to invalid IL or missing references)
double widthRequest = base.WidthRequest;
double heightRequest = base.HeightRequest;
if (widthRequest > 0.0 && heightRequest > 0.0)
{
return new SKSize((float)widthRequest, (float)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);
}
float num = _image.Width;
float num2 = _image.Height;
if (widthRequest > 0.0)
{
float num3 = (float)widthRequest / num;
return new SKSize((float)widthRequest, num2 * num3);
}
if (heightRequest > 0.0)
{
float num4 = (float)heightRequest / num2;
return new SKSize(num * num4, (float)heightRequest);
}
if (((SKSize)(ref availableSize)).Width < float.MaxValue && ((SKSize)(ref availableSize)).Height < float.MaxValue)
{
float num5 = Math.Min(((SKSize)(ref availableSize)).Width / num, ((SKSize)(ref availableSize)).Height / num2);
return new SKSize(num * num5, num2 * num5);
}
if (((SKSize)(ref availableSize)).Width < float.MaxValue)
{
float num6 = ((SKSize)(ref availableSize)).Width / num;
return new SKSize(((SKSize)(ref availableSize)).Width, num2 * num6);
}
if (((SKSize)(ref availableSize)).Height < float.MaxValue)
{
float num7 = ((SKSize)(ref availableSize)).Height / num2;
return new SKSize(num * num7, ((SKSize)(ref availableSize)).Height);
}
return new SKSize(num, num2);
}
var imageWidth = _image.Width;
var imageHeight = _image.Height;
// If we have constraints, respect them
if (availableSize.Width < float.MaxValue && availableSize.Height < float.MaxValue)
{
var scale = Math.Min(availableSize.Width / imageWidth, availableSize.Height / imageHeight);
return new SKSize(imageWidth * scale, imageHeight * scale);
}
else if (availableSize.Width < float.MaxValue)
{
var scale = availableSize.Width / imageWidth;
return new SKSize(availableSize.Width, imageHeight * scale);
}
else if (availableSize.Height < float.MaxValue)
{
var scale = availableSize.Height / imageHeight;
return new SKSize(imageWidth * scale, availableSize.Height);
}
return new SKSize(imageWidth, imageHeight);
}
protected override void Dispose(bool disposing)
{
if (disposing)
{
_bitmap?.Dispose();
_image?.Dispose();
}
base.Dispose(disposing);
}
}
/// <summary>
/// Event args for image loading errors.
/// </summary>
public class ImageLoadingErrorEventArgs : EventArgs
{
public Exception Exception { get; }
public ImageLoadingErrorEventArgs(Exception exception)
{
Exception = exception;
}
protected override void Dispose(bool disposing)
{
if (disposing)
{
SKBitmap? bitmap = _bitmap;
if (bitmap != null)
{
((SKNativeObject)bitmap).Dispose();
}
SKImage? image = _image;
if (image != null)
{
((SKNativeObject)image).Dispose();
}
}
base.Dispose(disposing);
}
}

View File

File diff suppressed because it is too large Load Diff

View File

@@ -1,316 +1,325 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System;
using SkiaSharp;
namespace Microsoft.Maui.Platform;
/// <summary>
/// A view that displays indicators for a collection of items.
/// Used to show page indicators for CarouselView or similar controls.
/// </summary>
public class SkiaIndicatorView : SkiaView
{
private int _count = 0;
private int _position = 0;
private int _count;
/// <summary>
/// Gets or sets the number of indicators to display.
/// </summary>
public int Count
{
get => _count;
set
{
if (_count != value)
{
_count = Math.Max(0, value);
if (_position >= _count)
{
_position = Math.Max(0, _count - 1);
}
InvalidateMeasure();
Invalidate();
}
}
}
private int _position;
/// <summary>
/// Gets or sets the selected position.
/// </summary>
public int Position
{
get => _position;
set
{
int newValue = Math.Clamp(value, 0, Math.Max(0, _count - 1));
if (_position != newValue)
{
_position = newValue;
Invalidate();
}
}
}
public int Count
{
get
{
return _count;
}
set
{
if (_count != value)
{
_count = Math.Max(0, value);
if (_position >= _count)
{
_position = Math.Max(0, _count - 1);
}
InvalidateMeasure();
Invalidate();
}
}
}
/// <summary>
/// Gets or sets the indicator color.
/// </summary>
public SKColor IndicatorColor { get; set; } = new SKColor(180, 180, 180);
public int Position
{
get
{
return _position;
}
set
{
int num = Math.Clamp(value, 0, Math.Max(0, _count - 1));
if (_position != num)
{
_position = num;
Invalidate();
}
}
}
/// <summary>
/// Gets or sets the selected indicator color.
/// </summary>
public SKColor SelectedIndicatorColor { get; set; } = new SKColor(33, 150, 243);
public SKColor IndicatorColor { get; set; } = new SKColor((byte)180, (byte)180, (byte)180);
/// <summary>
/// Gets or sets the indicator size.
/// </summary>
public float IndicatorSize { get; set; } = 10f;
public SKColor SelectedIndicatorColor { get; set; } = new SKColor((byte)33, (byte)150, (byte)243);
/// <summary>
/// Gets or sets the selected indicator size.
/// </summary>
public float SelectedIndicatorSize { get; set; } = 10f;
public float IndicatorSize { get; set; } = 10f;
/// <summary>
/// Gets or sets the spacing between indicators.
/// </summary>
public float IndicatorSpacing { get; set; } = 8f;
public float SelectedIndicatorSize { get; set; } = 10f;
/// <summary>
/// Gets or sets the indicator shape.
/// </summary>
public IndicatorShape IndicatorShape { get; set; } = IndicatorShape.Circle;
public float IndicatorSpacing { get; set; } = 8f;
/// <summary>
/// Gets or sets whether indicators should have a border.
/// </summary>
public bool ShowBorder { get; set; } = false;
public IndicatorShape IndicatorShape { get; set; }
/// <summary>
/// Gets or sets the border color.
/// </summary>
public SKColor BorderColor { get; set; } = new SKColor(100, 100, 100);
public bool ShowBorder { get; set; }
/// <summary>
/// Gets or sets the border width.
/// </summary>
public float BorderWidth { get; set; } = 1f;
public SKColor BorderColor { get; set; } = new SKColor((byte)100, (byte)100, (byte)100);
/// <summary>
/// Gets or sets the maximum visible indicators.
/// </summary>
public int MaximumVisible { get; set; } = 10;
public float BorderWidth { get; set; } = 1f;
/// <summary>
/// Gets or sets whether to hide indicators when count is 1 or less.
/// </summary>
public bool HideSingle { get; set; } = true;
public int MaximumVisible { get; set; } = 10;
protected override SKSize MeasureOverride(SKSize availableSize)
{
if (_count <= 0 || (HideSingle && _count <= 1))
{
return SKSize.Empty;
}
public bool HideSingle { get; set; } = true;
int visibleCount = Math.Min(_count, MaximumVisible);
float totalWidth = visibleCount * IndicatorSize + (visibleCount - 1) * IndicatorSpacing;
float height = Math.Max(IndicatorSize, SelectedIndicatorSize);
protected override SKSize MeasureOverride(SKSize availableSize)
{
//IL_001a: Unknown result type (might be due to invalid IL or missing references)
//IL_005a: Unknown result type (might be due to invalid IL or missing references)
if (_count <= 0 || (HideSingle && _count <= 1))
{
return SKSize.Empty;
}
int num = Math.Min(_count, MaximumVisible);
float num2 = (float)num * IndicatorSize + (float)(num - 1) * IndicatorSpacing;
float num3 = Math.Max(IndicatorSize, SelectedIndicatorSize);
return new SKSize(num2, num3);
}
return new SKSize(totalWidth, height);
}
protected override void OnDraw(SKCanvas canvas, SKRect bounds)
{
//IL_0024: Unknown result type (might be due to invalid IL or missing references)
//IL_0059: Unknown result type (might be due to invalid IL or missing references)
//IL_005e: Unknown result type (might be due to invalid IL or missing references)
//IL_007e: Unknown result type (might be due to invalid IL or missing references)
//IL_0083: Unknown result type (might be due to invalid IL or missing references)
//IL_00eb: Unknown result type (might be due to invalid IL or missing references)
//IL_00f0: Unknown result type (might be due to invalid IL or missing references)
//IL_00f2: Unknown result type (might be due to invalid IL or missing references)
//IL_00fc: Unknown result type (might be due to invalid IL or missing references)
//IL_0103: Unknown result type (might be due to invalid IL or missing references)
//IL_010c: Expected O, but got Unknown
//IL_010c: Unknown result type (might be due to invalid IL or missing references)
//IL_0111: Unknown result type (might be due to invalid IL or missing references)
//IL_0113: Unknown result type (might be due to invalid IL or missing references)
//IL_011d: Unknown result type (might be due to invalid IL or missing references)
//IL_0124: Unknown result type (might be due to invalid IL or missing references)
//IL_012d: Expected O, but got Unknown
//IL_012d: Unknown result type (might be due to invalid IL or missing references)
//IL_0132: Unknown result type (might be due to invalid IL or missing references)
//IL_0134: Unknown result type (might be due to invalid IL or missing references)
//IL_013e: Unknown result type (might be due to invalid IL or missing references)
//IL_0145: Unknown result type (might be due to invalid IL or missing references)
//IL_0151: Unknown result type (might be due to invalid IL or missing references)
//IL_015a: Expected O, but got Unknown
if (_count <= 0 || (HideSingle && _count <= 1))
{
return;
}
canvas.Save();
canvas.ClipRect(base.Bounds, (SKClipOperation)1, false);
int num = Math.Min(_count, MaximumVisible);
float num2 = (float)num * IndicatorSize + (float)(num - 1) * IndicatorSpacing;
SKRect bounds2 = base.Bounds;
float num3 = ((SKRect)(ref bounds2)).MidX - num2 / 2f + IndicatorSize / 2f;
bounds2 = base.Bounds;
float midY = ((SKRect)(ref bounds2)).MidY;
int num4 = 0;
int num5 = num;
if (_count > MaximumVisible)
{
int num6 = MaximumVisible / 2;
num4 = Math.Max(0, _position - num6);
num5 = Math.Min(_count, num4 + MaximumVisible);
if (num5 == _count)
{
num4 = _count - MaximumVisible;
}
}
SKPaint val = new SKPaint
{
Color = IndicatorColor,
Style = (SKPaintStyle)0,
IsAntialias = true
};
try
{
SKPaint val2 = new SKPaint
{
Color = SelectedIndicatorColor,
Style = (SKPaintStyle)0,
IsAntialias = true
};
try
{
SKPaint val3 = new SKPaint
{
Color = BorderColor,
Style = (SKPaintStyle)1,
StrokeWidth = BorderWidth,
IsAntialias = true
};
try
{
for (int i = num4; i < num5; i++)
{
int num7 = i - num4;
float x = num3 + (float)num7 * (IndicatorSize + IndicatorSpacing);
bool num8 = i == _position;
SKPaint fillPaint = (num8 ? val2 : val);
float size = (num8 ? SelectedIndicatorSize : IndicatorSize);
DrawIndicator(canvas, x, midY, size, fillPaint, val3);
}
canvas.Restore();
}
finally
{
((IDisposable)val3)?.Dispose();
}
}
finally
{
((IDisposable)val2)?.Dispose();
}
}
finally
{
((IDisposable)val)?.Dispose();
}
}
protected override void OnDraw(SKCanvas canvas, SKRect bounds)
{
if (_count <= 0 || (HideSingle && _count <= 1)) return;
private void DrawIndicator(SKCanvas canvas, float x, float y, float size, SKPaint fillPaint, SKPaint borderPaint)
{
//IL_005f: Unknown result type (might be due to invalid IL or missing references)
//IL_0098: Unknown result type (might be due to invalid IL or missing references)
//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
//IL_00bd: Expected O, but got Unknown
//IL_0073: Unknown result type (might be due to invalid IL or missing references)
//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
float num = size / 2f;
switch (IndicatorShape)
{
case IndicatorShape.Circle:
canvas.DrawCircle(x, y, num, fillPaint);
if (ShowBorder)
{
canvas.DrawCircle(x, y, num, borderPaint);
}
break;
case IndicatorShape.Square:
{
SKRect val3 = default(SKRect);
((SKRect)(ref val3))._002Ector(x - num, y - num, x + num, y + num);
canvas.DrawRect(val3, fillPaint);
if (ShowBorder)
{
canvas.DrawRect(val3, borderPaint);
}
break;
}
case IndicatorShape.RoundedSquare:
{
SKRect val2 = default(SKRect);
((SKRect)(ref val2))._002Ector(x - num, y - num, x + num, y + num);
float num2 = num * 0.3f;
canvas.DrawRoundRect(val2, num2, num2, fillPaint);
if (ShowBorder)
{
canvas.DrawRoundRect(val2, num2, num2, borderPaint);
}
break;
}
case IndicatorShape.Diamond:
{
SKPath val = new SKPath();
try
{
val.MoveTo(x, y - num);
val.LineTo(x + num, y);
val.LineTo(x, y + num);
val.LineTo(x - num, y);
val.Close();
canvas.DrawPath(val, fillPaint);
if (ShowBorder)
{
canvas.DrawPath(val, borderPaint);
}
break;
}
finally
{
((IDisposable)val)?.Dispose();
}
}
}
}
canvas.Save();
canvas.ClipRect(Bounds);
public override SkiaView? HitTest(float x, float y)
{
//IL_0009: Unknown result type (might be due to invalid IL or missing references)
//IL_000e: Unknown result type (might be due to invalid IL or missing references)
//IL_0051: Unknown result type (might be due to invalid IL or missing references)
//IL_0056: Unknown result type (might be due to invalid IL or missing references)
if (base.IsVisible)
{
SKRect bounds = base.Bounds;
if (((SKRect)(ref bounds)).Contains(x, y))
{
if (_count > 0)
{
int num = Math.Min(_count, MaximumVisible);
float num2 = (float)num * IndicatorSize + (float)(num - 1) * IndicatorSpacing;
bounds = base.Bounds;
float num3 = ((SKRect)(ref bounds)).MidX - num2 / 2f;
if (_count > MaximumVisible)
{
int num4 = MaximumVisible / 2;
if (Math.Max(0, _position - num4) + MaximumVisible > _count)
{
_ = _count;
_ = MaximumVisible;
}
}
for (int i = 0; i < num; i++)
{
float num5 = num3 + (float)i * (IndicatorSize + IndicatorSpacing);
if (x >= num5 && x <= num5 + IndicatorSize)
{
return this;
}
}
}
return null;
}
}
return null;
}
int visibleCount = Math.Min(_count, MaximumVisible);
float totalWidth = visibleCount * IndicatorSize + (visibleCount - 1) * IndicatorSpacing;
float startX = Bounds.MidX - totalWidth / 2 + IndicatorSize / 2;
float centerY = Bounds.MidY;
// Determine visible range if count > MaximumVisible
int startIndex = 0;
int endIndex = visibleCount;
if (_count > MaximumVisible)
{
int halfVisible = MaximumVisible / 2;
startIndex = Math.Max(0, _position - halfVisible);
endIndex = Math.Min(_count, startIndex + MaximumVisible);
if (endIndex == _count)
{
startIndex = _count - MaximumVisible;
}
}
using var normalPaint = new SKPaint
{
Color = IndicatorColor,
Style = SKPaintStyle.Fill,
IsAntialias = true
};
using var selectedPaint = new SKPaint
{
Color = SelectedIndicatorColor,
Style = SKPaintStyle.Fill,
IsAntialias = true
};
using var borderPaint = new SKPaint
{
Color = BorderColor,
Style = SKPaintStyle.Stroke,
StrokeWidth = BorderWidth,
IsAntialias = true
};
for (int i = startIndex; i < endIndex; i++)
{
int visualIndex = i - startIndex;
float x = startX + visualIndex * (IndicatorSize + IndicatorSpacing);
bool isSelected = i == _position;
var paint = isSelected ? selectedPaint : normalPaint;
float size = isSelected ? SelectedIndicatorSize : IndicatorSize;
DrawIndicator(canvas, x, centerY, size, paint, borderPaint);
}
canvas.Restore();
}
private void DrawIndicator(SKCanvas canvas, float x, float y, float size, SKPaint fillPaint, SKPaint borderPaint)
{
float radius = size / 2;
switch (IndicatorShape)
{
case IndicatorShape.Circle:
canvas.DrawCircle(x, y, radius, fillPaint);
if (ShowBorder)
{
canvas.DrawCircle(x, y, radius, borderPaint);
}
break;
case IndicatorShape.Square:
var rect = new SKRect(x - radius, y - radius, x + radius, y + radius);
canvas.DrawRect(rect, fillPaint);
if (ShowBorder)
{
canvas.DrawRect(rect, borderPaint);
}
break;
case IndicatorShape.RoundedSquare:
var roundRect = new SKRect(x - radius, y - radius, x + radius, y + radius);
float cornerRadius = radius * 0.3f;
canvas.DrawRoundRect(roundRect, cornerRadius, cornerRadius, fillPaint);
if (ShowBorder)
{
canvas.DrawRoundRect(roundRect, cornerRadius, cornerRadius, borderPaint);
}
break;
case IndicatorShape.Diamond:
using (var path = new SKPath())
{
path.MoveTo(x, y - radius);
path.LineTo(x + radius, y);
path.LineTo(x, y + radius);
path.LineTo(x - radius, y);
path.Close();
canvas.DrawPath(path, fillPaint);
if (ShowBorder)
{
canvas.DrawPath(path, borderPaint);
}
}
break;
}
}
public override SkiaView? HitTest(float x, float y)
{
if (!IsVisible || !Bounds.Contains(x, y)) return null;
// Check if click is on an indicator
if (_count > 0)
{
int visibleCount = Math.Min(_count, MaximumVisible);
float totalWidth = visibleCount * IndicatorSize + (visibleCount - 1) * IndicatorSpacing;
float startX = Bounds.MidX - totalWidth / 2;
int startIndex = 0;
if (_count > MaximumVisible)
{
int halfVisible = MaximumVisible / 2;
startIndex = Math.Max(0, _position - halfVisible);
if (startIndex + MaximumVisible > _count)
{
startIndex = _count - MaximumVisible;
}
}
for (int i = 0; i < visibleCount; i++)
{
float indicatorX = startX + i * (IndicatorSize + IndicatorSpacing);
if (x >= indicatorX && x <= indicatorX + IndicatorSize)
{
return this;
}
}
}
return null;
}
public override void OnPointerPressed(PointerEventArgs e)
{
if (!IsEnabled || _count <= 0) return;
// Calculate which indicator was clicked
int visibleCount = Math.Min(_count, MaximumVisible);
float totalWidth = visibleCount * IndicatorSize + (visibleCount - 1) * IndicatorSpacing;
float startX = Bounds.MidX - totalWidth / 2;
int startIndex = 0;
if (_count > MaximumVisible)
{
int halfVisible = MaximumVisible / 2;
startIndex = Math.Max(0, _position - halfVisible);
if (startIndex + MaximumVisible > _count)
{
startIndex = _count - MaximumVisible;
}
}
float relativeX = e.X - startX;
int visualIndex = (int)(relativeX / (IndicatorSize + IndicatorSpacing));
if (visualIndex >= 0 && visualIndex < visibleCount)
{
Position = startIndex + visualIndex;
e.Handled = true;
}
base.OnPointerPressed(e);
}
}
/// <summary>
/// Shape of indicator dots.
/// </summary>
public enum IndicatorShape
{
Circle,
Square,
RoundedSquare,
Diamond
public override void OnPointerPressed(PointerEventArgs e)
{
//IL_003b: Unknown result type (might be due to invalid IL or missing references)
//IL_0040: Unknown result type (might be due to invalid IL or missing references)
if (!base.IsEnabled || _count <= 0)
{
return;
}
int num = Math.Min(_count, MaximumVisible);
float num2 = (float)num * IndicatorSize + (float)(num - 1) * IndicatorSpacing;
SKRect bounds = base.Bounds;
float num3 = ((SKRect)(ref bounds)).MidX - num2 / 2f;
int num4 = 0;
if (_count > MaximumVisible)
{
int num5 = MaximumVisible / 2;
num4 = Math.Max(0, _position - num5);
if (num4 + MaximumVisible > _count)
{
num4 = _count - MaximumVisible;
}
}
int num6 = (int)((e.X - num3) / (IndicatorSize + IndicatorSpacing));
if (num6 >= 0 && num6 < num)
{
Position = num4 + num6;
e.Handled = true;
}
base.OnPointerPressed(e);
}
}

View File

File diff suppressed because it is too large Load Diff

View File

File diff suppressed because it is too large Load Diff

View File

File diff suppressed because it is too large Load Diff

View File

@@ -1,598 +1,335 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System;
using System.Collections.Generic;
using SkiaSharp;
namespace Microsoft.Maui.Platform;
/// <summary>
/// A horizontal menu bar control.
/// </summary>
public class SkiaMenuBar : SkiaView
{
private readonly List<MenuBarItem> _items = new();
private int _hoveredIndex = -1;
private int _openIndex = -1;
private SkiaMenuFlyout? _openFlyout;
private readonly List<MenuBarItem> _items = new List<MenuBarItem>();
/// <summary>
/// Gets the menu bar items.
/// </summary>
public IList<MenuBarItem> Items => _items;
private int _hoveredIndex = -1;
/// <summary>
/// Gets or sets the background color.
/// </summary>
public SKColor BackgroundColor { get; set; } = new SKColor(240, 240, 240);
private int _openIndex = -1;
/// <summary>
/// Gets or sets the text color.
/// </summary>
public SKColor TextColor { get; set; } = new SKColor(33, 33, 33);
private SkiaMenuFlyout? _openFlyout;
/// <summary>
/// Gets or sets the hover background color.
/// </summary>
public SKColor HoverBackgroundColor { get; set; } = new SKColor(220, 220, 220);
public IList<MenuBarItem> Items => _items;
/// <summary>
/// Gets or sets the active background color.
/// </summary>
public SKColor ActiveBackgroundColor { get; set; } = new SKColor(200, 200, 200);
public new SKColor BackgroundColor { get; set; } = new SKColor((byte)240, (byte)240, (byte)240);
/// <summary>
/// Gets or sets the bar height.
/// </summary>
public float BarHeight { get; set; } = 28f;
public SKColor TextColor { get; set; } = new SKColor((byte)33, (byte)33, (byte)33);
/// <summary>
/// Gets or sets the font size.
/// </summary>
public float FontSize { get; set; } = 13f;
public SKColor HoverBackgroundColor { get; set; } = new SKColor((byte)220, (byte)220, (byte)220);
/// <summary>
/// Gets or sets the item padding.
/// </summary>
public float ItemPadding { get; set; } = 12f;
public SKColor ActiveBackgroundColor { get; set; } = new SKColor((byte)200, (byte)200, (byte)200);
protected override SKSize MeasureOverride(SKSize availableSize)
{
return new SKSize(availableSize.Width, BarHeight);
}
public float BarHeight { get; set; } = 28f;
protected override void OnDraw(SKCanvas canvas, SKRect bounds)
{
canvas.Save();
public float FontSize { get; set; } = 13f;
// Draw background
using var bgPaint = new SKPaint
{
Color = BackgroundColor,
Style = SKPaintStyle.Fill
};
canvas.DrawRect(Bounds, bgPaint);
public float ItemPadding { get; set; } = 12f;
// Draw bottom border
using var borderPaint = new SKPaint
{
Color = new SKColor(200, 200, 200),
Style = SKPaintStyle.Stroke,
StrokeWidth = 1
};
canvas.DrawLine(Bounds.Left, Bounds.Bottom, Bounds.Right, Bounds.Bottom, borderPaint);
protected override SKSize MeasureOverride(SKSize availableSize)
{
//IL_000d: Unknown result type (might be due to invalid IL or missing references)
return new SKSize(((SKSize)(ref availableSize)).Width, BarHeight);
}
// Draw menu items
using var textPaint = new SKPaint
{
Color = TextColor,
TextSize = FontSize,
IsAntialias = true
};
protected override void OnDraw(SKCanvas canvas, SKRect bounds)
{
//IL_0007: Unknown result type (might be due to invalid IL or missing references)
//IL_000c: Unknown result type (might be due to invalid IL or missing references)
//IL_000e: Unknown result type (might be due to invalid IL or missing references)
//IL_0018: Unknown result type (might be due to invalid IL or missing references)
//IL_0020: Expected O, but got Unknown
//IL_0022: Unknown result type (might be due to invalid IL or missing references)
//IL_002d: Unknown result type (might be due to invalid IL or missing references)
//IL_0032: Unknown result type (might be due to invalid IL or missing references)
//IL_0042: Unknown result type (might be due to invalid IL or missing references)
//IL_004c: Unknown result type (might be due to invalid IL or missing references)
//IL_0053: Unknown result type (might be due to invalid IL or missing references)
//IL_005f: Expected O, but got Unknown
//IL_0061: Unknown result type (might be due to invalid IL or missing references)
//IL_0066: Unknown result type (might be due to invalid IL or missing references)
//IL_0070: Unknown result type (might be due to invalid IL or missing references)
//IL_0075: Unknown result type (might be due to invalid IL or missing references)
//IL_007f: Unknown result type (might be due to invalid IL or missing references)
//IL_0084: Unknown result type (might be due to invalid IL or missing references)
//IL_008e: Unknown result type (might be due to invalid IL or missing references)
//IL_0093: Unknown result type (might be due to invalid IL or missing references)
//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
//IL_00c7: Expected O, but got Unknown
//IL_00c8: Unknown result type (might be due to invalid IL or missing references)
//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
//IL_00f0: Unknown result type (might be due to invalid IL or missing references)
//IL_0120: Unknown result type (might be due to invalid IL or missing references)
//IL_0125: Unknown result type (might be due to invalid IL or missing references)
//IL_0133: Unknown result type (might be due to invalid IL or missing references)
//IL_0138: Unknown result type (might be due to invalid IL or missing references)
//IL_0150: Unknown result type (might be due to invalid IL or missing references)
//IL_0155: Unknown result type (might be due to invalid IL or missing references)
//IL_0157: Unknown result type (might be due to invalid IL or missing references)
//IL_0161: Unknown result type (might be due to invalid IL or missing references)
//IL_016a: Expected O, but got Unknown
//IL_01c9: Unknown result type (might be due to invalid IL or missing references)
//IL_01ce: Unknown result type (might be due to invalid IL or missing references)
//IL_01f5: Unknown result type (might be due to invalid IL or missing references)
//IL_018c: Unknown result type (might be due to invalid IL or missing references)
//IL_0191: Unknown result type (might be due to invalid IL or missing references)
//IL_0193: Unknown result type (might be due to invalid IL or missing references)
//IL_019d: Unknown result type (might be due to invalid IL or missing references)
//IL_01a6: Expected O, but got Unknown
//IL_016b: Unknown result type (might be due to invalid IL or missing references)
//IL_01a7: Unknown result type (might be due to invalid IL or missing references)
canvas.Save();
SKPaint val = new SKPaint
{
Color = BackgroundColor,
Style = (SKPaintStyle)0
};
try
{
canvas.DrawRect(base.Bounds, val);
SKPaint val2 = new SKPaint
{
Color = new SKColor((byte)200, (byte)200, (byte)200),
Style = (SKPaintStyle)1,
StrokeWidth = 1f
};
try
{
SKRect bounds2 = base.Bounds;
float left = ((SKRect)(ref bounds2)).Left;
bounds2 = base.Bounds;
float bottom = ((SKRect)(ref bounds2)).Bottom;
bounds2 = base.Bounds;
float right = ((SKRect)(ref bounds2)).Right;
bounds2 = base.Bounds;
canvas.DrawLine(left, bottom, right, ((SKRect)(ref bounds2)).Bottom, val2);
SKPaint val3 = new SKPaint
{
Color = TextColor,
TextSize = FontSize,
IsAntialias = true
};
try
{
bounds2 = base.Bounds;
float num = ((SKRect)(ref bounds2)).Left;
SKRect val5 = default(SKRect);
for (int i = 0; i < _items.Count; i++)
{
MenuBarItem menuBarItem = _items[i];
SKRect val4 = default(SKRect);
val3.MeasureText(menuBarItem.Text, ref val4);
float num2 = ((SKRect)(ref val4)).Width + ItemPadding * 2f;
float num3 = num;
bounds2 = base.Bounds;
float top = ((SKRect)(ref bounds2)).Top;
float num4 = num + num2;
bounds2 = base.Bounds;
((SKRect)(ref val5))._002Ector(num3, top, num4, ((SKRect)(ref bounds2)).Bottom);
if (i == _openIndex)
{
SKPaint val6 = new SKPaint
{
Color = ActiveBackgroundColor,
Style = (SKPaintStyle)0
};
try
{
canvas.DrawRect(val5, val6);
}
finally
{
((IDisposable)val6)?.Dispose();
}
}
else if (i == _hoveredIndex)
{
SKPaint val7 = new SKPaint
{
Color = HoverBackgroundColor,
Style = (SKPaintStyle)0
};
try
{
canvas.DrawRect(val5, val7);
}
finally
{
((IDisposable)val7)?.Dispose();
}
}
float num5 = num + ItemPadding;
bounds2 = base.Bounds;
float num6 = ((SKRect)(ref bounds2)).MidY - ((SKRect)(ref val4)).MidY;
canvas.DrawText(menuBarItem.Text, num5, num6, val3);
menuBarItem.Bounds = val5;
num += num2;
}
_openFlyout?.Draw(canvas);
canvas.Restore();
}
finally
{
((IDisposable)val3)?.Dispose();
}
}
finally
{
((IDisposable)val2)?.Dispose();
}
}
finally
{
((IDisposable)val)?.Dispose();
}
}
float x = Bounds.Left;
public override SkiaView? HitTest(float x, float y)
{
//IL_0026: Unknown result type (might be due to invalid IL or missing references)
//IL_002b: Unknown result type (might be due to invalid IL or missing references)
if (!base.IsVisible)
{
return null;
}
if (_openFlyout != null)
{
SkiaView skiaView = _openFlyout.HitTest(x, y);
if (skiaView != null)
{
return skiaView;
}
}
SKRect bounds = base.Bounds;
if (((SKRect)(ref bounds)).Contains(x, y))
{
return this;
}
if (_openFlyout != null)
{
CloseFlyout();
}
return null;
}
for (int i = 0; i < _items.Count; i++)
{
var item = _items[i];
var textBounds = new SKRect();
textPaint.MeasureText(item.Text, ref textBounds);
public override void OnPointerMoved(PointerEventArgs e)
{
//IL_001b: Unknown result type (might be due to invalid IL or missing references)
//IL_0020: Unknown result type (might be due to invalid IL or missing references)
if (!base.IsEnabled)
{
return;
}
int num = -1;
for (int i = 0; i < _items.Count; i++)
{
SKRect bounds = _items[i].Bounds;
if (((SKRect)(ref bounds)).Contains(e.X, e.Y))
{
num = i;
break;
}
}
if (num != _hoveredIndex)
{
_hoveredIndex = num;
if (_openIndex >= 0 && num >= 0 && num != _openIndex)
{
OpenFlyout(num);
}
Invalidate();
}
base.OnPointerMoved(e);
}
float itemWidth = textBounds.Width + ItemPadding * 2;
var itemBounds = new SKRect(x, Bounds.Top, x + itemWidth, Bounds.Bottom);
public override void OnPointerPressed(PointerEventArgs e)
{
//IL_003c: Unknown result type (might be due to invalid IL or missing references)
//IL_0041: Unknown result type (might be due to invalid IL or missing references)
if (!base.IsEnabled)
{
return;
}
if (_openFlyout != null)
{
_openFlyout.OnPointerPressed(e);
if (e.Handled)
{
CloseFlyout();
return;
}
}
for (int i = 0; i < _items.Count; i++)
{
SKRect bounds = _items[i].Bounds;
if (((SKRect)(ref bounds)).Contains(e.X, e.Y))
{
if (_openIndex == i)
{
CloseFlyout();
}
else
{
OpenFlyout(i);
}
e.Handled = true;
return;
}
}
if (_openFlyout != null)
{
CloseFlyout();
e.Handled = true;
}
base.OnPointerPressed(e);
}
// Draw item background
if (i == _openIndex)
{
using var activePaint = new SKPaint { Color = ActiveBackgroundColor, Style = SKPaintStyle.Fill };
canvas.DrawRect(itemBounds, activePaint);
}
else if (i == _hoveredIndex)
{
using var hoverPaint = new SKPaint { Color = HoverBackgroundColor, Style = SKPaintStyle.Fill };
canvas.DrawRect(itemBounds, hoverPaint);
}
private void OpenFlyout(int index)
{
//IL_003f: Unknown result type (might be due to invalid IL or missing references)
//IL_0044: Unknown result type (might be due to invalid IL or missing references)
//IL_004e: Unknown result type (might be due to invalid IL or missing references)
//IL_0053: Unknown result type (might be due to invalid IL or missing references)
//IL_0064: Unknown result type (might be due to invalid IL or missing references)
if (index >= 0 && index < _items.Count)
{
MenuBarItem menuBarItem = _items[index];
_openIndex = index;
_openFlyout = new SkiaMenuFlyout
{
Items = menuBarItem.Items
};
SKRect bounds = menuBarItem.Bounds;
float left = ((SKRect)(ref bounds)).Left;
bounds = menuBarItem.Bounds;
float bottom = ((SKRect)(ref bounds)).Bottom;
_openFlyout.Position = new SKPoint(left, bottom);
_openFlyout.ItemClicked += OnFlyoutItemClicked;
Invalidate();
}
}
// Draw text
float textX = x + ItemPadding;
float textY = Bounds.MidY - textBounds.MidY;
canvas.DrawText(item.Text, textX, textY, textPaint);
private void CloseFlyout()
{
if (_openFlyout != null)
{
_openFlyout.ItemClicked -= OnFlyoutItemClicked;
_openFlyout = null;
}
_openIndex = -1;
Invalidate();
}
item.Bounds = itemBounds;
x += itemWidth;
}
// Draw open flyout
_openFlyout?.Draw(canvas);
canvas.Restore();
}
public override SkiaView? HitTest(float x, float y)
{
if (!IsVisible) return null;
// Check flyout first
if (_openFlyout != null)
{
var flyoutHit = _openFlyout.HitTest(x, y);
if (flyoutHit != null) return flyoutHit;
}
if (Bounds.Contains(x, y))
{
return this;
}
// Close flyout if clicking outside
if (_openFlyout != null)
{
CloseFlyout();
}
return null;
}
public override void OnPointerMoved(PointerEventArgs e)
{
if (!IsEnabled) return;
int newHovered = -1;
for (int i = 0; i < _items.Count; i++)
{
if (_items[i].Bounds.Contains(e.X, e.Y))
{
newHovered = i;
break;
}
}
if (newHovered != _hoveredIndex)
{
_hoveredIndex = newHovered;
// If a menu is open and we hover another item, open that one
if (_openIndex >= 0 && newHovered >= 0 && newHovered != _openIndex)
{
OpenFlyout(newHovered);
}
Invalidate();
}
base.OnPointerMoved(e);
}
public override void OnPointerPressed(PointerEventArgs e)
{
if (!IsEnabled) return;
// Check if clicking on flyout
if (_openFlyout != null)
{
_openFlyout.OnPointerPressed(e);
if (e.Handled)
{
CloseFlyout();
return;
}
}
// Check menu bar items
for (int i = 0; i < _items.Count; i++)
{
if (_items[i].Bounds.Contains(e.X, e.Y))
{
if (_openIndex == i)
{
CloseFlyout();
}
else
{
OpenFlyout(i);
}
e.Handled = true;
return;
}
}
// Click outside - close flyout
if (_openFlyout != null)
{
CloseFlyout();
e.Handled = true;
}
base.OnPointerPressed(e);
}
private void OpenFlyout(int index)
{
if (index < 0 || index >= _items.Count) return;
var item = _items[index];
_openIndex = index;
_openFlyout = new SkiaMenuFlyout
{
Items = item.Items
};
// Position below the menu item
float x = item.Bounds.Left;
float y = item.Bounds.Bottom;
_openFlyout.Position = new SKPoint(x, y);
_openFlyout.ItemClicked += OnFlyoutItemClicked;
Invalidate();
}
private void CloseFlyout()
{
if (_openFlyout != null)
{
_openFlyout.ItemClicked -= OnFlyoutItemClicked;
_openFlyout = null;
}
_openIndex = -1;
Invalidate();
}
private void OnFlyoutItemClicked(object? sender, MenuItemClickedEventArgs e)
{
CloseFlyout();
}
}
/// <summary>
/// Represents a top-level menu bar item.
/// </summary>
public class MenuBarItem
{
/// <summary>
/// Gets or sets the display text.
/// </summary>
public string Text { get; set; } = string.Empty;
/// <summary>
/// Gets the menu items.
/// </summary>
public List<MenuItem> Items { get; } = new();
/// <summary>
/// Gets or sets the bounds (set during rendering).
/// </summary>
internal SKRect Bounds { get; set; }
}
/// <summary>
/// Represents a menu item.
/// </summary>
public class MenuItem
{
/// <summary>
/// Gets or sets the display text.
/// </summary>
public string Text { get; set; } = string.Empty;
/// <summary>
/// Gets or sets the keyboard shortcut text.
/// </summary>
public string? Shortcut { get; set; }
/// <summary>
/// Gets or sets whether this is a separator.
/// </summary>
public bool IsSeparator { get; set; }
/// <summary>
/// Gets or sets whether this item is enabled.
/// </summary>
public bool IsEnabled { get; set; } = true;
/// <summary>
/// Gets or sets whether this item is checked.
/// </summary>
public bool IsChecked { get; set; }
/// <summary>
/// Gets or sets the icon source.
/// </summary>
public string? IconSource { get; set; }
/// <summary>
/// Gets the sub-menu items.
/// </summary>
public List<MenuItem> SubItems { get; } = new();
/// <summary>
/// Event raised when the item is clicked.
/// </summary>
public event EventHandler? Clicked;
internal void OnClicked()
{
Clicked?.Invoke(this, EventArgs.Empty);
}
}
/// <summary>
/// A dropdown menu flyout.
/// </summary>
public class SkiaMenuFlyout : SkiaView
{
private int _hoveredIndex = -1;
private SKRect _bounds;
/// <summary>
/// Gets or sets the menu items.
/// </summary>
public List<MenuItem> Items { get; set; } = new();
/// <summary>
/// Gets or sets the position.
/// </summary>
public SKPoint Position { get; set; }
/// <summary>
/// Gets or sets the background color.
/// </summary>
public SKColor BackgroundColor { get; set; } = SKColors.White;
/// <summary>
/// Gets or sets the text color.
/// </summary>
public SKColor TextColor { get; set; } = new SKColor(33, 33, 33);
/// <summary>
/// Gets or sets the disabled text color.
/// </summary>
public SKColor DisabledTextColor { get; set; } = new SKColor(160, 160, 160);
/// <summary>
/// Gets or sets the hover background color.
/// </summary>
public SKColor HoverBackgroundColor { get; set; } = new SKColor(230, 230, 230);
/// <summary>
/// Gets or sets the separator color.
/// </summary>
public SKColor SeparatorColor { get; set; } = new SKColor(220, 220, 220);
/// <summary>
/// Gets or sets the font size.
/// </summary>
public float FontSize { get; set; } = 13f;
/// <summary>
/// Gets or sets the item height.
/// </summary>
public float ItemHeight { get; set; } = 28f;
/// <summary>
/// Gets or sets the separator height.
/// </summary>
public float SeparatorHeight { get; set; } = 9f;
/// <summary>
/// Gets or sets the minimum width.
/// </summary>
public float MinWidth { get; set; } = 180f;
/// <summary>
/// Event raised when an item is clicked.
/// </summary>
public event EventHandler<MenuItemClickedEventArgs>? ItemClicked;
protected override void OnDraw(SKCanvas canvas, SKRect bounds)
{
if (Items.Count == 0) return;
// Calculate bounds
float width = MinWidth;
float height = 0;
using var textPaint = new SKPaint
{
TextSize = FontSize,
IsAntialias = true
};
foreach (var item in Items)
{
if (item.IsSeparator)
{
height += SeparatorHeight;
}
else
{
height += ItemHeight;
var textBounds = new SKRect();
textPaint.MeasureText(item.Text, ref textBounds);
float itemWidth = textBounds.Width + 50; // Padding + icon space
if (!string.IsNullOrEmpty(item.Shortcut))
{
textPaint.MeasureText(item.Shortcut, ref textBounds);
itemWidth += textBounds.Width + 20;
}
width = Math.Max(width, itemWidth);
}
}
_bounds = new SKRect(Position.X, Position.Y, Position.X + width, Position.Y + height);
// Draw shadow
using var shadowPaint = new SKPaint
{
ImageFilter = SKImageFilter.CreateDropShadow(0, 2, 8, 8, new SKColor(0, 0, 0, 40))
};
canvas.DrawRect(_bounds, shadowPaint);
// Draw background
using var bgPaint = new SKPaint
{
Color = BackgroundColor,
Style = SKPaintStyle.Fill
};
canvas.DrawRect(_bounds, bgPaint);
// Draw border
using var borderPaint = new SKPaint
{
Color = new SKColor(200, 200, 200),
Style = SKPaintStyle.Stroke,
StrokeWidth = 1
};
canvas.DrawRect(_bounds, borderPaint);
// Draw items
float y = _bounds.Top;
textPaint.Color = TextColor;
for (int i = 0; i < Items.Count; i++)
{
var item = Items[i];
if (item.IsSeparator)
{
float separatorY = y + SeparatorHeight / 2;
using var sepPaint = new SKPaint { Color = SeparatorColor, StrokeWidth = 1 };
canvas.DrawLine(_bounds.Left + 8, separatorY, _bounds.Right - 8, separatorY, sepPaint);
y += SeparatorHeight;
}
else
{
var itemBounds = new SKRect(_bounds.Left, y, _bounds.Right, y + ItemHeight);
// Draw hover background
if (i == _hoveredIndex && item.IsEnabled)
{
using var hoverPaint = new SKPaint { Color = HoverBackgroundColor, Style = SKPaintStyle.Fill };
canvas.DrawRect(itemBounds, hoverPaint);
}
// Draw check mark
if (item.IsChecked)
{
using var checkPaint = new SKPaint
{
Color = item.IsEnabled ? TextColor : DisabledTextColor,
TextSize = FontSize,
IsAntialias = true
};
canvas.DrawText("✓", _bounds.Left + 8, y + ItemHeight / 2 + 5, checkPaint);
}
// Draw text
textPaint.Color = item.IsEnabled ? TextColor : DisabledTextColor;
canvas.DrawText(item.Text, _bounds.Left + 28, y + ItemHeight / 2 + 5, textPaint);
// Draw shortcut
if (!string.IsNullOrEmpty(item.Shortcut))
{
textPaint.Color = DisabledTextColor;
var shortcutBounds = new SKRect();
textPaint.MeasureText(item.Shortcut, ref shortcutBounds);
canvas.DrawText(item.Shortcut, _bounds.Right - shortcutBounds.Width - 12, y + ItemHeight / 2 + 5, textPaint);
}
// Draw submenu arrow
if (item.SubItems.Count > 0)
{
canvas.DrawText("▸", _bounds.Right - 16, y + ItemHeight / 2 + 5, textPaint);
}
y += ItemHeight;
}
}
}
public override SkiaView? HitTest(float x, float y)
{
if (_bounds.Contains(x, y))
{
return this;
}
return null;
}
public override void OnPointerMoved(PointerEventArgs e)
{
if (!_bounds.Contains(e.X, e.Y))
{
_hoveredIndex = -1;
Invalidate();
return;
}
float y = _bounds.Top;
int newHovered = -1;
for (int i = 0; i < Items.Count; i++)
{
var item = Items[i];
float itemHeight = item.IsSeparator ? SeparatorHeight : ItemHeight;
if (e.Y >= y && e.Y < y + itemHeight && !item.IsSeparator)
{
newHovered = i;
break;
}
y += itemHeight;
}
if (newHovered != _hoveredIndex)
{
_hoveredIndex = newHovered;
Invalidate();
}
}
public override void OnPointerPressed(PointerEventArgs e)
{
if (_hoveredIndex >= 0 && _hoveredIndex < Items.Count)
{
var item = Items[_hoveredIndex];
if (item.IsEnabled && !item.IsSeparator)
{
item.OnClicked();
ItemClicked?.Invoke(this, new MenuItemClickedEventArgs(item));
e.Handled = true;
}
}
}
}
/// <summary>
/// Event args for menu item clicked.
/// </summary>
public class MenuItemClickedEventArgs : EventArgs
{
public MenuItem Item { get; }
public MenuItemClickedEventArgs(MenuItem item)
{
Item = item;
}
private void OnFlyoutItemClicked(object? sender, MenuItemClickedEventArgs e)
{
CloseFlyout();
}
}

304
Views/SkiaMenuFlyout.cs Normal file
View File

@@ -0,0 +1,304 @@
using System;
using System.Collections.Generic;
using SkiaSharp;
namespace Microsoft.Maui.Platform;
public class SkiaMenuFlyout : SkiaView
{
private int _hoveredIndex = -1;
private SKRect _bounds;
public List<MenuItem> Items { get; set; } = new List<MenuItem>();
public SKPoint Position { get; set; }
public new SKColor BackgroundColor { get; set; } = SKColors.White;
public SKColor TextColor { get; set; } = new SKColor((byte)33, (byte)33, (byte)33);
public SKColor DisabledTextColor { get; set; } = new SKColor((byte)160, (byte)160, (byte)160);
public SKColor HoverBackgroundColor { get; set; } = new SKColor((byte)230, (byte)230, (byte)230);
public SKColor SeparatorColor { get; set; } = new SKColor((byte)220, (byte)220, (byte)220);
public float FontSize { get; set; } = 13f;
public float ItemHeight { get; set; } = 28f;
public float SeparatorHeight { get; set; } = 9f;
public float MinWidth { get; set; } = 180f;
public event EventHandler<MenuItemClickedEventArgs>? ItemClicked;
protected override void OnDraw(SKCanvas canvas, SKRect bounds)
{
//IL_001b: Unknown result type (might be due to invalid IL or missing references)
//IL_0020: Unknown result type (might be due to invalid IL or missing references)
//IL_002c: Unknown result type (might be due to invalid IL or missing references)
//IL_0034: Expected O, but got Unknown
//IL_006e: Unknown result type (might be due to invalid IL or missing references)
//IL_00ea: Unknown result type (might be due to invalid IL or missing references)
//IL_00ef: Unknown result type (might be due to invalid IL or missing references)
//IL_00f9: Unknown result type (might be due to invalid IL or missing references)
//IL_00fe: Unknown result type (might be due to invalid IL or missing references)
//IL_0108: Unknown result type (might be due to invalid IL or missing references)
//IL_010d: Unknown result type (might be due to invalid IL or missing references)
//IL_0119: Unknown result type (might be due to invalid IL or missing references)
//IL_011e: Unknown result type (might be due to invalid IL or missing references)
//IL_0129: Unknown result type (might be due to invalid IL or missing references)
//IL_012e: Unknown result type (might be due to invalid IL or missing references)
//IL_0133: Unknown result type (might be due to invalid IL or missing references)
//IL_0138: Unknown result type (might be due to invalid IL or missing references)
//IL_0152: Unknown result type (might be due to invalid IL or missing references)
//IL_0162: Expected O, but got Unknown
//IL_0164: Unknown result type (might be due to invalid IL or missing references)
//IL_016f: Unknown result type (might be due to invalid IL or missing references)
//IL_0174: Unknown result type (might be due to invalid IL or missing references)
//IL_0176: Unknown result type (might be due to invalid IL or missing references)
//IL_0180: Unknown result type (might be due to invalid IL or missing references)
//IL_0189: Expected O, but got Unknown
//IL_018b: Unknown result type (might be due to invalid IL or missing references)
//IL_0197: Unknown result type (might be due to invalid IL or missing references)
//IL_019c: Unknown result type (might be due to invalid IL or missing references)
//IL_01ac: Unknown result type (might be due to invalid IL or missing references)
//IL_01b6: Unknown result type (might be due to invalid IL or missing references)
//IL_01bd: Unknown result type (might be due to invalid IL or missing references)
//IL_01ca: Expected O, but got Unknown
//IL_01cc: Unknown result type (might be due to invalid IL or missing references)
//IL_01e7: Unknown result type (might be due to invalid IL or missing references)
//IL_0222: Unknown result type (might be due to invalid IL or missing references)
//IL_0227: Unknown result type (might be due to invalid IL or missing references)
//IL_0229: Unknown result type (might be due to invalid IL or missing references)
//IL_0233: Unknown result type (might be due to invalid IL or missing references)
//IL_0240: Expected O, but got Unknown
//IL_0300: Unknown result type (might be due to invalid IL or missing references)
//IL_0305: Unknown result type (might be due to invalid IL or missing references)
//IL_02c5: Unknown result type (might be due to invalid IL or missing references)
//IL_02ca: Unknown result type (might be due to invalid IL or missing references)
//IL_02cc: Unknown result type (might be due to invalid IL or missing references)
//IL_02d6: Unknown result type (might be due to invalid IL or missing references)
//IL_02df: Expected O, but got Unknown
//IL_038b: Unknown result type (might be due to invalid IL or missing references)
//IL_0383: Unknown result type (might be due to invalid IL or missing references)
//IL_0318: Unknown result type (might be due to invalid IL or missing references)
//IL_0310: Unknown result type (might be due to invalid IL or missing references)
//IL_02e0: Unknown result type (might be due to invalid IL or missing references)
//IL_0322: Unknown result type (might be due to invalid IL or missing references)
//IL_032e: Unknown result type (might be due to invalid IL or missing references)
//IL_0337: Expected O, but got Unknown
//IL_03d9: Unknown result type (might be due to invalid IL or missing references)
//IL_03e5: Unknown result type (might be due to invalid IL or missing references)
if (Items.Count == 0)
{
return;
}
float num = MinWidth;
float num2 = 0f;
SKPaint val = new SKPaint
{
TextSize = FontSize,
IsAntialias = true
};
try
{
foreach (MenuItem item in Items)
{
if (item.IsSeparator)
{
num2 += SeparatorHeight;
continue;
}
num2 += ItemHeight;
SKRect val2 = default(SKRect);
val.MeasureText(item.Text, ref val2);
float num3 = ((SKRect)(ref val2)).Width + 50f;
if (!string.IsNullOrEmpty(item.Shortcut))
{
val.MeasureText(item.Shortcut, ref val2);
num3 += ((SKRect)(ref val2)).Width + 20f;
}
num = Math.Max(num, num3);
}
SKPoint position = Position;
float x = ((SKPoint)(ref position)).X;
position = Position;
float y = ((SKPoint)(ref position)).Y;
position = Position;
float num4 = ((SKPoint)(ref position)).X + num;
position = Position;
_bounds = new SKRect(x, y, num4, ((SKPoint)(ref position)).Y + num2);
SKPaint val3 = new SKPaint
{
ImageFilter = SKImageFilter.CreateDropShadow(0f, 2f, 8f, 8f, new SKColor((byte)0, (byte)0, (byte)0, (byte)40))
};
try
{
canvas.DrawRect(_bounds, val3);
SKPaint val4 = new SKPaint
{
Color = BackgroundColor,
Style = (SKPaintStyle)0
};
try
{
canvas.DrawRect(_bounds, val4);
SKPaint val5 = new SKPaint
{
Color = new SKColor((byte)200, (byte)200, (byte)200),
Style = (SKPaintStyle)1,
StrokeWidth = 1f
};
try
{
canvas.DrawRect(_bounds, val5);
float num5 = ((SKRect)(ref _bounds)).Top;
val.Color = TextColor;
SKRect val7 = default(SKRect);
for (int i = 0; i < Items.Count; i++)
{
MenuItem menuItem = Items[i];
if (menuItem.IsSeparator)
{
float num6 = num5 + SeparatorHeight / 2f;
SKPaint val6 = new SKPaint
{
Color = SeparatorColor,
StrokeWidth = 1f
};
try
{
canvas.DrawLine(((SKRect)(ref _bounds)).Left + 8f, num6, ((SKRect)(ref _bounds)).Right - 8f, num6, val6);
num5 += SeparatorHeight;
}
finally
{
((IDisposable)val6)?.Dispose();
}
continue;
}
((SKRect)(ref val7))._002Ector(((SKRect)(ref _bounds)).Left, num5, ((SKRect)(ref _bounds)).Right, num5 + ItemHeight);
if (i == _hoveredIndex && menuItem.IsEnabled)
{
SKPaint val8 = new SKPaint
{
Color = HoverBackgroundColor,
Style = (SKPaintStyle)0
};
try
{
canvas.DrawRect(val7, val8);
}
finally
{
((IDisposable)val8)?.Dispose();
}
}
if (menuItem.IsChecked)
{
SKPaint val9 = new SKPaint
{
Color = (menuItem.IsEnabled ? TextColor : DisabledTextColor),
TextSize = FontSize,
IsAntialias = true
};
try
{
canvas.DrawText("✓", ((SKRect)(ref _bounds)).Left + 8f, num5 + ItemHeight / 2f + 5f, val9);
}
finally
{
((IDisposable)val9)?.Dispose();
}
}
val.Color = (menuItem.IsEnabled ? TextColor : DisabledTextColor);
canvas.DrawText(menuItem.Text, ((SKRect)(ref _bounds)).Left + 28f, num5 + ItemHeight / 2f + 5f, val);
if (!string.IsNullOrEmpty(menuItem.Shortcut))
{
val.Color = DisabledTextColor;
SKRect val10 = default(SKRect);
val.MeasureText(menuItem.Shortcut, ref val10);
canvas.DrawText(menuItem.Shortcut, ((SKRect)(ref _bounds)).Right - ((SKRect)(ref val10)).Width - 12f, num5 + ItemHeight / 2f + 5f, val);
}
if (menuItem.SubItems.Count > 0)
{
canvas.DrawText("▸", ((SKRect)(ref _bounds)).Right - 16f, num5 + ItemHeight / 2f + 5f, val);
}
num5 += ItemHeight;
}
}
finally
{
((IDisposable)val5)?.Dispose();
}
}
finally
{
((IDisposable)val4)?.Dispose();
}
}
finally
{
((IDisposable)val3)?.Dispose();
}
}
finally
{
((IDisposable)val)?.Dispose();
}
}
public override SkiaView? HitTest(float x, float y)
{
if (((SKRect)(ref _bounds)).Contains(x, y))
{
return this;
}
return null;
}
public override void OnPointerMoved(PointerEventArgs e)
{
if (!((SKRect)(ref _bounds)).Contains(e.X, e.Y))
{
_hoveredIndex = -1;
Invalidate();
return;
}
float num = ((SKRect)(ref _bounds)).Top;
int num2 = -1;
for (int i = 0; i < Items.Count; i++)
{
MenuItem menuItem = Items[i];
float num3 = (menuItem.IsSeparator ? SeparatorHeight : ItemHeight);
if (e.Y >= num && e.Y < num + num3 && !menuItem.IsSeparator)
{
num2 = i;
break;
}
num += num3;
}
if (num2 != _hoveredIndex)
{
_hoveredIndex = num2;
Invalidate();
}
}
public override void OnPointerPressed(PointerEventArgs e)
{
if (_hoveredIndex >= 0 && _hoveredIndex < Items.Count)
{
MenuItem menuItem = Items[_hoveredIndex];
if (menuItem.IsEnabled && !menuItem.IsSeparator)
{
menuItem.OnClicked();
this.ItemClicked?.Invoke(this, new MenuItemClickedEventArgs(menuItem));
e.Handled = true;
}
}
}
}

View File

@@ -1,451 +1,513 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.Maui.Platform.Linux;
using SkiaSharp;
using Microsoft.Maui.Graphics;
namespace Microsoft.Maui.Platform;
/// <summary>
/// Skia-rendered navigation page with back stack support.
/// </summary>
public class SkiaNavigationPage : SkiaView
{
private readonly Stack<SkiaPage> _navigationStack = new();
private SkiaPage? _currentPage;
private bool _isAnimating;
private float _animationProgress;
private SkiaPage? _incomingPage;
private bool _isPushAnimation;
private readonly Stack<SkiaPage> _navigationStack = new Stack<SkiaPage>();
// Navigation bar styling
private SKColor _barBackgroundColor = new SKColor(0x21, 0x96, 0xF3);
private SKColor _barTextColor = SKColors.White;
private float _navigationBarHeight = 56;
private bool _showBackButton = true;
private SkiaPage? _currentPage;
public SKColor BarBackgroundColor
{
get => _barBackgroundColor;
set
{
_barBackgroundColor = value;
UpdatePageNavigationBar();
Invalidate();
}
}
private bool _isAnimating;
public SKColor BarTextColor
{
get => _barTextColor;
set
{
_barTextColor = value;
UpdatePageNavigationBar();
Invalidate();
}
}
private float _animationProgress;
public float NavigationBarHeight
{
get => _navigationBarHeight;
set
{
_navigationBarHeight = value;
UpdatePageNavigationBar();
Invalidate();
}
}
private SkiaPage? _incomingPage;
public SkiaPage? CurrentPage => _currentPage;
public SkiaPage? RootPage => _navigationStack.Count > 0 ? _navigationStack.Last() : _currentPage;
public int StackDepth => _navigationStack.Count + (_currentPage != null ? 1 : 0);
private bool _isPushAnimation;
public event EventHandler<NavigationEventArgs>? Pushed;
public event EventHandler<NavigationEventArgs>? Popped;
public event EventHandler<NavigationEventArgs>? PoppedToRoot;
private SKColor _barBackgroundColor = new SKColor((byte)33, (byte)150, (byte)243);
public SkiaNavigationPage()
{
}
private SKColor _barTextColor = SKColors.White;
public SkiaNavigationPage(SkiaPage rootPage)
{
SetRootPage(rootPage);
}
private float _navigationBarHeight = 56f;
public void SetRootPage(SkiaPage page)
{
_navigationStack.Clear();
_currentPage?.OnDisappearing();
_currentPage = page;
_currentPage.Parent = this;
ConfigurePage(_currentPage, false);
_currentPage.OnAppearing();
Invalidate();
}
private bool _showBackButton = true;
public void Push(SkiaPage page, bool animated = true)
{
if (_isAnimating) return;
public SKColor BarBackgroundColor
{
get
{
//IL_0001: Unknown result type (might be due to invalid IL or missing references)
return _barBackgroundColor;
}
set
{
//IL_0001: Unknown result type (might be due to invalid IL or missing references)
//IL_0002: Unknown result type (might be due to invalid IL or missing references)
_barBackgroundColor = value;
UpdatePageNavigationBar();
Invalidate();
}
}
if (_currentPage != null)
{
_currentPage.OnDisappearing();
_navigationStack.Push(_currentPage);
}
public SKColor BarTextColor
{
get
{
//IL_0001: Unknown result type (might be due to invalid IL or missing references)
return _barTextColor;
}
set
{
//IL_0001: Unknown result type (might be due to invalid IL or missing references)
//IL_0002: Unknown result type (might be due to invalid IL or missing references)
_barTextColor = value;
UpdatePageNavigationBar();
Invalidate();
}
}
ConfigurePage(page, true);
page.Parent = this;
public float NavigationBarHeight
{
get
{
return _navigationBarHeight;
}
set
{
_navigationBarHeight = value;
UpdatePageNavigationBar();
Invalidate();
}
}
if (animated)
{
_incomingPage = page;
_isPushAnimation = true;
_animationProgress = 0;
_isAnimating = true;
AnimatePush();
}
else
{
_currentPage = page;
_currentPage.OnAppearing();
Invalidate();
}
public SkiaPage? CurrentPage => _currentPage;
Pushed?.Invoke(this, new NavigationEventArgs(page));
}
public SkiaPage? RootPage
{
get
{
if (_navigationStack.Count <= 0)
{
return _currentPage;
}
return _navigationStack.Last();
}
}
public SkiaPage? Pop(bool animated = true)
{
if (_isAnimating || _navigationStack.Count == 0) return null;
public int StackDepth => _navigationStack.Count + ((_currentPage != null) ? 1 : 0);
var poppedPage = _currentPage;
poppedPage?.OnDisappearing();
public event EventHandler<NavigationEventArgs>? Pushed;
var previousPage = _navigationStack.Pop();
public event EventHandler<NavigationEventArgs>? Popped;
if (animated && poppedPage != null)
{
_incomingPage = previousPage;
_isPushAnimation = false;
_animationProgress = 0;
_isAnimating = true;
AnimatePop(poppedPage);
}
else
{
_currentPage = previousPage;
_currentPage?.OnAppearing();
Invalidate();
}
public event EventHandler<NavigationEventArgs>? PoppedToRoot;
if (poppedPage != null)
{
Popped?.Invoke(this, new NavigationEventArgs(poppedPage));
}
public SkiaNavigationPage()
{
}//IL_0018: Unknown result type (might be due to invalid IL or missing references)
//IL_001d: Unknown result type (might be due to invalid IL or missing references)
//IL_0023: Unknown result type (might be due to invalid IL or missing references)
//IL_0028: Unknown result type (might be due to invalid IL or missing references)
return poppedPage;
}
public void PopToRoot(bool animated = true)
{
if (_isAnimating || _navigationStack.Count == 0) return;
public SkiaNavigationPage(SkiaPage rootPage)
{
//IL_0018: Unknown result type (might be due to invalid IL or missing references)
//IL_001d: Unknown result type (might be due to invalid IL or missing references)
//IL_0023: Unknown result type (might be due to invalid IL or missing references)
//IL_0028: Unknown result type (might be due to invalid IL or missing references)
SetRootPage(rootPage);
}
_currentPage?.OnDisappearing();
public void SetRootPage(SkiaPage page)
{
_navigationStack.Clear();
_currentPage?.OnDisappearing();
_currentPage = page;
_currentPage.Parent = this;
ConfigurePage(_currentPage, showBackButton: false);
_currentPage.OnAppearing();
Invalidate();
}
// Get root page
SkiaPage? rootPage = null;
while (_navigationStack.Count > 0)
{
rootPage = _navigationStack.Pop();
}
public void Push(SkiaPage page, bool animated = true)
{
if (!_isAnimating)
{
if (LinuxApplication.IsGtkMode)
{
animated = false;
}
if (_currentPage != null)
{
_currentPage.OnDisappearing();
_navigationStack.Push(_currentPage);
}
ConfigurePage(page, showBackButton: true);
page.Parent = this;
if (animated)
{
_incomingPage = page;
_isPushAnimation = true;
_animationProgress = 0f;
_isAnimating = true;
AnimatePush();
}
else
{
Console.WriteLine("[SkiaNavigationPage] Push (no animation): setting _currentPage to " + page.Title);
_currentPage = page;
_currentPage.OnAppearing();
Console.WriteLine("[SkiaNavigationPage] Push: calling Invalidate");
Invalidate();
Console.WriteLine("[SkiaNavigationPage] Push: Invalidate called, _currentPage is now " + _currentPage?.Title);
}
this.Pushed?.Invoke(this, new NavigationEventArgs(page));
}
}
if (rootPage != null)
{
_currentPage = rootPage;
ConfigurePage(_currentPage, false);
_currentPage.OnAppearing();
Invalidate();
}
public SkiaPage? Pop(bool animated = true)
{
if (_isAnimating || _navigationStack.Count == 0)
{
return null;
}
if (LinuxApplication.IsGtkMode)
{
animated = false;
}
SkiaPage currentPage = _currentPage;
currentPage?.OnDisappearing();
SkiaPage skiaPage = _navigationStack.Pop();
if (animated && currentPage != null)
{
_incomingPage = skiaPage;
_isPushAnimation = false;
_animationProgress = 0f;
_isAnimating = true;
AnimatePop(currentPage);
}
else
{
_currentPage = skiaPage;
_currentPage?.OnAppearing();
Invalidate();
}
if (currentPage != null)
{
this.Popped?.Invoke(this, new NavigationEventArgs(currentPage));
}
return currentPage;
}
PoppedToRoot?.Invoke(this, new NavigationEventArgs(_currentPage!));
}
public void PopToRoot(bool animated = true)
{
if (!_isAnimating && _navigationStack.Count != 0)
{
_currentPage?.OnDisappearing();
SkiaPage skiaPage = null;
while (_navigationStack.Count > 0)
{
skiaPage = _navigationStack.Pop();
}
if (skiaPage != null)
{
_currentPage = skiaPage;
ConfigurePage(_currentPage, showBackButton: false);
_currentPage.OnAppearing();
Invalidate();
}
this.PoppedToRoot?.Invoke(this, new NavigationEventArgs(_currentPage));
}
}
private void ConfigurePage(SkiaPage page, bool showBackButton)
{
page.ShowNavigationBar = true;
page.TitleBarColor = _barBackgroundColor;
page.TitleTextColor = _barTextColor;
page.NavigationBarHeight = _navigationBarHeight;
_showBackButton = showBackButton && _navigationStack.Count > 0;
}
private void ConfigurePage(SkiaPage page, bool showBackButton)
{
//IL_0009: Unknown result type (might be due to invalid IL or missing references)
//IL_0015: Unknown result type (might be due to invalid IL or missing references)
page.ShowNavigationBar = true;
page.TitleBarColor = _barBackgroundColor;
page.TitleTextColor = _barTextColor;
page.NavigationBarHeight = _navigationBarHeight;
_showBackButton = showBackButton && _navigationStack.Count > 0;
}
private void UpdatePageNavigationBar()
{
if (_currentPage != null)
{
_currentPage.TitleBarColor = _barBackgroundColor;
_currentPage.TitleTextColor = _barTextColor;
_currentPage.NavigationBarHeight = _navigationBarHeight;
}
}
private void UpdatePageNavigationBar()
{
//IL_000f: Unknown result type (might be due to invalid IL or missing references)
//IL_0020: Unknown result type (might be due to invalid IL or missing references)
if (_currentPage != null)
{
_currentPage.TitleBarColor = _barBackgroundColor;
_currentPage.TitleTextColor = _barTextColor;
_currentPage.NavigationBarHeight = _navigationBarHeight;
}
}
private async void AnimatePush()
{
const int durationMs = 250;
const int frameMs = 16;
var startTime = DateTime.Now;
private async void AnimatePush()
{
DateTime startTime = DateTime.Now;
while (_animationProgress < 1f)
{
await Task.Delay(16);
double totalMilliseconds = (DateTime.Now - startTime).TotalMilliseconds;
_animationProgress = Math.Min(1f, (float)(totalMilliseconds / 250.0));
Invalidate();
}
_currentPage = _incomingPage;
_incomingPage = null;
_isAnimating = false;
_currentPage?.OnAppearing();
Invalidate();
}
while (_animationProgress < 1)
{
await Task.Delay(frameMs);
var elapsed = (DateTime.Now - startTime).TotalMilliseconds;
_animationProgress = Math.Min(1, (float)(elapsed / durationMs));
Invalidate();
}
private async void AnimatePop(SkiaPage outgoingPage)
{
DateTime startTime = DateTime.Now;
while (_animationProgress < 1f)
{
await Task.Delay(16);
double totalMilliseconds = (DateTime.Now - startTime).TotalMilliseconds;
_animationProgress = Math.Min(1f, (float)(totalMilliseconds / 250.0));
Invalidate();
}
_currentPage = _incomingPage;
_incomingPage = null;
_isAnimating = false;
_currentPage?.OnAppearing();
outgoingPage.Parent = null;
Invalidate();
}
_currentPage = _incomingPage;
_incomingPage = null;
_isAnimating = false;
_currentPage?.OnAppearing();
Invalidate();
}
protected override void OnDraw(SKCanvas canvas, SKRect bounds)
{
//IL_0001: Unknown result type (might be due to invalid IL or missing references)
//IL_0006: Unknown result type (might be due to invalid IL or missing references)
//IL_0012: Unknown result type (might be due to invalid IL or missing references)
//IL_0017: Unknown result type (might be due to invalid IL or missing references)
//IL_0019: Unknown result type (might be due to invalid IL or missing references)
//IL_0023: Unknown result type (might be due to invalid IL or missing references)
//IL_002b: Expected O, but got Unknown
//IL_002c: Unknown result type (might be due to invalid IL or missing references)
//IL_01a7: Unknown result type (might be due to invalid IL or missing references)
//IL_0129: Unknown result type (might be due to invalid IL or missing references)
//IL_01d1: Unknown result type (might be due to invalid IL or missing references)
//IL_0166: Unknown result type (might be due to invalid IL or missing references)
//IL_00d9: Unknown result type (might be due to invalid IL or missing references)
//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
if (base.BackgroundColor != SKColors.Transparent)
{
SKPaint val = new SKPaint
{
Color = base.BackgroundColor,
Style = (SKPaintStyle)0
};
try
{
canvas.DrawRect(bounds, val);
}
finally
{
((IDisposable)val)?.Dispose();
}
}
if (_isAnimating && _incomingPage != null)
{
float num = EaseOutCubic(_animationProgress);
if (_isPushAnimation)
{
float num2 = (0f - ((SKRect)(ref bounds)).Width) * num;
float num3 = ((SKRect)(ref bounds)).Width * (1f - num);
if (_currentPage != null)
{
canvas.Save();
canvas.Translate(num2, 0f);
_currentPage.Bounds = bounds;
_currentPage.Draw(canvas);
canvas.Restore();
}
canvas.Save();
canvas.Translate(num3, 0f);
_incomingPage.Bounds = bounds;
_incomingPage.Draw(canvas);
canvas.Restore();
}
else
{
float num4 = (0f - ((SKRect)(ref bounds)).Width) * (1f - num);
float num5 = ((SKRect)(ref bounds)).Width * num;
canvas.Save();
canvas.Translate(num4, 0f);
_incomingPage.Bounds = bounds;
_incomingPage.Draw(canvas);
canvas.Restore();
if (_currentPage != null)
{
canvas.Save();
canvas.Translate(num5, 0f);
_currentPage.Bounds = bounds;
_currentPage.Draw(canvas);
canvas.Restore();
}
}
}
else if (_currentPage != null)
{
Console.WriteLine("[SkiaNavigationPage] OnDraw: drawing _currentPage=" + _currentPage.Title);
_currentPage.Bounds = bounds;
_currentPage.Draw(canvas);
if (_showBackButton && _navigationStack.Count > 0)
{
DrawBackButton(canvas, bounds);
}
}
}
private async void AnimatePop(SkiaPage outgoingPage)
{
const int durationMs = 250;
const int frameMs = 16;
var startTime = DateTime.Now;
private void DrawBackButton(SKCanvas canvas, SKRect bounds)
{
//IL_0042: Unknown result type (might be due to invalid IL or missing references)
//IL_0047: Unknown result type (might be due to invalid IL or missing references)
//IL_0049: Unknown result type (might be due to invalid IL or missing references)
//IL_0053: Unknown result type (might be due to invalid IL or missing references)
//IL_005a: Unknown result type (might be due to invalid IL or missing references)
//IL_0065: Unknown result type (might be due to invalid IL or missing references)
//IL_006c: Unknown result type (might be due to invalid IL or missing references)
//IL_0074: Expected O, but got Unknown
//IL_0091: Unknown result type (might be due to invalid IL or missing references)
//IL_0098: Expected O, but got Unknown
SKRect val = default(SKRect);
((SKRect)(ref val))._002Ector(((SKRect)(ref bounds)).Left + 8f, ((SKRect)(ref bounds)).Top + 12f, ((SKRect)(ref bounds)).Left + 48f, ((SKRect)(ref bounds)).Top + _navigationBarHeight - 12f);
SKPaint val2 = new SKPaint
{
Color = _barTextColor,
Style = (SKPaintStyle)1,
StrokeWidth = 2.5f,
IsAntialias = true,
StrokeCap = (SKStrokeCap)1
};
try
{
float midY = ((SKRect)(ref val)).MidY;
float num = 10f;
float num2 = ((SKRect)(ref val)).Left + 8f;
SKPath val3 = new SKPath();
try
{
val3.MoveTo(num2 + num, midY - num);
val3.LineTo(num2, midY);
val3.LineTo(num2 + num, midY + num);
canvas.DrawPath(val3, val2);
}
finally
{
((IDisposable)val3)?.Dispose();
}
}
finally
{
((IDisposable)val2)?.Dispose();
}
}
while (_animationProgress < 1)
{
await Task.Delay(frameMs);
var elapsed = (DateTime.Now - startTime).TotalMilliseconds;
_animationProgress = Math.Min(1, (float)(elapsed / durationMs));
Invalidate();
}
private static float EaseOutCubic(float t)
{
return 1f - (float)Math.Pow(1f - t, 3.0);
}
_currentPage = _incomingPage;
_incomingPage = null;
_isAnimating = false;
_currentPage?.OnAppearing();
outgoingPage.Parent = null;
Invalidate();
}
protected override SKSize MeasureOverride(SKSize availableSize)
{
//IL_0000: Unknown result type (might be due to invalid IL or missing references)
return availableSize;
}
protected override void OnDraw(SKCanvas canvas, SKRect bounds)
{
// Draw background
if (BackgroundColor != SKColors.Transparent)
{
using var bgPaint = new SKPaint
{
Color = BackgroundColor,
Style = SKPaintStyle.Fill
};
canvas.DrawRect(bounds, bgPaint);
}
public override void OnPointerPressed(PointerEventArgs e)
{
Console.WriteLine($"[SkiaNavigationPage] OnPointerPressed at ({e.X}, {e.Y}), _isAnimating={_isAnimating}");
if (!_isAnimating)
{
if (_showBackButton && _navigationStack.Count > 0 && e.X < 56f && e.Y < _navigationBarHeight)
{
Console.WriteLine("[SkiaNavigationPage] Back button clicked");
Pop();
}
else
{
Console.WriteLine("[SkiaNavigationPage] Forwarding to _currentPage: " + ((object)_currentPage)?.GetType().Name);
_currentPage?.OnPointerPressed(e);
}
}
}
if (_isAnimating && _incomingPage != null)
{
// Draw animation
var eased = EaseOutCubic(_animationProgress);
public override void OnPointerMoved(PointerEventArgs e)
{
if (!_isAnimating)
{
_currentPage?.OnPointerMoved(e);
}
}
if (_isPushAnimation)
{
// Push: current page slides left, incoming slides from right
var currentOffset = -bounds.Width * eased;
var incomingOffset = bounds.Width * (1 - eased);
public override void OnPointerReleased(PointerEventArgs e)
{
if (!_isAnimating)
{
_currentPage?.OnPointerReleased(e);
}
}
// Draw current page (sliding out)
if (_currentPage != null)
{
canvas.Save();
canvas.Translate(currentOffset, 0);
_currentPage.Bounds = bounds;
_currentPage.Draw(canvas);
canvas.Restore();
}
public override void OnKeyDown(KeyEventArgs e)
{
if (!_isAnimating)
{
if ((e.Key == Key.Escape || e.Key == Key.Backspace) && _navigationStack.Count > 0)
{
Pop();
e.Handled = true;
}
else
{
_currentPage?.OnKeyDown(e);
}
}
}
// Draw incoming page
canvas.Save();
canvas.Translate(incomingOffset, 0);
_incomingPage.Bounds = bounds;
_incomingPage.Draw(canvas);
canvas.Restore();
}
else
{
// Pop: incoming slides from left, current slides right
var incomingOffset = -bounds.Width * (1 - eased);
var currentOffset = bounds.Width * eased;
public override void OnKeyUp(KeyEventArgs e)
{
if (!_isAnimating)
{
_currentPage?.OnKeyUp(e);
}
}
// Draw incoming page (sliding in)
canvas.Save();
canvas.Translate(incomingOffset, 0);
_incomingPage.Bounds = bounds;
_incomingPage.Draw(canvas);
canvas.Restore();
public override void OnScroll(ScrollEventArgs e)
{
if (!_isAnimating)
{
_currentPage?.OnScroll(e);
}
}
// Draw current page (sliding out)
if (_currentPage != null)
{
canvas.Save();
canvas.Translate(currentOffset, 0);
_currentPage.Bounds = bounds;
_currentPage.Draw(canvas);
canvas.Restore();
}
}
}
else if (_currentPage != null)
{
// Draw current page normally
_currentPage.Bounds = bounds;
_currentPage.Draw(canvas);
// Draw back button if applicable
if (_showBackButton && _navigationStack.Count > 0)
{
DrawBackButton(canvas, bounds);
}
}
}
private void DrawBackButton(SKCanvas canvas, SKRect bounds)
{
var buttonBounds = new SKRect(bounds.Left + 8, bounds.Top + 12, bounds.Left + 48, bounds.Top + _navigationBarHeight - 12);
using var paint = new SKPaint
{
Color = _barTextColor,
Style = SKPaintStyle.Stroke,
StrokeWidth = 2.5f,
IsAntialias = true,
StrokeCap = SKStrokeCap.Round
};
// Draw back arrow
var centerY = buttonBounds.MidY;
var arrowSize = 10f;
var left = buttonBounds.Left + 8;
using var path = new SKPath();
path.MoveTo(left + arrowSize, centerY - arrowSize);
path.LineTo(left, centerY);
path.LineTo(left + arrowSize, centerY + arrowSize);
canvas.DrawPath(path, paint);
}
private static float EaseOutCubic(float t)
{
return 1 - (float)Math.Pow(1 - t, 3);
}
protected override SKSize MeasureOverride(SKSize availableSize)
{
return availableSize;
}
public override void OnPointerPressed(PointerEventArgs e)
{
Console.WriteLine($"[SkiaNavigationPage] OnPointerPressed at ({e.X}, {e.Y}), _isAnimating={_isAnimating}");
if (_isAnimating) return;
// Check for back button click
if (_showBackButton && _navigationStack.Count > 0)
{
if (e.X < 56 && e.Y < _navigationBarHeight)
{
Console.WriteLine($"[SkiaNavigationPage] Back button clicked");
Pop();
return;
}
}
Console.WriteLine($"[SkiaNavigationPage] Forwarding to _currentPage: {_currentPage?.GetType().Name}");
_currentPage?.OnPointerPressed(e);
}
public override void OnPointerMoved(PointerEventArgs e)
{
if (_isAnimating) return;
_currentPage?.OnPointerMoved(e);
}
public override void OnPointerReleased(PointerEventArgs e)
{
if (_isAnimating) return;
_currentPage?.OnPointerReleased(e);
}
public override void OnKeyDown(KeyEventArgs e)
{
if (_isAnimating) return;
// Handle back navigation with Escape or Backspace
if ((e.Key == Key.Escape || e.Key == Key.Backspace) && _navigationStack.Count > 0)
{
Pop();
e.Handled = true;
return;
}
_currentPage?.OnKeyDown(e);
}
public override void OnKeyUp(KeyEventArgs e)
{
if (_isAnimating) return;
_currentPage?.OnKeyUp(e);
}
public override void OnScroll(ScrollEventArgs e)
{
if (_isAnimating) return;
_currentPage?.OnScroll(e);
}
public override SkiaView? HitTest(float x, float y)
{
if (!IsVisible)
return null;
// Back button area - return self so OnPointerPressed handles it
if (_showBackButton && _navigationStack.Count > 0 && x < 56 && y < _navigationBarHeight)
{
return this;
}
// Check current page
if (_currentPage != null)
{
try
{
var hit = _currentPage.HitTest(x, y);
if (hit != null)
return hit;
}
catch (Exception ex)
{
Console.WriteLine($"[SkiaNavigationPage] HitTest error: {ex.Message}");
}
}
return this;
}
}
/// <summary>
/// Event args for navigation events.
/// </summary>
public class NavigationEventArgs : EventArgs
{
public SkiaPage Page { get; }
public NavigationEventArgs(SkiaPage page)
{
Page = page;
}
public override SkiaView? HitTest(float x, float y)
{
if (!base.IsVisible)
{
return null;
}
if (_showBackButton && _navigationStack.Count > 0 && x < 56f && y < _navigationBarHeight)
{
return this;
}
if (_currentPage != null)
{
try
{
SkiaView skiaView = _currentPage.HitTest(x, y);
if (skiaView != null)
{
return skiaView;
}
}
catch (Exception ex)
{
Console.WriteLine("[SkiaNavigationPage] HitTest error: " + ex.Message);
}
}
return this;
}
}

View File

@@ -1,464 +1,458 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System;
using SkiaSharp;
using Microsoft.Maui.Graphics;
namespace Microsoft.Maui.Platform;
/// <summary>
/// Base class for Skia-rendered pages.
/// </summary>
public class SkiaPage : SkiaView
{
private SkiaView? _content;
private string _title = "";
private SKColor _titleBarColor = new SKColor(0x21, 0x96, 0xF3); // Material Blue
private SKColor _titleTextColor = SKColors.White;
private bool _showNavigationBar = false;
private float _navigationBarHeight = 56;
private SkiaView? _content;
// Padding
private float _paddingLeft;
private float _paddingTop;
private float _paddingRight;
private float _paddingBottom;
private string _title = "";
public SkiaView? Content
{
get => _content;
set
{
if (_content != null)
{
_content.Parent = null;
}
_content = value;
if (_content != null)
{
_content.Parent = this;
}
Invalidate();
}
}
private SKColor _titleBarColor = new SKColor((byte)33, (byte)150, (byte)243);
public string Title
{
get => _title;
set
{
_title = value;
Invalidate();
}
}
private SKColor _titleTextColor = SKColors.White;
public SKColor TitleBarColor
{
get => _titleBarColor;
set
{
_titleBarColor = value;
Invalidate();
}
}
private bool _showNavigationBar;
public SKColor TitleTextColor
{
get => _titleTextColor;
set
{
_titleTextColor = value;
Invalidate();
}
}
private float _navigationBarHeight = 56f;
public bool ShowNavigationBar
{
get => _showNavigationBar;
set
{
_showNavigationBar = value;
Invalidate();
}
}
private float _paddingLeft;
public float NavigationBarHeight
{
get => _navigationBarHeight;
set
{
_navigationBarHeight = value;
Invalidate();
}
}
private float _paddingTop;
public float PaddingLeft
{
get => _paddingLeft;
set { _paddingLeft = value; Invalidate(); }
}
private float _paddingRight;
public float PaddingTop
{
get => _paddingTop;
set { _paddingTop = value; Invalidate(); }
}
private float _paddingBottom;
public float PaddingRight
{
get => _paddingRight;
set { _paddingRight = value; Invalidate(); }
}
public SkiaView? Content
{
get
{
return _content;
}
set
{
if (_content != null)
{
_content.Parent = null;
}
_content = value;
if (_content != null)
{
_content.Parent = this;
}
Invalidate();
}
}
public float PaddingBottom
{
get => _paddingBottom;
set { _paddingBottom = value; Invalidate(); }
}
public string Title
{
get
{
return _title;
}
set
{
_title = value;
Invalidate();
}
}
public bool IsBusy { get; set; }
public SKColor TitleBarColor
{
get
{
//IL_0001: Unknown result type (might be due to invalid IL or missing references)
return _titleBarColor;
}
set
{
//IL_0001: Unknown result type (might be due to invalid IL or missing references)
//IL_0002: Unknown result type (might be due to invalid IL or missing references)
_titleBarColor = value;
Invalidate();
}
}
public event EventHandler? Appearing;
public event EventHandler? Disappearing;
public SKColor TitleTextColor
{
get
{
//IL_0001: Unknown result type (might be due to invalid IL or missing references)
return _titleTextColor;
}
set
{
//IL_0001: Unknown result type (might be due to invalid IL or missing references)
//IL_0002: Unknown result type (might be due to invalid IL or missing references)
_titleTextColor = value;
Invalidate();
}
}
protected override void OnDraw(SKCanvas canvas, SKRect bounds)
{
// Draw background
if (BackgroundColor != SKColors.Transparent)
{
using var bgPaint = new SKPaint
{
Color = BackgroundColor,
Style = SKPaintStyle.Fill
};
canvas.DrawRect(bounds, bgPaint);
}
public bool ShowNavigationBar
{
get
{
return _showNavigationBar;
}
set
{
_showNavigationBar = value;
Invalidate();
}
}
var contentTop = bounds.Top;
public float NavigationBarHeight
{
get
{
return _navigationBarHeight;
}
set
{
_navigationBarHeight = value;
Invalidate();
}
}
// Draw navigation bar if visible
if (_showNavigationBar)
{
DrawNavigationBar(canvas, new SKRect(bounds.Left, bounds.Top, bounds.Right, bounds.Top + _navigationBarHeight));
contentTop = bounds.Top + _navigationBarHeight;
}
public float PaddingLeft
{
get
{
return _paddingLeft;
}
set
{
_paddingLeft = value;
Invalidate();
}
}
// Calculate content bounds with padding
var contentBounds = new SKRect(
bounds.Left + _paddingLeft,
contentTop + _paddingTop,
bounds.Right - _paddingRight,
bounds.Bottom - _paddingBottom);
public float PaddingTop
{
get
{
return _paddingTop;
}
set
{
_paddingTop = value;
Invalidate();
}
}
// Draw content
if (_content != null)
{
// Apply content's margin to the content bounds
var margin = _content.Margin;
var adjustedBounds = new SKRect(
contentBounds.Left + (float)margin.Left,
contentBounds.Top + (float)margin.Top,
contentBounds.Right - (float)margin.Right,
contentBounds.Bottom - (float)margin.Bottom);
public float PaddingRight
{
get
{
return _paddingRight;
}
set
{
_paddingRight = value;
Invalidate();
}
}
// Measure and arrange the content before drawing
var availableSize = new SKSize(adjustedBounds.Width, adjustedBounds.Height);
_content.Measure(availableSize);
_content.Arrange(adjustedBounds);
Console.WriteLine($"[SkiaPage] Drawing content: {_content.GetType().Name}, Bounds={_content.Bounds}, IsVisible={_content.IsVisible}");
_content.Draw(canvas);
}
public float PaddingBottom
{
get
{
return _paddingBottom;
}
set
{
_paddingBottom = value;
Invalidate();
}
}
// Draw busy indicator overlay
if (IsBusy)
{
DrawBusyIndicator(canvas, bounds);
}
}
public bool IsBusy { get; set; }
protected virtual void DrawNavigationBar(SKCanvas canvas, SKRect bounds)
{
// Draw navigation bar background
using var barPaint = new SKPaint
{
Color = _titleBarColor,
Style = SKPaintStyle.Fill
};
canvas.DrawRect(bounds, barPaint);
public event EventHandler? Appearing;
// Draw title
if (!string.IsNullOrEmpty(_title))
{
using var font = new SKFont(SKTypeface.Default, 20);
using var textPaint = new SKPaint(font)
{
Color = _titleTextColor,
IsAntialias = true
};
public event EventHandler? Disappearing;
var textBounds = new SKRect();
textPaint.MeasureText(_title, ref textBounds);
protected override void OnDraw(SKCanvas canvas, SKRect bounds)
{
//IL_0001: Unknown result type (might be due to invalid IL or missing references)
//IL_0006: Unknown result type (might be due to invalid IL or missing references)
//IL_0012: Unknown result type (might be due to invalid IL or missing references)
//IL_0017: Unknown result type (might be due to invalid IL or missing references)
//IL_0019: Unknown result type (might be due to invalid IL or missing references)
//IL_0023: Unknown result type (might be due to invalid IL or missing references)
//IL_002b: Expected O, but got Unknown
//IL_0074: Unknown result type (might be due to invalid IL or missing references)
//IL_002c: Unknown result type (might be due to invalid IL or missing references)
//IL_00d7: Unknown result type (might be due to invalid IL or missing references)
//IL_00dc: Unknown result type (might be due to invalid IL or missing references)
//IL_013f: Unknown result type (might be due to invalid IL or missing references)
//IL_0141: Unknown result type (might be due to invalid IL or missing references)
//IL_014d: Unknown result type (might be due to invalid IL or missing references)
//IL_0195: Unknown result type (might be due to invalid IL or missing references)
//IL_01df: Unknown result type (might be due to invalid IL or missing references)
if (base.BackgroundColor != SKColors.Transparent)
{
SKPaint val = new SKPaint
{
Color = base.BackgroundColor,
Style = (SKPaintStyle)0
};
try
{
canvas.DrawRect(bounds, val);
}
finally
{
((IDisposable)val)?.Dispose();
}
}
float num = ((SKRect)(ref bounds)).Top;
if (_showNavigationBar)
{
DrawNavigationBar(canvas, new SKRect(((SKRect)(ref bounds)).Left, ((SKRect)(ref bounds)).Top, ((SKRect)(ref bounds)).Right, ((SKRect)(ref bounds)).Top + _navigationBarHeight));
num = ((SKRect)(ref bounds)).Top + _navigationBarHeight;
}
SKRect val2 = default(SKRect);
((SKRect)(ref val2))._002Ector(((SKRect)(ref bounds)).Left + _paddingLeft, num + _paddingTop, ((SKRect)(ref bounds)).Right - _paddingRight, ((SKRect)(ref bounds)).Bottom - _paddingBottom);
if (_content != null)
{
Thickness margin = _content.Margin;
SKRect bounds2 = default(SKRect);
((SKRect)(ref bounds2))._002Ector(((SKRect)(ref val2)).Left + (float)((Thickness)(ref margin)).Left, ((SKRect)(ref val2)).Top + (float)((Thickness)(ref margin)).Top, ((SKRect)(ref val2)).Right - (float)((Thickness)(ref margin)).Right, ((SKRect)(ref val2)).Bottom - (float)((Thickness)(ref margin)).Bottom);
SKSize availableSize = default(SKSize);
((SKSize)(ref availableSize))._002Ector(((SKRect)(ref bounds2)).Width, ((SKRect)(ref bounds2)).Height);
_content.Measure(availableSize);
_content.Arrange(bounds2);
Console.WriteLine($"[SkiaPage] Drawing content: {((object)_content).GetType().Name}, Bounds={_content.Bounds}, IsVisible={_content.IsVisible}");
_content.Draw(canvas);
}
if (IsBusy)
{
DrawBusyIndicator(canvas, bounds);
}
}
var x = bounds.Left + 16;
var y = bounds.MidY - textBounds.MidY;
canvas.DrawText(_title, x, y, textPaint);
}
protected virtual void DrawNavigationBar(SKCanvas canvas, SKRect bounds)
{
//IL_0000: Unknown result type (might be due to invalid IL or missing references)
//IL_0005: Unknown result type (might be due to invalid IL or missing references)
//IL_0007: Unknown result type (might be due to invalid IL or missing references)
//IL_0011: Unknown result type (might be due to invalid IL or missing references)
//IL_0019: Expected O, but got Unknown
//IL_001a: Unknown result type (might be due to invalid IL or missing references)
//IL_00c3: Unknown result type (might be due to invalid IL or missing references)
//IL_00c8: Unknown result type (might be due to invalid IL or missing references)
//IL_00ce: Unknown result type (might be due to invalid IL or missing references)
//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
//IL_00df: Unknown result type (might be due to invalid IL or missing references)
//IL_00f1: Expected O, but got Unknown
//IL_0045: Unknown result type (might be due to invalid IL or missing references)
//IL_004b: Expected O, but got Unknown
//IL_0114: Unknown result type (might be due to invalid IL or missing references)
//IL_004c: Unknown result type (might be due to invalid IL or missing references)
//IL_0051: Unknown result type (might be due to invalid IL or missing references)
//IL_0053: Unknown result type (might be due to invalid IL or missing references)
//IL_005d: Unknown result type (might be due to invalid IL or missing references)
//IL_0065: Expected O, but got Unknown
//IL_0067: Unknown result type (might be due to invalid IL or missing references)
SKPaint val = new SKPaint
{
Color = _titleBarColor,
Style = (SKPaintStyle)0
};
try
{
canvas.DrawRect(bounds, val);
if (!string.IsNullOrEmpty(_title))
{
SKFont val2 = new SKFont(SKTypeface.Default, 20f, 1f, 0f);
try
{
SKPaint val3 = new SKPaint(val2)
{
Color = _titleTextColor,
IsAntialias = true
};
try
{
SKRect val4 = default(SKRect);
val3.MeasureText(_title, ref val4);
float num = ((SKRect)(ref bounds)).Left + 16f;
float num2 = ((SKRect)(ref bounds)).MidY - ((SKRect)(ref val4)).MidY;
canvas.DrawText(_title, num, num2, val3);
}
finally
{
((IDisposable)val3)?.Dispose();
}
}
finally
{
((IDisposable)val2)?.Dispose();
}
}
SKPaint val5 = new SKPaint
{
Color = new SKColor((byte)0, (byte)0, (byte)0, (byte)30),
Style = (SKPaintStyle)0,
MaskFilter = SKMaskFilter.CreateBlur((SKBlurStyle)0, 2f)
};
try
{
canvas.DrawRect(new SKRect(((SKRect)(ref bounds)).Left, ((SKRect)(ref bounds)).Bottom, ((SKRect)(ref bounds)).Right, ((SKRect)(ref bounds)).Bottom + 4f), val5);
}
finally
{
((IDisposable)val5)?.Dispose();
}
}
finally
{
((IDisposable)val)?.Dispose();
}
}
// Draw shadow
using var shadowPaint = new SKPaint
{
Color = new SKColor(0, 0, 0, 30),
Style = SKPaintStyle.Fill,
MaskFilter = SKMaskFilter.CreateBlur(SKBlurStyle.Normal, 2)
};
canvas.DrawRect(new SKRect(bounds.Left, bounds.Bottom, bounds.Right, bounds.Bottom + 4), shadowPaint);
}
private void DrawBusyIndicator(SKCanvas canvas, SKRect bounds)
{
//IL_0000: Unknown result type (might be due to invalid IL or missing references)
//IL_0005: Unknown result type (might be due to invalid IL or missing references)
//IL_001a: Unknown result type (might be due to invalid IL or missing references)
//IL_0024: Unknown result type (might be due to invalid IL or missing references)
//IL_002c: Expected O, but got Unknown
//IL_002d: Unknown result type (might be due to invalid IL or missing references)
//IL_0034: Unknown result type (might be due to invalid IL or missing references)
//IL_0039: Unknown result type (might be due to invalid IL or missing references)
//IL_003b: Unknown result type (might be due to invalid IL or missing references)
//IL_0045: Unknown result type (might be due to invalid IL or missing references)
//IL_004c: Unknown result type (might be due to invalid IL or missing references)
//IL_0057: Unknown result type (might be due to invalid IL or missing references)
//IL_005e: Unknown result type (might be due to invalid IL or missing references)
//IL_0066: Expected O, but got Unknown
//IL_007d: Unknown result type (might be due to invalid IL or missing references)
//IL_0084: Expected O, but got Unknown
//IL_0096: Unknown result type (might be due to invalid IL or missing references)
SKPaint val = new SKPaint
{
Color = new SKColor(byte.MaxValue, byte.MaxValue, byte.MaxValue, (byte)180),
Style = (SKPaintStyle)0
};
try
{
canvas.DrawRect(bounds, val);
SKPaint val2 = new SKPaint
{
Color = _titleBarColor,
Style = (SKPaintStyle)1,
StrokeWidth = 4f,
IsAntialias = true,
StrokeCap = (SKStrokeCap)1
};
try
{
float midX = ((SKRect)(ref bounds)).MidX;
float midY = ((SKRect)(ref bounds)).MidY;
float num = 20f;
SKPath val3 = new SKPath();
try
{
val3.AddArc(new SKRect(midX - num, midY - num, midX + num, midY + num), 0f, 270f);
canvas.DrawPath(val3, val2);
}
finally
{
((IDisposable)val3)?.Dispose();
}
}
finally
{
((IDisposable)val2)?.Dispose();
}
}
finally
{
((IDisposable)val)?.Dispose();
}
}
private void DrawBusyIndicator(SKCanvas canvas, SKRect bounds)
{
// Draw semi-transparent overlay
using var overlayPaint = new SKPaint
{
Color = new SKColor(255, 255, 255, 180),
Style = SKPaintStyle.Fill
};
canvas.DrawRect(bounds, overlayPaint);
public void OnAppearing()
{
Console.WriteLine($"[SkiaPage] OnAppearing called for: {Title}, HasListeners={this.Appearing != null}");
this.Appearing?.Invoke(this, EventArgs.Empty);
}
// Draw spinning indicator (simplified - would animate in real impl)
using var indicatorPaint = new SKPaint
{
Color = _titleBarColor,
Style = SKPaintStyle.Stroke,
StrokeWidth = 4,
IsAntialias = true,
StrokeCap = SKStrokeCap.Round
};
public void OnDisappearing()
{
this.Disappearing?.Invoke(this, EventArgs.Empty);
}
var centerX = bounds.MidX;
var centerY = bounds.MidY;
var radius = 20f;
protected override SKSize MeasureOverride(SKSize availableSize)
{
//IL_0000: Unknown result type (might be due to invalid IL or missing references)
return availableSize;
}
using var path = new SKPath();
path.AddArc(new SKRect(centerX - radius, centerY - radius, centerX + radius, centerY + radius), 0, 270);
canvas.DrawPath(path, indicatorPaint);
}
public override void OnPointerPressed(PointerEventArgs e)
{
float num = (_showNavigationBar ? _navigationBarHeight : 0f);
if (e.Y > num && _content != null)
{
PointerEventArgs e2 = new PointerEventArgs(e.X - _paddingLeft, e.Y - num - _paddingTop, e.Button);
_content.OnPointerPressed(e2);
}
}
public void OnAppearing()
{
Console.WriteLine($"[SkiaPage] OnAppearing called for: {Title}, HasListeners={Appearing != null}");
Appearing?.Invoke(this, EventArgs.Empty);
}
public override void OnPointerMoved(PointerEventArgs e)
{
float num = (_showNavigationBar ? _navigationBarHeight : 0f);
if (e.Y > num && _content != null)
{
PointerEventArgs e2 = new PointerEventArgs(e.X - _paddingLeft, e.Y - num - _paddingTop, e.Button);
_content.OnPointerMoved(e2);
}
}
public void OnDisappearing()
{
Disappearing?.Invoke(this, EventArgs.Empty);
}
public override void OnPointerReleased(PointerEventArgs e)
{
float num = (_showNavigationBar ? _navigationBarHeight : 0f);
if (e.Y > num && _content != null)
{
PointerEventArgs e2 = new PointerEventArgs(e.X - _paddingLeft, e.Y - num - _paddingTop, e.Button);
_content.OnPointerReleased(e2);
}
}
protected override SKSize MeasureOverride(SKSize availableSize)
{
// Page takes all available space
return availableSize;
}
public override void OnKeyDown(KeyEventArgs e)
{
_content?.OnKeyDown(e);
}
public override void OnPointerPressed(PointerEventArgs e)
{
// Adjust coordinates for content
var contentTop = _showNavigationBar ? _navigationBarHeight : 0;
if (e.Y > contentTop && _content != null)
{
var contentE = new PointerEventArgs(e.X - _paddingLeft, e.Y - contentTop - _paddingTop, e.Button);
_content.OnPointerPressed(contentE);
}
}
public override void OnKeyUp(KeyEventArgs e)
{
_content?.OnKeyUp(e);
}
public override void OnPointerMoved(PointerEventArgs e)
{
var contentTop = _showNavigationBar ? _navigationBarHeight : 0;
if (e.Y > contentTop && _content != null)
{
var contentE = new PointerEventArgs(e.X - _paddingLeft, e.Y - contentTop - _paddingTop, e.Button);
_content.OnPointerMoved(contentE);
}
}
public override void OnScroll(ScrollEventArgs e)
{
_content?.OnScroll(e);
}
public override void OnPointerReleased(PointerEventArgs e)
{
var contentTop = _showNavigationBar ? _navigationBarHeight : 0;
if (e.Y > contentTop && _content != null)
{
var contentE = new PointerEventArgs(e.X - _paddingLeft, e.Y - contentTop - _paddingTop, e.Button);
_content.OnPointerReleased(contentE);
}
}
public override void OnKeyDown(KeyEventArgs e)
{
_content?.OnKeyDown(e);
}
public override void OnKeyUp(KeyEventArgs e)
{
_content?.OnKeyUp(e);
}
public override void OnScroll(ScrollEventArgs e)
{
_content?.OnScroll(e);
}
public override SkiaView? HitTest(float x, float y)
{
if (!IsVisible)
return null;
// Don't check Bounds.Contains for page - it may not be set
// Just forward to content
// Check content
if (_content != null)
{
var hit = _content.HitTest(x, y);
if (hit != null)
return hit;
}
return this;
}
}
/// <summary>
/// Simple content page view with toolbar items support.
/// </summary>
public class SkiaContentPage : SkiaPage
{
private readonly List<SkiaToolbarItem> _toolbarItems = new();
/// <summary>
/// Gets the toolbar items for this page.
/// </summary>
public IList<SkiaToolbarItem> ToolbarItems => _toolbarItems;
protected override void DrawNavigationBar(SKCanvas canvas, SKRect bounds)
{
// Draw navigation bar background
using var barPaint = new SKPaint
{
Color = TitleBarColor,
Style = SKPaintStyle.Fill
};
canvas.DrawRect(bounds, barPaint);
// Draw title
if (!string.IsNullOrEmpty(Title))
{
using var font = new SKFont(SKTypeface.Default, 20);
using var textPaint = new SKPaint(font)
{
Color = TitleTextColor,
IsAntialias = true
};
var textBounds = new SKRect();
textPaint.MeasureText(Title, ref textBounds);
var x = bounds.Left + 56; // Leave space for back button
var y = bounds.MidY - textBounds.MidY;
canvas.DrawText(Title, x, y, textPaint);
}
// Draw toolbar items on the right
DrawToolbarItems(canvas, bounds);
// Draw shadow
using var shadowPaint = new SKPaint
{
Color = new SKColor(0, 0, 0, 30),
Style = SKPaintStyle.Fill,
MaskFilter = SKMaskFilter.CreateBlur(SKBlurStyle.Normal, 2)
};
canvas.DrawRect(new SKRect(bounds.Left, bounds.Bottom, bounds.Right, bounds.Bottom + 4), shadowPaint);
}
private void DrawToolbarItems(SKCanvas canvas, SKRect navBarBounds)
{
var primaryItems = _toolbarItems.Where(t => t.Order == SkiaToolbarItemOrder.Primary).ToList();
Console.WriteLine($"[SkiaContentPage] DrawToolbarItems: {primaryItems.Count} primary items, navBarBounds={navBarBounds}");
if (primaryItems.Count == 0) return;
using var font = new SKFont(SKTypeface.Default, 14);
using var textPaint = new SKPaint(font)
{
Color = TitleTextColor,
IsAntialias = true
};
float rightEdge = navBarBounds.Right - 16;
foreach (var item in primaryItems.AsEnumerable().Reverse())
{
var textBounds = new SKRect();
textPaint.MeasureText(item.Text, ref textBounds);
var itemWidth = textBounds.Width + 24; // Padding
var itemLeft = rightEdge - itemWidth;
// Store hit area for click handling
item.HitBounds = new SKRect(itemLeft, navBarBounds.Top, rightEdge, navBarBounds.Bottom);
Console.WriteLine($"[SkiaContentPage] Toolbar item '{item.Text}' HitBounds set to {item.HitBounds}");
// Draw text
var x = itemLeft + 12;
var y = navBarBounds.MidY - textBounds.MidY;
canvas.DrawText(item.Text, x, y, textPaint);
rightEdge = itemLeft - 8; // Gap between items
}
}
public override void OnPointerPressed(PointerEventArgs e)
{
Console.WriteLine($"[SkiaContentPage] OnPointerPressed at ({e.X}, {e.Y}), ShowNavigationBar={ShowNavigationBar}, NavigationBarHeight={NavigationBarHeight}");
Console.WriteLine($"[SkiaContentPage] ToolbarItems count: {_toolbarItems.Count}");
// Check toolbar item clicks
if (ShowNavigationBar && e.Y < NavigationBarHeight)
{
Console.WriteLine($"[SkiaContentPage] In navigation bar area, checking toolbar items");
foreach (var item in _toolbarItems.Where(t => t.Order == SkiaToolbarItemOrder.Primary))
{
var bounds = item.HitBounds;
var contains = bounds.Contains(e.X, e.Y);
Console.WriteLine($"[SkiaContentPage] Checking item '{item.Text}', HitBounds=({bounds.Left},{bounds.Top},{bounds.Right},{bounds.Bottom}), Click=({e.X},{e.Y}), Contains={contains}, Command={item.Command != null}");
if (contains)
{
Console.WriteLine($"[SkiaContentPage] Toolbar item clicked: {item.Text}");
item.Command?.Execute(null);
return;
}
}
Console.WriteLine($"[SkiaContentPage] No toolbar item hit");
}
base.OnPointerPressed(e);
}
}
/// <summary>
/// Represents a toolbar item in the navigation bar.
/// </summary>
public class SkiaToolbarItem
{
public string Text { get; set; } = "";
public SkiaToolbarItemOrder Order { get; set; } = SkiaToolbarItemOrder.Primary;
public System.Windows.Input.ICommand? Command { get; set; }
public SKRect HitBounds { get; set; }
}
/// <summary>
/// Order of toolbar items.
/// </summary>
public enum SkiaToolbarItemOrder
{
Primary,
Secondary
public override SkiaView? HitTest(float x, float y)
{
if (!base.IsVisible)
{
return null;
}
if (_content != null)
{
SkiaView skiaView = _content.HitTest(x, y);
if (skiaView != null)
{
return skiaView;
}
}
return this;
}
}

View File

File diff suppressed because it is too large Load Diff

View File

@@ -1,205 +1,192 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System;
using Microsoft.Maui.Controls;
using SkiaSharp;
namespace Microsoft.Maui.Platform;
/// <summary>
/// Skia-rendered progress bar control with full XAML styling support.
/// </summary>
public class SkiaProgressBar : SkiaView
{
#region BindableProperties
public static readonly BindableProperty ProgressProperty = BindableProperty.Create("Progress", typeof(double), typeof(SkiaProgressBar), (object)0.0, (BindingMode)1, (ValidateValueDelegate)null, (BindingPropertyChangedDelegate)delegate(BindableObject b, object o, object n)
{
((SkiaProgressBar)(object)b).OnProgressChanged();
}, (BindingPropertyChangingDelegate)null, (CoerceValueDelegate)((BindableObject b, object v) => Math.Clamp((double)v, 0.0, 1.0)), (CreateDefaultValueDelegate)null);
/// <summary>
/// Bindable property for Progress.
/// </summary>
public static readonly BindableProperty ProgressProperty =
BindableProperty.Create(
nameof(Progress),
typeof(double),
typeof(SkiaProgressBar),
0.0,
BindingMode.TwoWay,
coerceValue: (b, v) => Math.Clamp((double)v, 0, 1),
propertyChanged: (b, o, n) => ((SkiaProgressBar)b).OnProgressChanged());
public static readonly BindableProperty TrackColorProperty = BindableProperty.Create("TrackColor", typeof(SKColor), typeof(SkiaProgressBar), (object)new SKColor((byte)224, (byte)224, (byte)224), (BindingMode)2, (ValidateValueDelegate)null, (BindingPropertyChangedDelegate)delegate(BindableObject b, object o, object n)
{
((SkiaProgressBar)(object)b).Invalidate();
}, (BindingPropertyChangingDelegate)null, (CoerceValueDelegate)null, (CreateDefaultValueDelegate)null);
/// <summary>
/// Bindable property for TrackColor.
/// </summary>
public static readonly BindableProperty TrackColorProperty =
BindableProperty.Create(
nameof(TrackColor),
typeof(SKColor),
typeof(SkiaProgressBar),
new SKColor(0xE0, 0xE0, 0xE0),
propertyChanged: (b, o, n) => ((SkiaProgressBar)b).Invalidate());
public static readonly BindableProperty ProgressColorProperty = BindableProperty.Create("ProgressColor", typeof(SKColor), typeof(SkiaProgressBar), (object)new SKColor((byte)33, (byte)150, (byte)243), (BindingMode)2, (ValidateValueDelegate)null, (BindingPropertyChangedDelegate)delegate(BindableObject b, object o, object n)
{
((SkiaProgressBar)(object)b).Invalidate();
}, (BindingPropertyChangingDelegate)null, (CoerceValueDelegate)null, (CreateDefaultValueDelegate)null);
/// <summary>
/// Bindable property for ProgressColor.
/// </summary>
public static readonly BindableProperty ProgressColorProperty =
BindableProperty.Create(
nameof(ProgressColor),
typeof(SKColor),
typeof(SkiaProgressBar),
new SKColor(0x21, 0x96, 0xF3),
propertyChanged: (b, o, n) => ((SkiaProgressBar)b).Invalidate());
public static readonly BindableProperty DisabledColorProperty = BindableProperty.Create("DisabledColor", typeof(SKColor), typeof(SkiaProgressBar), (object)new SKColor((byte)189, (byte)189, (byte)189), (BindingMode)2, (ValidateValueDelegate)null, (BindingPropertyChangedDelegate)delegate(BindableObject b, object o, object n)
{
((SkiaProgressBar)(object)b).Invalidate();
}, (BindingPropertyChangingDelegate)null, (CoerceValueDelegate)null, (CreateDefaultValueDelegate)null);
/// <summary>
/// Bindable property for DisabledColor.
/// </summary>
public static readonly BindableProperty DisabledColorProperty =
BindableProperty.Create(
nameof(DisabledColor),
typeof(SKColor),
typeof(SkiaProgressBar),
new SKColor(0xBD, 0xBD, 0xBD),
propertyChanged: (b, o, n) => ((SkiaProgressBar)b).Invalidate());
public static readonly BindableProperty BarHeightProperty = BindableProperty.Create("BarHeight", typeof(float), typeof(SkiaProgressBar), (object)4f, (BindingMode)2, (ValidateValueDelegate)null, (BindingPropertyChangedDelegate)delegate(BindableObject b, object o, object n)
{
((SkiaProgressBar)(object)b).InvalidateMeasure();
}, (BindingPropertyChangingDelegate)null, (CoerceValueDelegate)null, (CreateDefaultValueDelegate)null);
/// <summary>
/// Bindable property for BarHeight.
/// </summary>
public static readonly BindableProperty BarHeightProperty =
BindableProperty.Create(
nameof(BarHeight),
typeof(float),
typeof(SkiaProgressBar),
4f,
propertyChanged: (b, o, n) => ((SkiaProgressBar)b).InvalidateMeasure());
public static readonly BindableProperty CornerRadiusProperty = BindableProperty.Create("CornerRadius", typeof(float), typeof(SkiaProgressBar), (object)2f, (BindingMode)2, (ValidateValueDelegate)null, (BindingPropertyChangedDelegate)delegate(BindableObject b, object o, object n)
{
((SkiaProgressBar)(object)b).Invalidate();
}, (BindingPropertyChangingDelegate)null, (CoerceValueDelegate)null, (CreateDefaultValueDelegate)null);
/// <summary>
/// Bindable property for CornerRadius.
/// </summary>
public static readonly BindableProperty CornerRadiusProperty =
BindableProperty.Create(
nameof(CornerRadius),
typeof(float),
typeof(SkiaProgressBar),
2f,
propertyChanged: (b, o, n) => ((SkiaProgressBar)b).Invalidate());
public double Progress
{
get
{
return (double)((BindableObject)this).GetValue(ProgressProperty);
}
set
{
((BindableObject)this).SetValue(ProgressProperty, (object)value);
}
}
#endregion
public SKColor TrackColor
{
get
{
//IL_000b: Unknown result type (might be due to invalid IL or missing references)
return (SKColor)((BindableObject)this).GetValue(TrackColorProperty);
}
set
{
//IL_0006: Unknown result type (might be due to invalid IL or missing references)
((BindableObject)this).SetValue(TrackColorProperty, (object)value);
}
}
#region Properties
public SKColor ProgressColor
{
get
{
//IL_000b: Unknown result type (might be due to invalid IL or missing references)
return (SKColor)((BindableObject)this).GetValue(ProgressColorProperty);
}
set
{
//IL_0006: Unknown result type (might be due to invalid IL or missing references)
((BindableObject)this).SetValue(ProgressColorProperty, (object)value);
}
}
/// <summary>
/// Gets or sets the progress value (0.0 to 1.0).
/// </summary>
public double Progress
{
get => (double)GetValue(ProgressProperty);
set => SetValue(ProgressProperty, value);
}
public SKColor DisabledColor
{
get
{
//IL_000b: Unknown result type (might be due to invalid IL or missing references)
return (SKColor)((BindableObject)this).GetValue(DisabledColorProperty);
}
set
{
//IL_0006: Unknown result type (might be due to invalid IL or missing references)
((BindableObject)this).SetValue(DisabledColorProperty, (object)value);
}
}
/// <summary>
/// Gets or sets the track color.
/// </summary>
public SKColor TrackColor
{
get => (SKColor)GetValue(TrackColorProperty);
set => SetValue(TrackColorProperty, value);
}
public float BarHeight
{
get
{
return (float)((BindableObject)this).GetValue(BarHeightProperty);
}
set
{
((BindableObject)this).SetValue(BarHeightProperty, (object)value);
}
}
/// <summary>
/// Gets or sets the progress color.
/// </summary>
public SKColor ProgressColor
{
get => (SKColor)GetValue(ProgressColorProperty);
set => SetValue(ProgressColorProperty, value);
}
public float CornerRadius
{
get
{
return (float)((BindableObject)this).GetValue(CornerRadiusProperty);
}
set
{
((BindableObject)this).SetValue(CornerRadiusProperty, (object)value);
}
}
/// <summary>
/// Gets or sets the disabled color.
/// </summary>
public SKColor DisabledColor
{
get => (SKColor)GetValue(DisabledColorProperty);
set => SetValue(DisabledColorProperty, value);
}
public event EventHandler<ProgressChangedEventArgs>? ProgressChanged;
/// <summary>
/// Gets or sets the bar height.
/// </summary>
public float BarHeight
{
get => (float)GetValue(BarHeightProperty);
set => SetValue(BarHeightProperty, value);
}
private void OnProgressChanged()
{
this.ProgressChanged?.Invoke(this, new ProgressChangedEventArgs(Progress));
Invalidate();
}
/// <summary>
/// Gets or sets the corner radius.
/// </summary>
public float CornerRadius
{
get => (float)GetValue(CornerRadiusProperty);
set => SetValue(CornerRadiusProperty, value);
}
protected override void OnDraw(SKCanvas canvas, SKRect bounds)
{
//IL_0024: Unknown result type (might be due to invalid IL or missing references)
//IL_0029: Unknown result type (might be due to invalid IL or missing references)
//IL_003b: Unknown result type (might be due to invalid IL or missing references)
//IL_0033: Unknown result type (might be due to invalid IL or missing references)
//IL_0045: Unknown result type (might be due to invalid IL or missing references)
//IL_004c: Unknown result type (might be due to invalid IL or missing references)
//IL_0054: Expected O, but got Unknown
//IL_0064: Unknown result type (might be due to invalid IL or missing references)
//IL_006f: Unknown result type (might be due to invalid IL or missing references)
//IL_0075: Expected O, but got Unknown
//IL_009f: Unknown result type (might be due to invalid IL or missing references)
//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
//IL_00c7: Unknown result type (might be due to invalid IL or missing references)
//IL_00d0: Expected O, but got Unknown
//IL_00e3: Unknown result type (might be due to invalid IL or missing references)
//IL_00ee: Unknown result type (might be due to invalid IL or missing references)
//IL_00f5: Expected O, but got Unknown
float midY = ((SKRect)(ref bounds)).MidY;
float num = midY - BarHeight / 2f;
float num2 = midY + BarHeight / 2f;
SKPaint val = new SKPaint
{
Color = (base.IsEnabled ? TrackColor : DisabledColor),
IsAntialias = true,
Style = (SKPaintStyle)0
};
try
{
SKRoundRect val2 = new SKRoundRect(new SKRect(((SKRect)(ref bounds)).Left, num, ((SKRect)(ref bounds)).Right, num2), CornerRadius);
canvas.DrawRoundRect(val2, val);
if (Progress > 0.0)
{
float num3 = ((SKRect)(ref bounds)).Width * (float)Progress;
SKPaint val3 = new SKPaint
{
Color = (base.IsEnabled ? ProgressColor : DisabledColor),
IsAntialias = true,
Style = (SKPaintStyle)0
};
try
{
SKRoundRect val4 = new SKRoundRect(new SKRect(((SKRect)(ref bounds)).Left, num, ((SKRect)(ref bounds)).Left + num3, num2), CornerRadius);
canvas.DrawRoundRect(val4, val3);
return;
}
finally
{
((IDisposable)val3)?.Dispose();
}
}
}
finally
{
((IDisposable)val)?.Dispose();
}
}
#endregion
/// <summary>
/// Event raised when progress changes.
/// </summary>
public event EventHandler<ProgressChangedEventArgs>? ProgressChanged;
private void OnProgressChanged()
{
ProgressChanged?.Invoke(this, new ProgressChangedEventArgs(Progress));
Invalidate();
}
protected override void OnDraw(SKCanvas canvas, SKRect bounds)
{
var trackY = bounds.MidY;
var trackTop = trackY - BarHeight / 2;
var trackBottom = trackY + BarHeight / 2;
// Draw track
using var trackPaint = new SKPaint
{
Color = IsEnabled ? TrackColor : DisabledColor,
IsAntialias = true,
Style = SKPaintStyle.Fill
};
var trackRect = new SKRoundRect(
new SKRect(bounds.Left, trackTop, bounds.Right, trackBottom),
CornerRadius);
canvas.DrawRoundRect(trackRect, trackPaint);
// Draw progress
if (Progress > 0)
{
var progressWidth = bounds.Width * (float)Progress;
using var progressPaint = new SKPaint
{
Color = IsEnabled ? ProgressColor : DisabledColor,
IsAntialias = true,
Style = SKPaintStyle.Fill
};
var progressRect = new SKRoundRect(
new SKRect(bounds.Left, trackTop, bounds.Left + progressWidth, trackBottom),
CornerRadius);
canvas.DrawRoundRect(progressRect, progressPaint);
}
}
protected override SKSize MeasureOverride(SKSize availableSize)
{
return new SKSize(200, BarHeight + 8);
}
}
/// <summary>
/// Event args for progress changed events.
/// </summary>
public class ProgressChangedEventArgs : EventArgs
{
public double Progress { get; }
public ProgressChangedEventArgs(double progress) => Progress = progress;
protected override SKSize MeasureOverride(SKSize availableSize)
{
//IL_0011: Unknown result type (might be due to invalid IL or missing references)
return new SKSize(200f, BarHeight + 8f);
}
}

View File

@@ -1,284 +1,442 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System;
using System.Collections.Generic;
using Microsoft.Maui.Controls;
using SkiaSharp;
namespace Microsoft.Maui.Platform;
/// <summary>
/// Skia-rendered radio button control with full XAML styling support.
/// </summary>
public class SkiaRadioButton : SkiaView
{
#region BindableProperties
public static readonly BindableProperty IsCheckedProperty = BindableProperty.Create("IsChecked", typeof(bool), typeof(SkiaRadioButton), (object)false, (BindingMode)1, (ValidateValueDelegate)null, (BindingPropertyChangedDelegate)delegate(BindableObject b, object o, object n)
{
((SkiaRadioButton)(object)b).OnIsCheckedChanged();
}, (BindingPropertyChangingDelegate)null, (CoerceValueDelegate)null, (CreateDefaultValueDelegate)null);
public static readonly BindableProperty IsCheckedProperty =
BindableProperty.Create(nameof(IsChecked), typeof(bool), typeof(SkiaRadioButton), false, BindingMode.TwoWay,
propertyChanged: (b, o, n) => ((SkiaRadioButton)b).OnIsCheckedChanged());
public static readonly BindableProperty ContentProperty = BindableProperty.Create("Content", typeof(string), typeof(SkiaRadioButton), (object)"", (BindingMode)2, (ValidateValueDelegate)null, (BindingPropertyChangedDelegate)delegate(BindableObject b, object o, object n)
{
((SkiaRadioButton)(object)b).InvalidateMeasure();
}, (BindingPropertyChangingDelegate)null, (CoerceValueDelegate)null, (CreateDefaultValueDelegate)null);
public static readonly BindableProperty ContentProperty =
BindableProperty.Create(nameof(Content), typeof(string), typeof(SkiaRadioButton), "",
propertyChanged: (b, o, n) => ((SkiaRadioButton)b).InvalidateMeasure());
public static readonly BindableProperty ValueProperty = BindableProperty.Create("Value", typeof(object), typeof(SkiaRadioButton), (object)null, (BindingMode)2, (ValidateValueDelegate)null, (BindingPropertyChangedDelegate)null, (BindingPropertyChangingDelegate)null, (CoerceValueDelegate)null, (CreateDefaultValueDelegate)null);
public static readonly BindableProperty ValueProperty =
BindableProperty.Create(nameof(Value), typeof(object), typeof(SkiaRadioButton), null);
public static readonly BindableProperty GroupNameProperty = BindableProperty.Create("GroupName", typeof(string), typeof(SkiaRadioButton), (object)null, (BindingMode)2, (ValidateValueDelegate)null, (BindingPropertyChangedDelegate)delegate(BindableObject b, object o, object n)
{
((SkiaRadioButton)(object)b).OnGroupNameChanged((string)o, (string)n);
}, (BindingPropertyChangingDelegate)null, (CoerceValueDelegate)null, (CreateDefaultValueDelegate)null);
public static readonly BindableProperty GroupNameProperty =
BindableProperty.Create(nameof(GroupName), typeof(string), typeof(SkiaRadioButton), null,
propertyChanged: (b, o, n) => ((SkiaRadioButton)b).OnGroupNameChanged((string?)o, (string?)n));
public static readonly BindableProperty RadioColorProperty = BindableProperty.Create("RadioColor", typeof(SKColor), typeof(SkiaRadioButton), (object)new SKColor((byte)33, (byte)150, (byte)243), (BindingMode)2, (ValidateValueDelegate)null, (BindingPropertyChangedDelegate)delegate(BindableObject b, object o, object n)
{
((SkiaRadioButton)(object)b).Invalidate();
}, (BindingPropertyChangingDelegate)null, (CoerceValueDelegate)null, (CreateDefaultValueDelegate)null);
public static readonly BindableProperty RadioColorProperty =
BindableProperty.Create(nameof(RadioColor), typeof(SKColor), typeof(SkiaRadioButton), new SKColor(0x21, 0x96, 0xF3),
propertyChanged: (b, o, n) => ((SkiaRadioButton)b).Invalidate());
public static readonly BindableProperty UncheckedColorProperty = BindableProperty.Create("UncheckedColor", typeof(SKColor), typeof(SkiaRadioButton), (object)new SKColor((byte)117, (byte)117, (byte)117), (BindingMode)2, (ValidateValueDelegate)null, (BindingPropertyChangedDelegate)delegate(BindableObject b, object o, object n)
{
((SkiaRadioButton)(object)b).Invalidate();
}, (BindingPropertyChangingDelegate)null, (CoerceValueDelegate)null, (CreateDefaultValueDelegate)null);
public static readonly BindableProperty UncheckedColorProperty =
BindableProperty.Create(nameof(UncheckedColor), typeof(SKColor), typeof(SkiaRadioButton), new SKColor(0x75, 0x75, 0x75),
propertyChanged: (b, o, n) => ((SkiaRadioButton)b).Invalidate());
public static readonly BindableProperty TextColorProperty = BindableProperty.Create("TextColor", typeof(SKColor), typeof(SkiaRadioButton), (object)SKColors.Black, (BindingMode)2, (ValidateValueDelegate)null, (BindingPropertyChangedDelegate)delegate(BindableObject b, object o, object n)
{
((SkiaRadioButton)(object)b).Invalidate();
}, (BindingPropertyChangingDelegate)null, (CoerceValueDelegate)null, (CreateDefaultValueDelegate)null);
public static readonly BindableProperty TextColorProperty =
BindableProperty.Create(nameof(TextColor), typeof(SKColor), typeof(SkiaRadioButton), SKColors.Black,
propertyChanged: (b, o, n) => ((SkiaRadioButton)b).Invalidate());
public static readonly BindableProperty DisabledColorProperty = BindableProperty.Create("DisabledColor", typeof(SKColor), typeof(SkiaRadioButton), (object)new SKColor((byte)189, (byte)189, (byte)189), (BindingMode)2, (ValidateValueDelegate)null, (BindingPropertyChangedDelegate)delegate(BindableObject b, object o, object n)
{
((SkiaRadioButton)(object)b).Invalidate();
}, (BindingPropertyChangingDelegate)null, (CoerceValueDelegate)null, (CreateDefaultValueDelegate)null);
public static readonly BindableProperty DisabledColorProperty =
BindableProperty.Create(nameof(DisabledColor), typeof(SKColor), typeof(SkiaRadioButton), new SKColor(0xBD, 0xBD, 0xBD),
propertyChanged: (b, o, n) => ((SkiaRadioButton)b).Invalidate());
public static readonly BindableProperty FontSizeProperty = BindableProperty.Create("FontSize", typeof(float), typeof(SkiaRadioButton), (object)14f, (BindingMode)2, (ValidateValueDelegate)null, (BindingPropertyChangedDelegate)delegate(BindableObject b, object o, object n)
{
((SkiaRadioButton)(object)b).InvalidateMeasure();
}, (BindingPropertyChangingDelegate)null, (CoerceValueDelegate)null, (CreateDefaultValueDelegate)null);
public static readonly BindableProperty FontSizeProperty =
BindableProperty.Create(nameof(FontSize), typeof(float), typeof(SkiaRadioButton), 14f,
propertyChanged: (b, o, n) => ((SkiaRadioButton)b).InvalidateMeasure());
public static readonly BindableProperty RadioSizeProperty = BindableProperty.Create("RadioSize", typeof(float), typeof(SkiaRadioButton), (object)20f, (BindingMode)2, (ValidateValueDelegate)null, (BindingPropertyChangedDelegate)delegate(BindableObject b, object o, object n)
{
((SkiaRadioButton)(object)b).InvalidateMeasure();
}, (BindingPropertyChangingDelegate)null, (CoerceValueDelegate)null, (CreateDefaultValueDelegate)null);
public static readonly BindableProperty RadioSizeProperty =
BindableProperty.Create(nameof(RadioSize), typeof(float), typeof(SkiaRadioButton), 20f,
propertyChanged: (b, o, n) => ((SkiaRadioButton)b).InvalidateMeasure());
public static readonly BindableProperty SpacingProperty = BindableProperty.Create("Spacing", typeof(float), typeof(SkiaRadioButton), (object)8f, (BindingMode)2, (ValidateValueDelegate)null, (BindingPropertyChangedDelegate)delegate(BindableObject b, object o, object n)
{
((SkiaRadioButton)(object)b).InvalidateMeasure();
}, (BindingPropertyChangingDelegate)null, (CoerceValueDelegate)null, (CreateDefaultValueDelegate)null);
public static readonly BindableProperty SpacingProperty =
BindableProperty.Create(nameof(Spacing), typeof(float), typeof(SkiaRadioButton), 8f,
propertyChanged: (b, o, n) => ((SkiaRadioButton)b).InvalidateMeasure());
private static readonly Dictionary<string, List<WeakReference<SkiaRadioButton>>> _groups = new Dictionary<string, List<WeakReference<SkiaRadioButton>>>();
#endregion
public bool IsChecked
{
get
{
return (bool)((BindableObject)this).GetValue(IsCheckedProperty);
}
set
{
((BindableObject)this).SetValue(IsCheckedProperty, (object)value);
}
}
#region Properties
public string Content
{
get
{
return (string)((BindableObject)this).GetValue(ContentProperty);
}
set
{
((BindableObject)this).SetValue(ContentProperty, (object)value);
}
}
public bool IsChecked
{
get => (bool)GetValue(IsCheckedProperty);
set => SetValue(IsCheckedProperty, value);
}
public object? Value
{
get
{
return ((BindableObject)this).GetValue(ValueProperty);
}
set
{
((BindableObject)this).SetValue(ValueProperty, value);
}
}
public string Content
{
get => (string)GetValue(ContentProperty);
set => SetValue(ContentProperty, value);
}
public string? GroupName
{
get
{
return (string)((BindableObject)this).GetValue(GroupNameProperty);
}
set
{
((BindableObject)this).SetValue(GroupNameProperty, (object)value);
}
}
public object? Value
{
get => GetValue(ValueProperty);
set => SetValue(ValueProperty, value);
}
public SKColor RadioColor
{
get
{
//IL_000b: Unknown result type (might be due to invalid IL or missing references)
return (SKColor)((BindableObject)this).GetValue(RadioColorProperty);
}
set
{
//IL_0006: Unknown result type (might be due to invalid IL or missing references)
((BindableObject)this).SetValue(RadioColorProperty, (object)value);
}
}
public string? GroupName
{
get => (string?)GetValue(GroupNameProperty);
set => SetValue(GroupNameProperty, value);
}
public SKColor UncheckedColor
{
get
{
//IL_000b: Unknown result type (might be due to invalid IL or missing references)
return (SKColor)((BindableObject)this).GetValue(UncheckedColorProperty);
}
set
{
//IL_0006: Unknown result type (might be due to invalid IL or missing references)
((BindableObject)this).SetValue(UncheckedColorProperty, (object)value);
}
}
public SKColor RadioColor
{
get => (SKColor)GetValue(RadioColorProperty);
set => SetValue(RadioColorProperty, value);
}
public SKColor TextColor
{
get
{
//IL_000b: Unknown result type (might be due to invalid IL or missing references)
return (SKColor)((BindableObject)this).GetValue(TextColorProperty);
}
set
{
//IL_0006: Unknown result type (might be due to invalid IL or missing references)
((BindableObject)this).SetValue(TextColorProperty, (object)value);
}
}
public SKColor UncheckedColor
{
get => (SKColor)GetValue(UncheckedColorProperty);
set => SetValue(UncheckedColorProperty, value);
}
public SKColor DisabledColor
{
get
{
//IL_000b: Unknown result type (might be due to invalid IL or missing references)
return (SKColor)((BindableObject)this).GetValue(DisabledColorProperty);
}
set
{
//IL_0006: Unknown result type (might be due to invalid IL or missing references)
((BindableObject)this).SetValue(DisabledColorProperty, (object)value);
}
}
public SKColor TextColor
{
get => (SKColor)GetValue(TextColorProperty);
set => SetValue(TextColorProperty, value);
}
public float FontSize
{
get
{
return (float)((BindableObject)this).GetValue(FontSizeProperty);
}
set
{
((BindableObject)this).SetValue(FontSizeProperty, (object)value);
}
}
public SKColor DisabledColor
{
get => (SKColor)GetValue(DisabledColorProperty);
set => SetValue(DisabledColorProperty, value);
}
public float RadioSize
{
get
{
return (float)((BindableObject)this).GetValue(RadioSizeProperty);
}
set
{
((BindableObject)this).SetValue(RadioSizeProperty, (object)value);
}
}
public float FontSize
{
get => (float)GetValue(FontSizeProperty);
set => SetValue(FontSizeProperty, value);
}
public float Spacing
{
get
{
return (float)((BindableObject)this).GetValue(SpacingProperty);
}
set
{
((BindableObject)this).SetValue(SpacingProperty, (object)value);
}
}
public float RadioSize
{
get => (float)GetValue(RadioSizeProperty);
set => SetValue(RadioSizeProperty, value);
}
public event EventHandler? CheckedChanged;
public float Spacing
{
get => (float)GetValue(SpacingProperty);
set => SetValue(SpacingProperty, value);
}
public SkiaRadioButton()
{
base.IsFocusable = true;
}
#endregion
private void OnIsCheckedChanged()
{
if (IsChecked && !string.IsNullOrEmpty(GroupName))
{
UncheckOthersInGroup();
}
this.CheckedChanged?.Invoke(this, EventArgs.Empty);
SkiaVisualStateManager.GoToState(this, IsChecked ? "Checked" : "Unchecked");
Invalidate();
}
private static readonly Dictionary<string, List<WeakReference<SkiaRadioButton>>> _groups = new();
private void OnGroupNameChanged(string? oldValue, string? newValue)
{
RemoveFromGroup(oldValue);
AddToGroup(newValue);
}
public event EventHandler? CheckedChanged;
private void AddToGroup(string? groupName)
{
if (!string.IsNullOrEmpty(groupName))
{
if (!_groups.TryGetValue(groupName, out List<WeakReference<SkiaRadioButton>> value))
{
value = new List<WeakReference<SkiaRadioButton>>();
_groups[groupName] = value;
}
value.RemoveAll((WeakReference<SkiaRadioButton> wr) => !wr.TryGetTarget(out SkiaRadioButton _));
value.Add(new WeakReference<SkiaRadioButton>(this));
}
}
public SkiaRadioButton()
{
IsFocusable = true;
}
private void RemoveFromGroup(string? groupName)
{
if (!string.IsNullOrEmpty(groupName) && _groups.TryGetValue(groupName, out List<WeakReference<SkiaRadioButton>> value))
{
value.RemoveAll((WeakReference<SkiaRadioButton> wr) => !wr.TryGetTarget(out SkiaRadioButton target) || target == this);
if (value.Count == 0)
{
_groups.Remove(groupName);
}
}
}
private void OnIsCheckedChanged()
{
if (IsChecked && !string.IsNullOrEmpty(GroupName))
{
UncheckOthersInGroup();
}
CheckedChanged?.Invoke(this, EventArgs.Empty);
SkiaVisualStateManager.GoToState(this, IsChecked ? SkiaVisualStateManager.CommonStates.Checked : SkiaVisualStateManager.CommonStates.Unchecked);
Invalidate();
}
private void UncheckOthersInGroup()
{
if (string.IsNullOrEmpty(GroupName) || !_groups.TryGetValue(GroupName, out List<WeakReference<SkiaRadioButton>> value))
{
return;
}
foreach (WeakReference<SkiaRadioButton> item in value)
{
if (item.TryGetTarget(out var target) && target != this && target.IsChecked)
{
((BindableObject)target).SetValue(IsCheckedProperty, (object)false);
}
}
}
private void OnGroupNameChanged(string? oldValue, string? newValue)
{
RemoveFromGroup(oldValue);
AddToGroup(newValue);
}
protected override void OnDraw(SKCanvas canvas, SKRect bounds)
{
//IL_001f: Unknown result type (might be due to invalid IL or missing references)
//IL_0024: Unknown result type (might be due to invalid IL or missing references)
//IL_002e: Unknown result type (might be due to invalid IL or missing references)
//IL_0046: Unknown result type (might be due to invalid IL or missing references)
//IL_003e: Unknown result type (might be due to invalid IL or missing references)
//IL_0050: Unknown result type (might be due to invalid IL or missing references)
//IL_0057: Unknown result type (might be due to invalid IL or missing references)
//IL_0062: Unknown result type (might be due to invalid IL or missing references)
//IL_006a: Expected O, but got Unknown
//IL_0082: Unknown result type (might be due to invalid IL or missing references)
//IL_0087: Unknown result type (might be due to invalid IL or missing references)
//IL_00da: Unknown result type (might be due to invalid IL or missing references)
//IL_00df: Unknown result type (might be due to invalid IL or missing references)
//IL_00e1: Unknown result type (might be due to invalid IL or missing references)
//IL_00e6: Unknown result type (might be due to invalid IL or missing references)
//IL_00ec: Unknown result type (might be due to invalid IL or missing references)
//IL_00f6: Unknown result type (might be due to invalid IL or missing references)
//IL_00fd: Unknown result type (might be due to invalid IL or missing references)
//IL_0106: Expected O, but got Unknown
//IL_0099: Unknown result type (might be due to invalid IL or missing references)
//IL_0091: Unknown result type (might be due to invalid IL or missing references)
//IL_014a: Unknown result type (might be due to invalid IL or missing references)
//IL_0151: Expected O, but got Unknown
//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
//IL_00b3: Expected O, but got Unknown
//IL_0153: Unknown result type (might be due to invalid IL or missing references)
//IL_0158: Unknown result type (might be due to invalid IL or missing references)
//IL_016a: Unknown result type (might be due to invalid IL or missing references)
//IL_0162: Unknown result type (might be due to invalid IL or missing references)
//IL_0174: Unknown result type (might be due to invalid IL or missing references)
//IL_017d: Expected O, but got Unknown
//IL_0196: Unknown result type (might be due to invalid IL or missing references)
float num = RadioSize / 2f;
float num2 = ((SKRect)(ref bounds)).Left + num;
float midY = ((SKRect)(ref bounds)).MidY;
SKPaint val = new SKPaint
{
Color = ((!base.IsEnabled) ? DisabledColor : (IsChecked ? RadioColor : UncheckedColor)),
Style = (SKPaintStyle)1,
StrokeWidth = 2f,
IsAntialias = true
};
try
{
canvas.DrawCircle(num2, midY, num - 1f, val);
if (IsChecked)
{
SKPaint val2 = new SKPaint
{
Color = (base.IsEnabled ? RadioColor : DisabledColor),
Style = (SKPaintStyle)0,
IsAntialias = true
};
try
{
canvas.DrawCircle(num2, midY, num - 5f, val2);
}
finally
{
((IDisposable)val2)?.Dispose();
}
}
if (base.IsFocused)
{
SKPaint val3 = new SKPaint();
SKColor radioColor = RadioColor;
val3.Color = ((SKColor)(ref radioColor)).WithAlpha((byte)80);
val3.Style = (SKPaintStyle)0;
val3.IsAntialias = true;
SKPaint val4 = val3;
try
{
canvas.DrawCircle(num2, midY, num + 4f, val4);
}
finally
{
((IDisposable)val4)?.Dispose();
}
}
if (string.IsNullOrEmpty(Content))
{
return;
}
SKFont val5 = new SKFont(SKTypeface.Default, FontSize, 1f, 0f);
try
{
SKPaint val6 = new SKPaint(val5)
{
Color = (base.IsEnabled ? TextColor : DisabledColor),
IsAntialias = true
};
try
{
float num3 = ((SKRect)(ref bounds)).Left + RadioSize + Spacing;
SKRect val7 = default(SKRect);
val6.MeasureText(Content, ref val7);
canvas.DrawText(Content, num3, ((SKRect)(ref bounds)).MidY - ((SKRect)(ref val7)).MidY, val6);
}
finally
{
((IDisposable)val6)?.Dispose();
}
}
finally
{
((IDisposable)val5)?.Dispose();
}
}
finally
{
((IDisposable)val)?.Dispose();
}
}
private void AddToGroup(string? groupName)
{
if (string.IsNullOrEmpty(groupName)) return;
public override void OnPointerPressed(PointerEventArgs e)
{
if (base.IsEnabled && !IsChecked)
{
IsChecked = true;
}
}
if (!_groups.TryGetValue(groupName, out var group))
{
group = new List<WeakReference<SkiaRadioButton>>();
_groups[groupName] = group;
}
public override void OnKeyDown(KeyEventArgs e)
{
if (base.IsEnabled && (e.Key == Key.Space || e.Key == Key.Enter))
{
if (!IsChecked)
{
IsChecked = true;
}
e.Handled = true;
}
}
group.RemoveAll(wr => !wr.TryGetTarget(out _));
group.Add(new WeakReference<SkiaRadioButton>(this));
}
protected override void OnEnabledChanged()
{
base.OnEnabledChanged();
SkiaVisualStateManager.GoToState(this, base.IsEnabled ? "Normal" : "Disabled");
}
private void RemoveFromGroup(string? groupName)
{
if (string.IsNullOrEmpty(groupName)) return;
if (_groups.TryGetValue(groupName, out var group))
{
group.RemoveAll(wr => !wr.TryGetTarget(out var target) || target == this);
if (group.Count == 0) _groups.Remove(groupName);
}
}
private void UncheckOthersInGroup()
{
if (string.IsNullOrEmpty(GroupName)) return;
if (_groups.TryGetValue(GroupName, out var group))
{
foreach (var weakRef in group)
{
if (weakRef.TryGetTarget(out var radioButton) && radioButton != this && radioButton.IsChecked)
{
radioButton.SetValue(IsCheckedProperty, false);
}
}
}
}
protected override void OnDraw(SKCanvas canvas, SKRect bounds)
{
var radioRadius = RadioSize / 2;
var radioCenterX = bounds.Left + radioRadius;
var radioCenterY = bounds.MidY;
using var outerPaint = new SKPaint
{
Color = IsEnabled ? (IsChecked ? RadioColor : UncheckedColor) : DisabledColor,
Style = SKPaintStyle.Stroke,
StrokeWidth = 2,
IsAntialias = true
};
canvas.DrawCircle(radioCenterX, radioCenterY, radioRadius - 1, outerPaint);
if (IsChecked)
{
using var innerPaint = new SKPaint
{
Color = IsEnabled ? RadioColor : DisabledColor,
Style = SKPaintStyle.Fill,
IsAntialias = true
};
canvas.DrawCircle(radioCenterX, radioCenterY, radioRadius - 5, innerPaint);
}
if (IsFocused)
{
using var focusPaint = new SKPaint
{
Color = RadioColor.WithAlpha(80),
Style = SKPaintStyle.Fill,
IsAntialias = true
};
canvas.DrawCircle(radioCenterX, radioCenterY, radioRadius + 4, focusPaint);
}
if (!string.IsNullOrEmpty(Content))
{
using var font = new SKFont(SKTypeface.Default, FontSize);
using var textPaint = new SKPaint(font)
{
Color = IsEnabled ? TextColor : DisabledColor,
IsAntialias = true
};
var textX = bounds.Left + RadioSize + Spacing;
var textBounds = new SKRect();
textPaint.MeasureText(Content, ref textBounds);
canvas.DrawText(Content, textX, bounds.MidY - textBounds.MidY, textPaint);
}
}
public override void OnPointerPressed(PointerEventArgs e)
{
if (!IsEnabled) return;
if (!IsChecked) IsChecked = true;
}
public override void OnKeyDown(KeyEventArgs e)
{
if (!IsEnabled) return;
if (e.Key == Key.Space || e.Key == Key.Enter)
{
if (!IsChecked) IsChecked = true;
e.Handled = true;
}
}
protected override void OnEnabledChanged()
{
base.OnEnabledChanged();
SkiaVisualStateManager.GoToState(this, IsEnabled ? SkiaVisualStateManager.CommonStates.Normal : SkiaVisualStateManager.CommonStates.Disabled);
}
protected override SKSize MeasureOverride(SKSize availableSize)
{
var textWidth = 0f;
if (!string.IsNullOrEmpty(Content))
{
using var font = new SKFont(SKTypeface.Default, FontSize);
using var paint = new SKPaint(font);
textWidth = paint.MeasureText(Content) + Spacing;
}
return new SKSize(RadioSize + textWidth, Math.Max(RadioSize, FontSize * 1.5f));
}
protected override SKSize MeasureOverride(SKSize availableSize)
{
//IL_007e: Unknown result type (might be due to invalid IL or missing references)
//IL_0028: Unknown result type (might be due to invalid IL or missing references)
//IL_002e: Expected O, but got Unknown
//IL_002f: Unknown result type (might be due to invalid IL or missing references)
//IL_0035: Expected O, but got Unknown
float num = 0f;
if (!string.IsNullOrEmpty(Content))
{
SKFont val = new SKFont(SKTypeface.Default, FontSize, 1f, 0f);
try
{
SKPaint val2 = new SKPaint(val);
try
{
num = val2.MeasureText(Content) + Spacing;
}
finally
{
((IDisposable)val2)?.Dispose();
}
}
finally
{
((IDisposable)val)?.Dispose();
}
}
return new SKSize(RadioSize + num, Math.Max(RadioSize, FontSize * 1.5f));
}
}

View File

@@ -1,278 +1,315 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System;
using System.Windows.Input;
using SkiaSharp;
namespace Microsoft.Maui.Platform;
/// <summary>
/// A pull-to-refresh container view.
/// </summary>
public class SkiaRefreshView : SkiaLayoutView
{
private SkiaView? _content;
private bool _isRefreshing = false;
private float _pullDistance = 0f;
private float _refreshThreshold = 80f;
private bool _isPulling = false;
private float _pullStartY;
private float _spinnerRotation = 0f;
private DateTime _lastSpinnerUpdate;
private SkiaView? _content;
/// <summary>
/// Gets or sets the content view.
/// </summary>
public SkiaView? Content
{
get => _content;
set
{
if (_content != value)
{
if (_content != null)
{
RemoveChild(_content);
}
private bool _isRefreshing;
_content = value;
private float _pullDistance;
if (_content != null)
{
AddChild(_content);
}
private float _refreshThreshold = 80f;
InvalidateMeasure();
Invalidate();
}
}
}
private bool _isPulling;
/// <summary>
/// Gets or sets whether the view is currently refreshing.
/// </summary>
public bool IsRefreshing
{
get => _isRefreshing;
set
{
if (_isRefreshing != value)
{
_isRefreshing = value;
if (!value)
{
_pullDistance = 0;
}
Invalidate();
}
}
}
private float _pullStartY;
/// <summary>
/// Gets or sets the pull distance required to trigger refresh.
/// </summary>
public float RefreshThreshold
{
get => _refreshThreshold;
set => _refreshThreshold = Math.Max(40, value);
}
private float _spinnerRotation;
/// <summary>
/// Gets or sets the refresh indicator color.
/// </summary>
public SKColor RefreshColor { get; set; } = new SKColor(33, 150, 243);
private DateTime _lastSpinnerUpdate;
/// <summary>
/// Gets or sets the background color of the refresh indicator.
/// </summary>
public SKColor RefreshBackgroundColor { get; set; } = SKColors.White;
public SkiaView? Content
{
get
{
return _content;
}
set
{
if (_content != value)
{
if (_content != null)
{
RemoveChild(_content);
}
_content = value;
if (_content != null)
{
AddChild(_content);
}
InvalidateMeasure();
Invalidate();
}
}
}
/// <summary>
/// Event raised when refresh is triggered.
/// </summary>
public event EventHandler? Refreshing;
public bool IsRefreshing
{
get
{
return _isRefreshing;
}
set
{
if (_isRefreshing != value)
{
_isRefreshing = value;
if (!value)
{
_pullDistance = 0f;
}
Invalidate();
}
}
}
protected override SKSize MeasureOverride(SKSize availableSize)
{
if (_content != null)
{
_content.Measure(availableSize);
}
return availableSize;
}
public float RefreshThreshold
{
get
{
return _refreshThreshold;
}
set
{
_refreshThreshold = Math.Max(40f, value);
}
}
protected override SKRect ArrangeOverride(SKRect bounds)
{
if (_content != null)
{
float offset = _isRefreshing ? _refreshThreshold : _pullDistance;
var contentBounds = new SKRect(
bounds.Left,
bounds.Top + offset,
bounds.Right,
bounds.Bottom + offset);
_content.Arrange(contentBounds);
}
return bounds;
}
public SKColor RefreshColor { get; set; } = new SKColor((byte)33, (byte)150, (byte)243);
protected override void OnDraw(SKCanvas canvas, SKRect bounds)
{
canvas.Save();
canvas.ClipRect(bounds);
public SKColor RefreshBackgroundColor { get; set; } = SKColors.White;
// Draw refresh indicator
float indicatorY = bounds.Top + (_isRefreshing ? _refreshThreshold : _pullDistance) / 2;
public ICommand? Command { get; set; }
if (_pullDistance > 0 || _isRefreshing)
{
DrawRefreshIndicator(canvas, bounds.MidX, indicatorY);
}
public object? CommandParameter { get; set; }
// Draw content
_content?.Draw(canvas);
public event EventHandler? Refreshing;
canvas.Restore();
}
protected override SKSize MeasureOverride(SKSize availableSize)
{
//IL_0015: Unknown result type (might be due to invalid IL or missing references)
//IL_000e: Unknown result type (might be due to invalid IL or missing references)
//IL_000f: Unknown result type (might be due to invalid IL or missing references)
if (_content != null)
{
_content.Measure(availableSize);
}
return availableSize;
}
private void DrawRefreshIndicator(SKCanvas canvas, float x, float y)
{
float size = 36f;
float progress = Math.Clamp(_pullDistance / _refreshThreshold, 0f, 1f);
protected override SKRect ArrangeOverride(SKRect bounds)
{
//IL_0052: Unknown result type (might be due to invalid IL or missing references)
//IL_004c: Unknown result type (might be due to invalid IL or missing references)
if (_content != null)
{
float num = (_isRefreshing ? _refreshThreshold : _pullDistance);
SKRect bounds2 = default(SKRect);
((SKRect)(ref bounds2))._002Ector(((SKRect)(ref bounds)).Left, ((SKRect)(ref bounds)).Top + num, ((SKRect)(ref bounds)).Right, ((SKRect)(ref bounds)).Bottom + num);
_content.Arrange(bounds2);
}
return bounds;
}
// Draw background circle
using var bgPaint = new SKPaint
{
Color = RefreshBackgroundColor,
Style = SKPaintStyle.Fill,
IsAntialias = true
};
protected override void OnDraw(SKCanvas canvas, SKRect bounds)
{
//IL_0008: Unknown result type (might be due to invalid IL or missing references)
canvas.Save();
canvas.ClipRect(bounds, (SKClipOperation)1, false);
float y = ((SKRect)(ref bounds)).Top + (_isRefreshing ? _refreshThreshold : _pullDistance) / 2f;
if (_pullDistance > 0f || _isRefreshing)
{
DrawRefreshIndicator(canvas, ((SKRect)(ref bounds)).MidX, y);
}
_content?.Draw(canvas);
canvas.Restore();
}
// Add shadow
bgPaint.ImageFilter = SKImageFilter.CreateDropShadow(0, 2, 4, 4, new SKColor(0, 0, 0, 40));
canvas.DrawCircle(x, y, size / 2, bgPaint);
private void DrawRefreshIndicator(SKCanvas canvas, float x, float y)
{
//IL_0023: Unknown result type (might be due to invalid IL or missing references)
//IL_0028: Unknown result type (might be due to invalid IL or missing references)
//IL_002a: Unknown result type (might be due to invalid IL or missing references)
//IL_0034: Unknown result type (might be due to invalid IL or missing references)
//IL_003b: Unknown result type (might be due to invalid IL or missing references)
//IL_0043: Expected O, but got Unknown
//IL_005d: Unknown result type (might be due to invalid IL or missing references)
//IL_007c: Unknown result type (might be due to invalid IL or missing references)
//IL_0081: Unknown result type (might be due to invalid IL or missing references)
//IL_0083: Unknown result type (might be due to invalid IL or missing references)
//IL_008d: Unknown result type (might be due to invalid IL or missing references)
//IL_0094: Unknown result type (might be due to invalid IL or missing references)
//IL_009f: Unknown result type (might be due to invalid IL or missing references)
//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
//IL_00ae: Expected O, but got Unknown
//IL_0185: Unknown result type (might be due to invalid IL or missing references)
//IL_018c: Expected O, but got Unknown
//IL_0111: Unknown result type (might be due to invalid IL or missing references)
//IL_0118: Expected O, but got Unknown
//IL_01aa: Unknown result type (might be due to invalid IL or missing references)
//IL_01af: Unknown result type (might be due to invalid IL or missing references)
//IL_01bc: Unknown result type (might be due to invalid IL or missing references)
//IL_0136: Unknown result type (might be due to invalid IL or missing references)
//IL_013b: Unknown result type (might be due to invalid IL or missing references)
//IL_013f: Unknown result type (might be due to invalid IL or missing references)
float num = 36f;
float num2 = Math.Clamp(_pullDistance / _refreshThreshold, 0f, 1f);
SKPaint val = new SKPaint
{
Color = RefreshBackgroundColor,
Style = (SKPaintStyle)0,
IsAntialias = true
};
try
{
val.ImageFilter = SKImageFilter.CreateDropShadow(0f, 2f, 4f, 4f, new SKColor((byte)0, (byte)0, (byte)0, (byte)40));
canvas.DrawCircle(x, y, num / 2f, val);
SKPaint val2 = new SKPaint
{
Color = RefreshColor,
Style = (SKPaintStyle)1,
StrokeWidth = 3f,
IsAntialias = true,
StrokeCap = (SKStrokeCap)1
};
try
{
if (_isRefreshing)
{
DateTime utcNow = DateTime.UtcNow;
float num3 = (float)(utcNow - _lastSpinnerUpdate).TotalMilliseconds;
_spinnerRotation += num3 * 0.36f;
_lastSpinnerUpdate = utcNow;
canvas.Save();
canvas.Translate(x, y);
canvas.RotateDegrees(_spinnerRotation);
SKPath val3 = new SKPath();
try
{
SKRect val4 = new SKRect((0f - num) / 3f, (0f - num) / 3f, num / 3f, num / 3f);
val3.AddArc(val4, 0f, 270f);
canvas.DrawPath(val3, val2);
canvas.Restore();
Invalidate();
return;
}
finally
{
((IDisposable)val3)?.Dispose();
}
}
canvas.Save();
canvas.Translate(x, y);
SKPath val5 = new SKPath();
try
{
SKRect val6 = new SKRect((0f - num) / 3f, (0f - num) / 3f, num / 3f, num / 3f);
float num4 = 270f * num2;
val5.AddArc(val6, -90f, num4);
canvas.DrawPath(val5, val2);
canvas.Restore();
}
finally
{
((IDisposable)val5)?.Dispose();
}
}
finally
{
((IDisposable)val2)?.Dispose();
}
}
finally
{
((IDisposable)val)?.Dispose();
}
}
// Draw spinner
using var spinnerPaint = new SKPaint
{
Color = RefreshColor,
Style = SKPaintStyle.Stroke,
StrokeWidth = 3,
IsAntialias = true,
StrokeCap = SKStrokeCap.Round
};
public override SkiaView? HitTest(float x, float y)
{
//IL_0009: Unknown result type (might be due to invalid IL or missing references)
//IL_000e: Unknown result type (might be due to invalid IL or missing references)
if (base.IsVisible)
{
SKRect bounds = base.Bounds;
if (((SKRect)(ref bounds)).Contains(x, y))
{
if (_content != null)
{
SkiaView skiaView = _content.HitTest(x, y);
if (skiaView != null)
{
return skiaView;
}
}
return this;
}
}
return null;
}
if (_isRefreshing)
{
// Animate spinner
var now = DateTime.UtcNow;
float elapsed = (float)(now - _lastSpinnerUpdate).TotalMilliseconds;
_spinnerRotation += elapsed * 0.36f; // 360 degrees per second
_lastSpinnerUpdate = now;
public override void OnPointerPressed(PointerEventArgs e)
{
if (base.IsEnabled && !_isRefreshing)
{
bool flag = true;
if (_content is SkiaScrollView skiaScrollView)
{
flag = skiaScrollView.ScrollY <= 0f;
}
if (flag)
{
_isPulling = true;
_pullStartY = e.Y;
_pullDistance = 0f;
}
base.OnPointerPressed(e);
}
}
canvas.Save();
canvas.Translate(x, y);
canvas.RotateDegrees(_spinnerRotation);
public override void OnPointerMoved(PointerEventArgs e)
{
if (_isPulling)
{
float num = e.Y - _pullStartY;
if (num > 0f)
{
_pullDistance = num * 0.5f;
_pullDistance = Math.Min(_pullDistance, _refreshThreshold * 1.5f);
Invalidate();
e.Handled = true;
}
else
{
_pullDistance = 0f;
}
base.OnPointerMoved(e);
}
}
// Draw spinning arc
using var path = new SKPath();
var rect = new SKRect(-size / 3, -size / 3, size / 3, size / 3);
path.AddArc(rect, 0, 270);
canvas.DrawPath(path, spinnerPaint);
canvas.Restore();
Invalidate(); // Continue animation
}
else
{
// Draw progress arc
canvas.Save();
canvas.Translate(x, y);
using var path = new SKPath();
var rect = new SKRect(-size / 3, -size / 3, size / 3, size / 3);
float sweepAngle = 270 * progress;
path.AddArc(rect, -90, sweepAngle);
canvas.DrawPath(path, spinnerPaint);
canvas.Restore();
}
}
public override SkiaView? HitTest(float x, float y)
{
if (!IsVisible || !Bounds.Contains(x, y)) return null;
if (_content != null)
{
var hit = _content.HitTest(x, y);
if (hit != null) return hit;
}
return this;
}
public override void OnPointerPressed(PointerEventArgs e)
{
if (!IsEnabled || _isRefreshing) return;
// Check if content is at top (can pull to refresh)
bool canPull = true;
if (_content is SkiaScrollView scrollView)
{
canPull = scrollView.ScrollY <= 0;
}
if (canPull)
{
_isPulling = true;
_pullStartY = e.Y;
_pullDistance = 0;
}
base.OnPointerPressed(e);
}
public override void OnPointerMoved(PointerEventArgs e)
{
if (!_isPulling) return;
float delta = e.Y - _pullStartY;
if (delta > 0)
{
// Apply resistance
_pullDistance = delta * 0.5f;
_pullDistance = Math.Min(_pullDistance, _refreshThreshold * 1.5f);
Invalidate();
e.Handled = true;
}
else
{
_pullDistance = 0;
}
base.OnPointerMoved(e);
}
public override void OnPointerReleased(PointerEventArgs e)
{
if (!_isPulling) return;
_isPulling = false;
if (_pullDistance >= _refreshThreshold)
{
_isRefreshing = true;
_pullDistance = _refreshThreshold;
_lastSpinnerUpdate = DateTime.UtcNow;
Refreshing?.Invoke(this, EventArgs.Empty);
}
else
{
_pullDistance = 0;
}
Invalidate();
base.OnPointerReleased(e);
}
public override void OnPointerReleased(PointerEventArgs e)
{
if (_isPulling)
{
_isPulling = false;
if (_pullDistance >= _refreshThreshold)
{
_isRefreshing = true;
_pullDistance = _refreshThreshold;
_lastSpinnerUpdate = DateTime.UtcNow;
this.Refreshing?.Invoke(this, EventArgs.Empty);
Command?.Execute(CommandParameter);
}
else
{
_pullDistance = 0f;
}
Invalidate();
base.OnPointerReleased(e);
}
}
}

View File

File diff suppressed because it is too large Load Diff

View File

@@ -1,242 +1,356 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System;
using SkiaSharp;
using Microsoft.Maui.Platform.Linux.Rendering;
namespace Microsoft.Maui.Platform;
/// <summary>
/// Skia-rendered search bar control.
/// </summary>
public class SkiaSearchBar : SkiaView
{
private readonly SkiaEntry _entry;
private bool _showClearButton;
private readonly SkiaEntry _entry;
public string Text
{
get => _entry.Text;
set => _entry.Text = value;
}
private bool _showClearButton;
public string Placeholder
{
get => _entry.Placeholder;
set => _entry.Placeholder = value;
}
public string Text
{
get
{
return _entry.Text;
}
set
{
_entry.Text = value;
}
}
public SKColor TextColor
{
get => _entry.TextColor;
set => _entry.TextColor = value;
}
public string Placeholder
{
get
{
return _entry.Placeholder;
}
set
{
_entry.Placeholder = value;
}
}
public SKColor PlaceholderColor
{
get => _entry.PlaceholderColor;
set => _entry.PlaceholderColor = value;
}
public SKColor TextColor
{
get
{
//IL_0006: Unknown result type (might be due to invalid IL or missing references)
return _entry.TextColor;
}
set
{
//IL_0006: Unknown result type (might be due to invalid IL or missing references)
_entry.TextColor = value;
}
}
public new SKColor BackgroundColor { get; set; } = new SKColor(0xF5, 0xF5, 0xF5);
public SKColor IconColor { get; set; } = new SKColor(0x75, 0x75, 0x75);
public SKColor ClearButtonColor { get; set; } = new SKColor(0x9E, 0x9E, 0x9E);
public SKColor FocusedBorderColor { get; set; } = new SKColor(0x21, 0x96, 0xF3);
public string FontFamily { get; set; } = "Sans";
public float FontSize { get; set; } = 14;
public float CornerRadius { get; set; } = 8;
public float IconSize { get; set; } = 20;
public SKColor PlaceholderColor
{
get
{
//IL_0006: Unknown result type (might be due to invalid IL or missing references)
return _entry.PlaceholderColor;
}
set
{
//IL_0006: Unknown result type (might be due to invalid IL or missing references)
_entry.PlaceholderColor = value;
}
}
public event EventHandler<TextChangedEventArgs>? TextChanged;
public event EventHandler? SearchButtonPressed;
public new SKColor BackgroundColor { get; set; } = new SKColor((byte)245, (byte)245, (byte)245);
public SkiaSearchBar()
{
_entry = new SkiaEntry
{
Placeholder = "Search...",
EntryBackgroundColor = SKColors.Transparent,
BackgroundColor = SKColors.Transparent,
BorderColor = SKColors.Transparent,
FocusedBorderColor = SKColors.Transparent,
BorderWidth = 0
};
public SKColor IconColor { get; set; } = new SKColor((byte)117, (byte)117, (byte)117);
_entry.TextChanged += (s, e) =>
{
_showClearButton = !string.IsNullOrEmpty(e.NewTextValue);
TextChanged?.Invoke(this, e);
Invalidate();
};
public SKColor ClearButtonColor { get; set; } = new SKColor((byte)158, (byte)158, (byte)158);
_entry.Completed += (s, e) => SearchButtonPressed?.Invoke(this, EventArgs.Empty);
public SKColor FocusedBorderColor { get; set; } = new SKColor((byte)33, (byte)150, (byte)243);
IsFocusable = true;
}
public string FontFamily { get; set; } = "Sans";
protected override void OnDraw(SKCanvas canvas, SKRect bounds)
{
var iconPadding = 12f;
var clearButtonSize = 20f;
public float FontSize { get; set; } = 14f;
// Draw background
using var bgPaint = new SKPaint
{
Color = BackgroundColor,
IsAntialias = true,
Style = SKPaintStyle.Fill
};
public float CornerRadius { get; set; } = 8f;
var bgRect = new SKRoundRect(bounds, CornerRadius);
canvas.DrawRoundRect(bgRect, bgPaint);
public float IconSize { get; set; } = 20f;
// Draw focus border
if (IsFocused || _entry.IsFocused)
{
using var borderPaint = new SKPaint
{
Color = FocusedBorderColor,
IsAntialias = true,
Style = SKPaintStyle.Stroke,
StrokeWidth = 2
};
canvas.DrawRoundRect(bgRect, borderPaint);
}
public event EventHandler<TextChangedEventArgs>? TextChanged;
// Draw search icon
var iconX = bounds.Left + iconPadding;
var iconY = bounds.MidY;
DrawSearchIcon(canvas, iconX, iconY, IconSize);
public event EventHandler? SearchButtonPressed;
// Calculate entry bounds - leave space for clear button
var entryLeft = iconX + IconSize + iconPadding;
var entryRight = _showClearButton
? bounds.Right - clearButtonSize - iconPadding * 2
: bounds.Right - iconPadding;
public SkiaSearchBar()
{
//IL_0010: Unknown result type (might be due to invalid IL or missing references)
//IL_0015: Unknown result type (might be due to invalid IL or missing references)
//IL_0021: Unknown result type (might be due to invalid IL or missing references)
//IL_0026: Unknown result type (might be due to invalid IL or missing references)
//IL_003b: Unknown result type (might be due to invalid IL or missing references)
//IL_0040: Unknown result type (might be due to invalid IL or missing references)
//IL_0052: Unknown result type (might be due to invalid IL or missing references)
//IL_0057: Unknown result type (might be due to invalid IL or missing references)
//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
//IL_00c1: Unknown result type (might be due to invalid IL or missing references)
_entry = new SkiaEntry
{
Placeholder = "Search...",
EntryBackgroundColor = SKColors.Transparent,
BackgroundColor = SKColors.Transparent,
BorderColor = SKColors.Transparent,
FocusedBorderColor = SKColors.Transparent,
BorderWidth = 0f
};
_entry.TextChanged += delegate(object? s, TextChangedEventArgs e)
{
_showClearButton = !string.IsNullOrEmpty(e.NewTextValue);
this.TextChanged?.Invoke(this, e);
Invalidate();
};
_entry.Completed += delegate
{
this.SearchButtonPressed?.Invoke(this, EventArgs.Empty);
};
base.IsFocusable = true;
}
var entryBounds = new SKRect(entryLeft, bounds.Top, entryRight, bounds.Bottom);
_entry.Arrange(entryBounds);
_entry.Draw(canvas);
protected override void OnDraw(SKCanvas canvas, SKRect bounds)
{
//IL_000c: Unknown result type (might be due to invalid IL or missing references)
//IL_0011: Unknown result type (might be due to invalid IL or missing references)
//IL_0013: Unknown result type (might be due to invalid IL or missing references)
//IL_001d: Unknown result type (might be due to invalid IL or missing references)
//IL_0024: Unknown result type (might be due to invalid IL or missing references)
//IL_002c: Expected O, but got Unknown
//IL_002c: Unknown result type (might be due to invalid IL or missing references)
//IL_0033: Unknown result type (might be due to invalid IL or missing references)
//IL_0039: Expected O, but got Unknown
//IL_0056: Unknown result type (might be due to invalid IL or missing references)
//IL_005b: Unknown result type (might be due to invalid IL or missing references)
//IL_005d: Unknown result type (might be due to invalid IL or missing references)
//IL_0067: Unknown result type (might be due to invalid IL or missing references)
//IL_006e: Unknown result type (might be due to invalid IL or missing references)
//IL_0075: Unknown result type (might be due to invalid IL or missing references)
//IL_0082: Expected O, but got Unknown
//IL_0103: Unknown result type (might be due to invalid IL or missing references)
//IL_0108: Unknown result type (might be due to invalid IL or missing references)
//IL_0110: Unknown result type (might be due to invalid IL or missing references)
float num = 12f;
float num2 = 20f;
SKPaint val = new SKPaint
{
Color = BackgroundColor,
IsAntialias = true,
Style = (SKPaintStyle)0
};
try
{
SKRoundRect val2 = new SKRoundRect(bounds, CornerRadius);
canvas.DrawRoundRect(val2, val);
if (base.IsFocused || _entry.IsFocused)
{
SKPaint val3 = new SKPaint
{
Color = FocusedBorderColor,
IsAntialias = true,
Style = (SKPaintStyle)1,
StrokeWidth = 2f
};
try
{
canvas.DrawRoundRect(val2, val3);
}
finally
{
((IDisposable)val3)?.Dispose();
}
}
float num3 = ((SKRect)(ref bounds)).Left + num;
float midY = ((SKRect)(ref bounds)).MidY;
DrawSearchIcon(canvas, num3, midY, IconSize);
float num4 = num3 + IconSize + num;
float num5 = (_showClearButton ? (((SKRect)(ref bounds)).Right - num2 - num * 2f) : (((SKRect)(ref bounds)).Right - num));
SKRect bounds2 = new SKRect(num4, ((SKRect)(ref bounds)).Top, num5, ((SKRect)(ref bounds)).Bottom);
_entry.Arrange(bounds2);
_entry.Draw(canvas);
if (_showClearButton)
{
float x = ((SKRect)(ref bounds)).Right - num - num2 / 2f;
float midY2 = ((SKRect)(ref bounds)).MidY;
DrawClearButton(canvas, x, midY2, num2 / 2f);
}
}
finally
{
((IDisposable)val)?.Dispose();
}
}
// Draw clear button
if (_showClearButton)
{
var clearX = bounds.Right - iconPadding - clearButtonSize / 2;
var clearY = bounds.MidY;
DrawClearButton(canvas, clearX, clearY, clearButtonSize / 2);
}
}
private void DrawSearchIcon(SKCanvas canvas, float x, float y, float size)
{
//IL_0000: Unknown result type (might be due to invalid IL or missing references)
//IL_0005: Unknown result type (might be due to invalid IL or missing references)
//IL_0007: Unknown result type (might be due to invalid IL or missing references)
//IL_0011: Unknown result type (might be due to invalid IL or missing references)
//IL_0018: Unknown result type (might be due to invalid IL or missing references)
//IL_001f: Unknown result type (might be due to invalid IL or missing references)
//IL_002a: Unknown result type (might be due to invalid IL or missing references)
//IL_0032: Expected O, but got Unknown
//IL_0047: Unknown result type (might be due to invalid IL or missing references)
//IL_004c: Unknown result type (might be due to invalid IL or missing references)
//IL_004e: Unknown result type (might be due to invalid IL or missing references)
//IL_0074: Unknown result type (might be due to invalid IL or missing references)
//IL_0079: Unknown result type (might be due to invalid IL or missing references)
//IL_008e: Unknown result type (might be due to invalid IL or missing references)
//IL_0093: Unknown result type (might be due to invalid IL or missing references)
//IL_0096: Unknown result type (might be due to invalid IL or missing references)
//IL_0097: Unknown result type (might be due to invalid IL or missing references)
SKPaint val = new SKPaint
{
Color = IconColor,
IsAntialias = true,
Style = (SKPaintStyle)1,
StrokeWidth = 2f,
StrokeCap = (SKStrokeCap)1
};
try
{
float num = size * 0.35f;
SKPoint val2 = new SKPoint(x + num, y - num * 0.3f);
canvas.DrawCircle(val2, num, val);
SKPoint val3 = new SKPoint(((SKPoint)(ref val2)).X + num * 0.7f, ((SKPoint)(ref val2)).Y + num * 0.7f);
SKPoint val4 = new SKPoint(x + size * 0.8f, y + size * 0.3f);
canvas.DrawLine(val3, val4, val);
}
finally
{
((IDisposable)val)?.Dispose();
}
}
private void DrawSearchIcon(SKCanvas canvas, float x, float y, float size)
{
using var paint = new SKPaint
{
Color = IconColor,
IsAntialias = true,
Style = SKPaintStyle.Stroke,
StrokeWidth = 2,
StrokeCap = SKStrokeCap.Round
};
private void DrawClearButton(SKCanvas canvas, float x, float y, float radius)
{
//IL_0000: Unknown result type (might be due to invalid IL or missing references)
//IL_0005: Unknown result type (might be due to invalid IL or missing references)
//IL_0007: Unknown result type (might be due to invalid IL or missing references)
//IL_000c: Unknown result type (might be due to invalid IL or missing references)
//IL_0011: Unknown result type (might be due to invalid IL or missing references)
//IL_001b: Unknown result type (might be due to invalid IL or missing references)
//IL_0022: Unknown result type (might be due to invalid IL or missing references)
//IL_002a: Expected O, but got Unknown
//IL_003b: Unknown result type (might be due to invalid IL or missing references)
//IL_0040: Unknown result type (might be due to invalid IL or missing references)
//IL_0042: Unknown result type (might be due to invalid IL or missing references)
//IL_004c: Unknown result type (might be due to invalid IL or missing references)
//IL_0053: Unknown result type (might be due to invalid IL or missing references)
//IL_005a: Unknown result type (might be due to invalid IL or missing references)
//IL_0065: Unknown result type (might be due to invalid IL or missing references)
//IL_006d: Expected O, but got Unknown
SKPaint val = new SKPaint();
SKColor clearButtonColor = ClearButtonColor;
val.Color = ((SKColor)(ref clearButtonColor)).WithAlpha((byte)80);
val.IsAntialias = true;
val.Style = (SKPaintStyle)0;
SKPaint val2 = val;
try
{
canvas.DrawCircle(x, y, radius + 2f, val2);
SKPaint val3 = new SKPaint
{
Color = ClearButtonColor,
IsAntialias = true,
Style = (SKPaintStyle)1,
StrokeWidth = 2f,
StrokeCap = (SKStrokeCap)1
};
try
{
float num = radius * 0.5f;
canvas.DrawLine(x - num, y - num, x + num, y + num, val3);
canvas.DrawLine(x + num, y - num, x - num, y + num, val3);
}
finally
{
((IDisposable)val3)?.Dispose();
}
}
finally
{
((IDisposable)val2)?.Dispose();
}
}
var circleRadius = size * 0.35f;
var circleCenter = new SKPoint(x + circleRadius, y - circleRadius * 0.3f);
public override void OnPointerPressed(PointerEventArgs e)
{
//IL_0010: Unknown result type (might be due to invalid IL or missing references)
//IL_0015: Unknown result type (might be due to invalid IL or missing references)
//IL_0029: Unknown result type (might be due to invalid IL or missing references)
//IL_002e: Unknown result type (might be due to invalid IL or missing references)
if (!base.IsEnabled)
{
return;
}
float x = e.X;
SKRect bounds = base.Bounds;
float num = x - ((SKRect)(ref bounds)).Left;
if (_showClearButton)
{
bounds = base.Bounds;
if (num >= ((SKRect)(ref bounds)).Width - 40f)
{
Text = "";
Invalidate();
return;
}
}
_entry.IsFocused = true;
base.IsFocused = true;
_entry.OnPointerPressed(e);
Invalidate();
}
// Draw magnifying glass circle
canvas.DrawCircle(circleCenter, circleRadius, paint);
public override void OnPointerMoved(PointerEventArgs e)
{
if (base.IsEnabled)
{
_entry.OnPointerMoved(e);
}
}
// Draw handle
var handleStart = new SKPoint(
circleCenter.X + circleRadius * 0.7f,
circleCenter.Y + circleRadius * 0.7f);
var handleEnd = new SKPoint(
x + size * 0.8f,
y + size * 0.3f);
canvas.DrawLine(handleStart, handleEnd, paint);
}
public override void OnPointerReleased(PointerEventArgs e)
{
_entry.OnPointerReleased(e);
}
private void DrawClearButton(SKCanvas canvas, float x, float y, float radius)
{
// Draw circle background
using var bgPaint = new SKPaint
{
Color = ClearButtonColor.WithAlpha(80),
IsAntialias = true,
Style = SKPaintStyle.Fill
};
canvas.DrawCircle(x, y, radius + 2, bgPaint);
public override void OnTextInput(TextInputEventArgs e)
{
_entry.OnTextInput(e);
}
// Draw X
using var paint = new SKPaint
{
Color = ClearButtonColor,
IsAntialias = true,
Style = SKPaintStyle.Stroke,
StrokeWidth = 2,
StrokeCap = SKStrokeCap.Round
};
public override void OnKeyDown(KeyEventArgs e)
{
if (e.Key == Key.Escape && _showClearButton)
{
Text = "";
e.Handled = true;
}
else
{
_entry.OnKeyDown(e);
}
}
var offset = radius * 0.5f;
canvas.DrawLine(x - offset, y - offset, x + offset, y + offset, paint);
canvas.DrawLine(x + offset, y - offset, x - offset, y + offset, paint);
}
public override void OnKeyUp(KeyEventArgs e)
{
_entry.OnKeyUp(e);
}
public override void OnPointerPressed(PointerEventArgs e)
{
if (!IsEnabled) return;
// Convert to local coordinates (relative to this view's bounds)
var localX = e.X - Bounds.Left;
// Check if clear button was clicked (in the rightmost 40 pixels)
if (_showClearButton && localX >= Bounds.Width - 40)
{
Text = "";
Invalidate();
return;
}
// Forward to entry for text input focus and selection
_entry.IsFocused = true;
IsFocused = true;
_entry.OnPointerPressed(e);
Invalidate();
}
public override void OnPointerMoved(PointerEventArgs e)
{
if (!IsEnabled) return;
_entry.OnPointerMoved(e);
}
public override void OnPointerReleased(PointerEventArgs e)
{
_entry.OnPointerReleased(e);
}
public override void OnTextInput(TextInputEventArgs e)
{
_entry.OnTextInput(e);
}
public override void OnKeyDown(KeyEventArgs e)
{
if (e.Key == Key.Escape && _showClearButton)
{
Text = "";
e.Handled = true;
return;
}
_entry.OnKeyDown(e);
}
public override void OnKeyUp(KeyEventArgs e)
{
_entry.OnKeyUp(e);
}
protected override SKSize MeasureOverride(SKSize availableSize)
{
return new SKSize(250, 40);
}
protected override SKSize MeasureOverride(SKSize availableSize)
{
//IL_000a: Unknown result type (might be due to invalid IL or missing references)
return new SKSize(250f, 40f);
}
}

View File

@@ -0,0 +1,8 @@
namespace Microsoft.Maui.Platform;
public enum SkiaSelectionMode
{
None,
Single,
Multiple
}

View File

File diff suppressed because it is too large Load Diff

View File

@@ -1,398 +1,415 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System;
using Microsoft.Maui.Controls;
using SkiaSharp;
namespace Microsoft.Maui.Platform;
/// <summary>
/// Skia-rendered slider control with full XAML styling support.
/// </summary>
public class SkiaSlider : SkiaView
{
#region BindableProperties
public static readonly BindableProperty MinimumProperty = BindableProperty.Create("Minimum", typeof(double), typeof(SkiaSlider), (object)0.0, (BindingMode)2, (ValidateValueDelegate)null, (BindingPropertyChangedDelegate)delegate(BindableObject b, object o, object n)
{
((SkiaSlider)(object)b).OnRangeChanged();
}, (BindingPropertyChangingDelegate)null, (CoerceValueDelegate)null, (CreateDefaultValueDelegate)null);
/// <summary>
/// Bindable property for Minimum.
/// </summary>
public static readonly BindableProperty MinimumProperty =
BindableProperty.Create(
nameof(Minimum),
typeof(double),
typeof(SkiaSlider),
0.0,
propertyChanged: (b, o, n) => ((SkiaSlider)b).OnRangeChanged());
public static readonly BindableProperty MaximumProperty = BindableProperty.Create("Maximum", typeof(double), typeof(SkiaSlider), (object)100.0, (BindingMode)2, (ValidateValueDelegate)null, (BindingPropertyChangedDelegate)delegate(BindableObject b, object o, object n)
{
((SkiaSlider)(object)b).OnRangeChanged();
}, (BindingPropertyChangingDelegate)null, (CoerceValueDelegate)null, (CreateDefaultValueDelegate)null);
/// <summary>
/// Bindable property for Maximum.
/// </summary>
public static readonly BindableProperty MaximumProperty =
BindableProperty.Create(
nameof(Maximum),
typeof(double),
typeof(SkiaSlider),
100.0,
propertyChanged: (b, o, n) => ((SkiaSlider)b).OnRangeChanged());
public static readonly BindableProperty ValueProperty = BindableProperty.Create("Value", typeof(double), typeof(SkiaSlider), (object)0.0, (BindingMode)1, (ValidateValueDelegate)null, (BindingPropertyChangedDelegate)delegate(BindableObject b, object o, object n)
{
((SkiaSlider)(object)b).OnValuePropertyChanged((double)o, (double)n);
}, (BindingPropertyChangingDelegate)null, (CoerceValueDelegate)null, (CreateDefaultValueDelegate)null);
/// <summary>
/// Bindable property for Value.
/// </summary>
public static readonly BindableProperty ValueProperty =
BindableProperty.Create(
nameof(Value),
typeof(double),
typeof(SkiaSlider),
0.0,
BindingMode.TwoWay,
propertyChanged: (b, o, n) => ((SkiaSlider)b).OnValuePropertyChanged((double)o, (double)n));
public static readonly BindableProperty TrackColorProperty = BindableProperty.Create("TrackColor", typeof(SKColor), typeof(SkiaSlider), (object)new SKColor((byte)224, (byte)224, (byte)224), (BindingMode)2, (ValidateValueDelegate)null, (BindingPropertyChangedDelegate)delegate(BindableObject b, object o, object n)
{
((SkiaSlider)(object)b).Invalidate();
}, (BindingPropertyChangingDelegate)null, (CoerceValueDelegate)null, (CreateDefaultValueDelegate)null);
/// <summary>
/// Bindable property for TrackColor.
/// </summary>
public static readonly BindableProperty TrackColorProperty =
BindableProperty.Create(
nameof(TrackColor),
typeof(SKColor),
typeof(SkiaSlider),
new SKColor(0xE0, 0xE0, 0xE0),
propertyChanged: (b, o, n) => ((SkiaSlider)b).Invalidate());
public static readonly BindableProperty ActiveTrackColorProperty = BindableProperty.Create("ActiveTrackColor", typeof(SKColor), typeof(SkiaSlider), (object)new SKColor((byte)33, (byte)150, (byte)243), (BindingMode)2, (ValidateValueDelegate)null, (BindingPropertyChangedDelegate)delegate(BindableObject b, object o, object n)
{
((SkiaSlider)(object)b).Invalidate();
}, (BindingPropertyChangingDelegate)null, (CoerceValueDelegate)null, (CreateDefaultValueDelegate)null);
/// <summary>
/// Bindable property for ActiveTrackColor.
/// </summary>
public static readonly BindableProperty ActiveTrackColorProperty =
BindableProperty.Create(
nameof(ActiveTrackColor),
typeof(SKColor),
typeof(SkiaSlider),
new SKColor(0x21, 0x96, 0xF3),
propertyChanged: (b, o, n) => ((SkiaSlider)b).Invalidate());
public static readonly BindableProperty ThumbColorProperty = BindableProperty.Create("ThumbColor", typeof(SKColor), typeof(SkiaSlider), (object)new SKColor((byte)33, (byte)150, (byte)243), (BindingMode)2, (ValidateValueDelegate)null, (BindingPropertyChangedDelegate)delegate(BindableObject b, object o, object n)
{
((SkiaSlider)(object)b).Invalidate();
}, (BindingPropertyChangingDelegate)null, (CoerceValueDelegate)null, (CreateDefaultValueDelegate)null);
/// <summary>
/// Bindable property for ThumbColor.
/// </summary>
public static readonly BindableProperty ThumbColorProperty =
BindableProperty.Create(
nameof(ThumbColor),
typeof(SKColor),
typeof(SkiaSlider),
new SKColor(0x21, 0x96, 0xF3),
propertyChanged: (b, o, n) => ((SkiaSlider)b).Invalidate());
public static readonly BindableProperty DisabledColorProperty = BindableProperty.Create("DisabledColor", typeof(SKColor), typeof(SkiaSlider), (object)new SKColor((byte)189, (byte)189, (byte)189), (BindingMode)2, (ValidateValueDelegate)null, (BindingPropertyChangedDelegate)delegate(BindableObject b, object o, object n)
{
((SkiaSlider)(object)b).Invalidate();
}, (BindingPropertyChangingDelegate)null, (CoerceValueDelegate)null, (CreateDefaultValueDelegate)null);
/// <summary>
/// Bindable property for DisabledColor.
/// </summary>
public static readonly BindableProperty DisabledColorProperty =
BindableProperty.Create(
nameof(DisabledColor),
typeof(SKColor),
typeof(SkiaSlider),
new SKColor(0xBD, 0xBD, 0xBD),
propertyChanged: (b, o, n) => ((SkiaSlider)b).Invalidate());
public static readonly BindableProperty TrackHeightProperty = BindableProperty.Create("TrackHeight", typeof(float), typeof(SkiaSlider), (object)4f, (BindingMode)2, (ValidateValueDelegate)null, (BindingPropertyChangedDelegate)delegate(BindableObject b, object o, object n)
{
((SkiaSlider)(object)b).Invalidate();
}, (BindingPropertyChangingDelegate)null, (CoerceValueDelegate)null, (CreateDefaultValueDelegate)null);
/// <summary>
/// Bindable property for TrackHeight.
/// </summary>
public static readonly BindableProperty TrackHeightProperty =
BindableProperty.Create(
nameof(TrackHeight),
typeof(float),
typeof(SkiaSlider),
4f,
propertyChanged: (b, o, n) => ((SkiaSlider)b).Invalidate());
public static readonly BindableProperty ThumbRadiusProperty = BindableProperty.Create("ThumbRadius", typeof(float), typeof(SkiaSlider), (object)10f, (BindingMode)2, (ValidateValueDelegate)null, (BindingPropertyChangedDelegate)delegate(BindableObject b, object o, object n)
{
((SkiaSlider)(object)b).InvalidateMeasure();
}, (BindingPropertyChangingDelegate)null, (CoerceValueDelegate)null, (CreateDefaultValueDelegate)null);
/// <summary>
/// Bindable property for ThumbRadius.
/// </summary>
public static readonly BindableProperty ThumbRadiusProperty =
BindableProperty.Create(
nameof(ThumbRadius),
typeof(float),
typeof(SkiaSlider),
10f,
propertyChanged: (b, o, n) => ((SkiaSlider)b).InvalidateMeasure());
private bool _isDragging;
#endregion
public double Minimum
{
get
{
return (double)((BindableObject)this).GetValue(MinimumProperty);
}
set
{
((BindableObject)this).SetValue(MinimumProperty, (object)value);
}
}
#region Properties
public double Maximum
{
get
{
return (double)((BindableObject)this).GetValue(MaximumProperty);
}
set
{
((BindableObject)this).SetValue(MaximumProperty, (object)value);
}
}
/// <summary>
/// Gets or sets the minimum value.
/// </summary>
public double Minimum
{
get => (double)GetValue(MinimumProperty);
set => SetValue(MinimumProperty, value);
}
public double Value
{
get
{
return (double)((BindableObject)this).GetValue(ValueProperty);
}
set
{
((BindableObject)this).SetValue(ValueProperty, (object)Math.Clamp(value, Minimum, Maximum));
}
}
/// <summary>
/// Gets or sets the maximum value.
/// </summary>
public double Maximum
{
get => (double)GetValue(MaximumProperty);
set => SetValue(MaximumProperty, value);
}
public SKColor TrackColor
{
get
{
//IL_000b: Unknown result type (might be due to invalid IL or missing references)
return (SKColor)((BindableObject)this).GetValue(TrackColorProperty);
}
set
{
//IL_0006: Unknown result type (might be due to invalid IL or missing references)
((BindableObject)this).SetValue(TrackColorProperty, (object)value);
}
}
/// <summary>
/// Gets or sets the current value.
/// </summary>
public double Value
{
get => (double)GetValue(ValueProperty);
set => SetValue(ValueProperty, Math.Clamp(value, Minimum, Maximum));
}
public SKColor ActiveTrackColor
{
get
{
//IL_000b: Unknown result type (might be due to invalid IL or missing references)
return (SKColor)((BindableObject)this).GetValue(ActiveTrackColorProperty);
}
set
{
//IL_0006: Unknown result type (might be due to invalid IL or missing references)
((BindableObject)this).SetValue(ActiveTrackColorProperty, (object)value);
}
}
/// <summary>
/// Gets or sets the track color.
/// </summary>
public SKColor TrackColor
{
get => (SKColor)GetValue(TrackColorProperty);
set => SetValue(TrackColorProperty, value);
}
public SKColor ThumbColor
{
get
{
//IL_000b: Unknown result type (might be due to invalid IL or missing references)
return (SKColor)((BindableObject)this).GetValue(ThumbColorProperty);
}
set
{
//IL_0006: Unknown result type (might be due to invalid IL or missing references)
((BindableObject)this).SetValue(ThumbColorProperty, (object)value);
}
}
/// <summary>
/// Gets or sets the active track color.
/// </summary>
public SKColor ActiveTrackColor
{
get => (SKColor)GetValue(ActiveTrackColorProperty);
set => SetValue(ActiveTrackColorProperty, value);
}
public SKColor DisabledColor
{
get
{
//IL_000b: Unknown result type (might be due to invalid IL or missing references)
return (SKColor)((BindableObject)this).GetValue(DisabledColorProperty);
}
set
{
//IL_0006: Unknown result type (might be due to invalid IL or missing references)
((BindableObject)this).SetValue(DisabledColorProperty, (object)value);
}
}
/// <summary>
/// Gets or sets the thumb color.
/// </summary>
public SKColor ThumbColor
{
get => (SKColor)GetValue(ThumbColorProperty);
set => SetValue(ThumbColorProperty, value);
}
public float TrackHeight
{
get
{
return (float)((BindableObject)this).GetValue(TrackHeightProperty);
}
set
{
((BindableObject)this).SetValue(TrackHeightProperty, (object)value);
}
}
/// <summary>
/// Gets or sets the disabled color.
/// </summary>
public SKColor DisabledColor
{
get => (SKColor)GetValue(DisabledColorProperty);
set => SetValue(DisabledColorProperty, value);
}
public float ThumbRadius
{
get
{
return (float)((BindableObject)this).GetValue(ThumbRadiusProperty);
}
set
{
((BindableObject)this).SetValue(ThumbRadiusProperty, (object)value);
}
}
/// <summary>
/// Gets or sets the track height.
/// </summary>
public float TrackHeight
{
get => (float)GetValue(TrackHeightProperty);
set => SetValue(TrackHeightProperty, value);
}
public event EventHandler<SliderValueChangedEventArgs>? ValueChanged;
/// <summary>
/// Gets or sets the thumb radius.
/// </summary>
public float ThumbRadius
{
get => (float)GetValue(ThumbRadiusProperty);
set => SetValue(ThumbRadiusProperty, value);
}
public event EventHandler? DragStarted;
#endregion
public event EventHandler? DragCompleted;
private bool _isDragging;
public SkiaSlider()
{
base.IsFocusable = true;
}
/// <summary>
/// Event raised when the value changes.
/// </summary>
public event EventHandler<SliderValueChangedEventArgs>? ValueChanged;
private void OnRangeChanged()
{
double num = Math.Clamp(Value, Minimum, Maximum);
if (Value != num)
{
Value = num;
}
Invalidate();
}
/// <summary>
/// Event raised when drag starts.
/// </summary>
public event EventHandler? DragStarted;
private void OnValuePropertyChanged(double oldValue, double newValue)
{
this.ValueChanged?.Invoke(this, new SliderValueChangedEventArgs(newValue));
Invalidate();
}
/// <summary>
/// Event raised when drag completes.
/// </summary>
public event EventHandler? DragCompleted;
protected override void OnDraw(SKCanvas canvas, SKRect bounds)
{
//IL_006a: Unknown result type (might be due to invalid IL or missing references)
//IL_006f: Unknown result type (might be due to invalid IL or missing references)
//IL_0081: Unknown result type (might be due to invalid IL or missing references)
//IL_0079: Unknown result type (might be due to invalid IL or missing references)
//IL_008b: Unknown result type (might be due to invalid IL or missing references)
//IL_0092: Unknown result type (might be due to invalid IL or missing references)
//IL_009b: Expected O, but got Unknown
//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
//IL_00ca: Unknown result type (might be due to invalid IL or missing references)
//IL_00d1: Expected O, but got Unknown
//IL_00eb: Unknown result type (might be due to invalid IL or missing references)
//IL_00f0: Unknown result type (might be due to invalid IL or missing references)
//IL_01cd: Unknown result type (might be due to invalid IL or missing references)
//IL_01d2: Unknown result type (might be due to invalid IL or missing references)
//IL_0173: Unknown result type (might be due to invalid IL or missing references)
//IL_0178: Unknown result type (might be due to invalid IL or missing references)
//IL_017e: Unknown result type (might be due to invalid IL or missing references)
//IL_0188: Unknown result type (might be due to invalid IL or missing references)
//IL_018f: Unknown result type (might be due to invalid IL or missing references)
//IL_01a2: Expected O, but got Unknown
//IL_0102: Unknown result type (might be due to invalid IL or missing references)
//IL_00fa: Unknown result type (might be due to invalid IL or missing references)
//IL_01e4: Unknown result type (might be due to invalid IL or missing references)
//IL_01dc: Unknown result type (might be due to invalid IL or missing references)
//IL_010c: Unknown result type (might be due to invalid IL or missing references)
//IL_0113: Unknown result type (might be due to invalid IL or missing references)
//IL_011c: Expected O, but got Unknown
//IL_01ee: Unknown result type (might be due to invalid IL or missing references)
//IL_01f5: Unknown result type (might be due to invalid IL or missing references)
//IL_01fe: Expected O, but got Unknown
//IL_013b: Unknown result type (might be due to invalid IL or missing references)
//IL_014c: Unknown result type (might be due to invalid IL or missing references)
//IL_0153: Expected O, but got Unknown
//IL_0217: Unknown result type (might be due to invalid IL or missing references)
//IL_021c: Unknown result type (might be due to invalid IL or missing references)
//IL_021e: Unknown result type (might be due to invalid IL or missing references)
//IL_0223: Unknown result type (might be due to invalid IL or missing references)
//IL_0229: Unknown result type (might be due to invalid IL or missing references)
//IL_0233: Unknown result type (might be due to invalid IL or missing references)
//IL_023a: Unknown result type (might be due to invalid IL or missing references)
//IL_0243: Expected O, but got Unknown
float midY = ((SKRect)(ref bounds)).MidY;
float num = ((SKRect)(ref bounds)).Left + ThumbRadius;
float num2 = ((SKRect)(ref bounds)).Right - ThumbRadius;
float num3 = num2 - num;
double num4 = ((Maximum > Minimum) ? ((Value - Minimum) / (Maximum - Minimum)) : 0.0);
float num5 = num + (float)(num4 * (double)num3);
SKPaint val = new SKPaint
{
Color = (base.IsEnabled ? TrackColor : DisabledColor),
IsAntialias = true,
Style = (SKPaintStyle)0
};
try
{
SKRoundRect val2 = new SKRoundRect(new SKRect(num, midY - TrackHeight / 2f, num2, midY + TrackHeight / 2f), TrackHeight / 2f);
canvas.DrawRoundRect(val2, val);
if (num4 > 0.0)
{
SKPaint val3 = new SKPaint
{
Color = (base.IsEnabled ? ActiveTrackColor : DisabledColor),
IsAntialias = true,
Style = (SKPaintStyle)0
};
try
{
SKRoundRect val4 = new SKRoundRect(new SKRect(num, midY - TrackHeight / 2f, num5, midY + TrackHeight / 2f), TrackHeight / 2f);
canvas.DrawRoundRect(val4, val3);
}
finally
{
((IDisposable)val3)?.Dispose();
}
}
if (base.IsEnabled)
{
SKPaint val5 = new SKPaint
{
Color = new SKColor((byte)0, (byte)0, (byte)0, (byte)30),
IsAntialias = true,
MaskFilter = SKMaskFilter.CreateBlur((SKBlurStyle)0, 3f)
};
try
{
canvas.DrawCircle(num5 + 1f, midY + 2f, ThumbRadius, val5);
}
finally
{
((IDisposable)val5)?.Dispose();
}
}
SKPaint val6 = new SKPaint
{
Color = (base.IsEnabled ? ThumbColor : DisabledColor),
IsAntialias = true,
Style = (SKPaintStyle)0
};
try
{
canvas.DrawCircle(num5, midY, ThumbRadius, val6);
if (base.IsFocused)
{
SKPaint val7 = new SKPaint();
SKColor thumbColor = ThumbColor;
val7.Color = ((SKColor)(ref thumbColor)).WithAlpha((byte)60);
val7.IsAntialias = true;
val7.Style = (SKPaintStyle)0;
SKPaint val8 = val7;
try
{
canvas.DrawCircle(num5, midY, ThumbRadius + 8f, val8);
return;
}
finally
{
((IDisposable)val8)?.Dispose();
}
}
}
finally
{
((IDisposable)val6)?.Dispose();
}
}
finally
{
((IDisposable)val)?.Dispose();
}
}
public SkiaSlider()
{
IsFocusable = true;
}
public override void OnPointerPressed(PointerEventArgs e)
{
if (base.IsEnabled)
{
_isDragging = true;
UpdateValueFromPosition(e.X);
this.DragStarted?.Invoke(this, EventArgs.Empty);
SkiaVisualStateManager.GoToState(this, "Pressed");
}
}
private void OnRangeChanged()
{
// Clamp value to new range
var clamped = Math.Clamp(Value, Minimum, Maximum);
if (Value != clamped)
{
Value = clamped;
}
Invalidate();
}
public override void OnPointerMoved(PointerEventArgs e)
{
if (base.IsEnabled && _isDragging)
{
UpdateValueFromPosition(e.X);
}
}
private void OnValuePropertyChanged(double oldValue, double newValue)
{
ValueChanged?.Invoke(this, new SliderValueChangedEventArgs(newValue));
Invalidate();
}
public override void OnPointerReleased(PointerEventArgs e)
{
if (_isDragging)
{
_isDragging = false;
this.DragCompleted?.Invoke(this, EventArgs.Empty);
SkiaVisualStateManager.GoToState(this, base.IsEnabled ? "Normal" : "Disabled");
}
}
protected override void OnDraw(SKCanvas canvas, SKRect bounds)
{
var trackY = bounds.MidY;
var trackLeft = bounds.Left + ThumbRadius;
var trackRight = bounds.Right - ThumbRadius;
var trackWidth = trackRight - trackLeft;
private void UpdateValueFromPosition(float x)
{
//IL_0001: Unknown result type (might be due to invalid IL or missing references)
//IL_0006: Unknown result type (might be due to invalid IL or missing references)
//IL_0017: Unknown result type (might be due to invalid IL or missing references)
//IL_001c: Unknown result type (might be due to invalid IL or missing references)
SKRect bounds = base.Bounds;
float num = ((SKRect)(ref bounds)).Left + ThumbRadius;
bounds = base.Bounds;
float num2 = ((SKRect)(ref bounds)).Right - ThumbRadius - num;
float num3 = Math.Clamp((x - num) / num2, 0f, 1f);
Value = Minimum + (double)num3 * (Maximum - Minimum);
}
var percentage = Maximum > Minimum ? (Value - Minimum) / (Maximum - Minimum) : 0;
var thumbX = trackLeft + (float)(percentage * trackWidth);
public override void OnKeyDown(KeyEventArgs e)
{
if (base.IsEnabled)
{
double num = (Maximum - Minimum) / 100.0;
switch (e.Key)
{
case Key.Left:
case Key.Down:
Value -= num * 10.0;
e.Handled = true;
break;
case Key.Up:
case Key.Right:
Value += num * 10.0;
e.Handled = true;
break;
case Key.Home:
Value = Minimum;
e.Handled = true;
break;
case Key.End:
Value = Maximum;
e.Handled = true;
break;
}
}
}
// Draw inactive track
using var inactiveTrackPaint = new SKPaint
{
Color = IsEnabled ? TrackColor : DisabledColor,
IsAntialias = true,
Style = SKPaintStyle.Fill
};
protected override void OnEnabledChanged()
{
base.OnEnabledChanged();
SkiaVisualStateManager.GoToState(this, base.IsEnabled ? "Normal" : "Disabled");
}
var inactiveRect = new SKRoundRect(
new SKRect(trackLeft, trackY - TrackHeight / 2, trackRight, trackY + TrackHeight / 2),
TrackHeight / 2);
canvas.DrawRoundRect(inactiveRect, inactiveTrackPaint);
// Draw active track
if (percentage > 0)
{
using var activeTrackPaint = new SKPaint
{
Color = IsEnabled ? ActiveTrackColor : DisabledColor,
IsAntialias = true,
Style = SKPaintStyle.Fill
};
var activeRect = new SKRoundRect(
new SKRect(trackLeft, trackY - TrackHeight / 2, thumbX, trackY + TrackHeight / 2),
TrackHeight / 2);
canvas.DrawRoundRect(activeRect, activeTrackPaint);
}
// Draw thumb shadow
if (IsEnabled)
{
using var shadowPaint = new SKPaint
{
Color = new SKColor(0, 0, 0, 30),
IsAntialias = true,
MaskFilter = SKMaskFilter.CreateBlur(SKBlurStyle.Normal, 3)
};
canvas.DrawCircle(thumbX + 1, trackY + 2, ThumbRadius, shadowPaint);
}
// Draw thumb
using var thumbPaint = new SKPaint
{
Color = IsEnabled ? ThumbColor : DisabledColor,
IsAntialias = true,
Style = SKPaintStyle.Fill
};
canvas.DrawCircle(thumbX, trackY, ThumbRadius, thumbPaint);
// Draw focus ring
if (IsFocused)
{
using var focusPaint = new SKPaint
{
Color = ThumbColor.WithAlpha(60),
IsAntialias = true,
Style = SKPaintStyle.Fill
};
canvas.DrawCircle(thumbX, trackY, ThumbRadius + 8, focusPaint);
}
}
public override void OnPointerPressed(PointerEventArgs e)
{
if (!IsEnabled) return;
_isDragging = true;
UpdateValueFromPosition(e.X);
DragStarted?.Invoke(this, EventArgs.Empty);
SkiaVisualStateManager.GoToState(this, SkiaVisualStateManager.CommonStates.Pressed);
}
public override void OnPointerMoved(PointerEventArgs e)
{
if (!IsEnabled || !_isDragging) return;
UpdateValueFromPosition(e.X);
}
public override void OnPointerReleased(PointerEventArgs e)
{
if (_isDragging)
{
_isDragging = false;
DragCompleted?.Invoke(this, EventArgs.Empty);
SkiaVisualStateManager.GoToState(this, IsEnabled ? SkiaVisualStateManager.CommonStates.Normal : SkiaVisualStateManager.CommonStates.Disabled);
}
}
private void UpdateValueFromPosition(float x)
{
var trackLeft = Bounds.Left + ThumbRadius;
var trackRight = Bounds.Right - ThumbRadius;
var trackWidth = trackRight - trackLeft;
var percentage = Math.Clamp((x - trackLeft) / trackWidth, 0, 1);
Value = Minimum + percentage * (Maximum - Minimum);
}
public override void OnKeyDown(KeyEventArgs e)
{
if (!IsEnabled) return;
var step = (Maximum - Minimum) / 100; // 1% steps
switch (e.Key)
{
case Key.Left:
case Key.Down:
Value -= step * 10;
e.Handled = true;
break;
case Key.Right:
case Key.Up:
Value += step * 10;
e.Handled = true;
break;
case Key.Home:
Value = Minimum;
e.Handled = true;
break;
case Key.End:
Value = Maximum;
e.Handled = true;
break;
}
}
protected override void OnEnabledChanged()
{
base.OnEnabledChanged();
SkiaVisualStateManager.GoToState(this, IsEnabled ? SkiaVisualStateManager.CommonStates.Normal : SkiaVisualStateManager.CommonStates.Disabled);
}
protected override SKSize MeasureOverride(SKSize availableSize)
{
return new SKSize(200, ThumbRadius * 2 + 16);
}
}
/// <summary>
/// Event args for slider value changed events.
/// </summary>
public class SliderValueChangedEventArgs : EventArgs
{
public double NewValue { get; }
public SliderValueChangedEventArgs(double newValue) => NewValue = newValue;
protected override SKSize MeasureOverride(SKSize availableSize)
{
//IL_0017: Unknown result type (might be due to invalid IL or missing references)
return new SKSize(200f, ThumbRadius * 2f + 16f);
}
}

213
Views/SkiaStackLayout.cs Normal file
View File

@@ -0,0 +1,213 @@
using System;
using System.Linq;
using Microsoft.Maui.Controls;
using SkiaSharp;
namespace Microsoft.Maui.Platform;
public class SkiaStackLayout : SkiaLayoutView
{
public static readonly BindableProperty OrientationProperty = BindableProperty.Create("Orientation", typeof(StackOrientation), typeof(SkiaStackLayout), (object)StackOrientation.Vertical, (BindingMode)2, (ValidateValueDelegate)null, (BindingPropertyChangedDelegate)delegate(BindableObject b, object o, object n)
{
((SkiaStackLayout)(object)b).InvalidateMeasure();
}, (BindingPropertyChangingDelegate)null, (CoerceValueDelegate)null, (CreateDefaultValueDelegate)null);
public StackOrientation Orientation
{
get
{
return (StackOrientation)((BindableObject)this).GetValue(OrientationProperty);
}
set
{
((BindableObject)this).SetValue(OrientationProperty, (object)value);
}
}
protected override SKSize MeasureOverride(SKSize availableSize)
{
//IL_0001: Unknown result type (might be due to invalid IL or missing references)
//IL_0006: Unknown result type (might be due to invalid IL or missing references)
//IL_0017: Unknown result type (might be due to invalid IL or missing references)
//IL_001c: Unknown result type (might be due to invalid IL or missing references)
//IL_002e: Unknown result type (might be due to invalid IL or missing references)
//IL_0033: Unknown result type (might be due to invalid IL or missing references)
//IL_0044: Unknown result type (might be due to invalid IL or missing references)
//IL_0049: Unknown result type (might be due to invalid IL or missing references)
//IL_005b: Unknown result type (might be due to invalid IL or missing references)
//IL_0060: Unknown result type (might be due to invalid IL or missing references)
//IL_0071: Unknown result type (might be due to invalid IL or missing references)
//IL_0076: Unknown result type (might be due to invalid IL or missing references)
//IL_0088: Unknown result type (might be due to invalid IL or missing references)
//IL_008d: Unknown result type (might be due to invalid IL or missing references)
//IL_009e: Unknown result type (might be due to invalid IL or missing references)
//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
//IL_014d: Unknown result type (might be due to invalid IL or missing references)
//IL_014f: Unknown result type (might be due to invalid IL or missing references)
//IL_0154: Unknown result type (might be due to invalid IL or missing references)
//IL_024e: Unknown result type (might be due to invalid IL or missing references)
//IL_0235: Unknown result type (might be due to invalid IL or missing references)
SKRect padding = base.Padding;
float num;
if (!float.IsNaN(((SKRect)(ref padding)).Left))
{
padding = base.Padding;
num = ((SKRect)(ref padding)).Left;
}
else
{
num = 0f;
}
float num2 = num;
padding = base.Padding;
float num3;
if (!float.IsNaN(((SKRect)(ref padding)).Right))
{
padding = base.Padding;
num3 = ((SKRect)(ref padding)).Right;
}
else
{
num3 = 0f;
}
float num4 = num3;
padding = base.Padding;
float num5;
if (!float.IsNaN(((SKRect)(ref padding)).Top))
{
padding = base.Padding;
num5 = ((SKRect)(ref padding)).Top;
}
else
{
num5 = 0f;
}
float num6 = num5;
padding = base.Padding;
float num7;
if (!float.IsNaN(((SKRect)(ref padding)).Bottom))
{
padding = base.Padding;
num7 = ((SKRect)(ref padding)).Bottom;
}
else
{
num7 = 0f;
}
float num8 = num7;
float num9 = ((SKSize)(ref availableSize)).Width - num2 - num4;
float num10 = ((SKSize)(ref availableSize)).Height - num6 - num8;
if (num9 < 0f || float.IsNaN(num9))
{
num9 = 0f;
}
if (num10 < 0f || float.IsNaN(num10))
{
num10 = 0f;
}
float num11 = 0f;
float num12 = 0f;
float num13 = 0f;
float num14 = 0f;
SKSize availableSize2 = default(SKSize);
((SKSize)(ref availableSize2))._002Ector(num9, num10);
foreach (SkiaView child in base.Children)
{
if (child.IsVisible)
{
SKSize val = child.Measure(availableSize2);
float num15 = (float.IsNaN(((SKSize)(ref val)).Width) ? 0f : ((SKSize)(ref val)).Width);
float num16 = (float.IsNaN(((SKSize)(ref val)).Height) ? 0f : ((SKSize)(ref val)).Height);
if (Orientation == StackOrientation.Vertical)
{
num12 += num16;
num13 = Math.Max(num13, num15);
}
else
{
num11 += num15;
num14 = Math.Max(num14, num16);
}
}
}
int num17 = base.Children.Count((SkiaView c) => c.IsVisible);
float num18 = (float)Math.Max(0, num17 - 1) * base.Spacing;
if (Orientation == StackOrientation.Vertical)
{
num12 += num18;
return new SKSize(num13 + num2 + num4, num12 + num6 + num8);
}
num11 += num18;
return new SKSize(num11 + num2 + num4, num14 + num6 + num8);
}
protected override SKRect ArrangeOverride(SKRect bounds)
{
//IL_0001: Unknown result type (might be due to invalid IL or missing references)
//IL_0002: Unknown result type (might be due to invalid IL or missing references)
//IL_0007: Unknown result type (might be due to invalid IL or missing references)
//IL_008d: Unknown result type (might be due to invalid IL or missing references)
//IL_0092: Unknown result type (might be due to invalid IL or missing references)
//IL_02bc: Unknown result type (might be due to invalid IL or missing references)
//IL_01b2: Unknown result type (might be due to invalid IL or missing references)
//IL_01b7: Unknown result type (might be due to invalid IL or missing references)
//IL_01bb: Unknown result type (might be due to invalid IL or missing references)
//IL_01c2: Expected I4, but got Unknown
//IL_024b: Unknown result type (might be due to invalid IL or missing references)
//IL_0250: Unknown result type (might be due to invalid IL or missing references)
//IL_029b: Unknown result type (might be due to invalid IL or missing references)
SKRect contentBounds = GetContentBounds(bounds);
float num = ((float.IsInfinity(((SKRect)(ref contentBounds)).Width) || float.IsNaN(((SKRect)(ref contentBounds)).Width)) ? 800f : ((SKRect)(ref contentBounds)).Width);
float num2 = ((float.IsInfinity(((SKRect)(ref contentBounds)).Height) || float.IsNaN(((SKRect)(ref contentBounds)).Height)) ? 600f : ((SKRect)(ref contentBounds)).Height);
float num3 = 0f;
SKRect val = default(SKRect);
SKRect bounds2 = default(SKRect);
foreach (SkiaView child in base.Children)
{
if (!child.IsVisible)
{
continue;
}
SKSize desiredSize = child.DesiredSize;
float num4 = ((float.IsNaN(((SKSize)(ref desiredSize)).Width) || float.IsInfinity(((SKSize)(ref desiredSize)).Width)) ? num : ((SKSize)(ref desiredSize)).Width);
float num5 = ((float.IsNaN(((SKSize)(ref desiredSize)).Height) || float.IsInfinity(((SKSize)(ref desiredSize)).Height)) ? num2 : ((SKSize)(ref desiredSize)).Height);
if (Orientation == StackOrientation.Vertical)
{
float num6 = Math.Max(0f, num2 - num3);
float num7 = ((child is SkiaScrollView) ? num6 : Math.Min(num5, (num6 > 0f) ? num6 : num5));
((SKRect)(ref val))._002Ector(((SKRect)(ref contentBounds)).Left, ((SKRect)(ref contentBounds)).Top + num3, ((SKRect)(ref contentBounds)).Left + num, ((SKRect)(ref contentBounds)).Top + num3 + num7);
num3 += num7 + base.Spacing;
}
else
{
float num8 = Math.Max(0f, num - num3);
float num9 = ((child is SkiaScrollView) ? num8 : Math.Min(num4, (num8 > 0f) ? num8 : num4));
float num10 = Math.Min(num5, num2);
float num11 = ((SKRect)(ref contentBounds)).Top;
float num12 = ((SKRect)(ref contentBounds)).Top + num10;
LayoutOptions verticalOptions = child.VerticalOptions;
switch ((int)((LayoutOptions)(ref verticalOptions)).Alignment)
{
case 1:
num11 = ((SKRect)(ref contentBounds)).Top + (num2 - num10) / 2f;
num12 = num11 + num10;
break;
case 2:
num11 = ((SKRect)(ref contentBounds)).Top + num2 - num10;
num12 = ((SKRect)(ref contentBounds)).Top + num2;
break;
case 3:
num11 = ((SKRect)(ref contentBounds)).Top;
num12 = ((SKRect)(ref contentBounds)).Top + num2;
break;
}
((SKRect)(ref val))._002Ector(((SKRect)(ref contentBounds)).Left + num3, num11, ((SKRect)(ref contentBounds)).Left + num3 + num9, num12);
num3 += num9 + base.Spacing;
}
Thickness margin = child.Margin;
((SKRect)(ref bounds2))._002Ector(((SKRect)(ref val)).Left + (float)((Thickness)(ref margin)).Left, ((SKRect)(ref val)).Top + (float)((Thickness)(ref margin)).Top, ((SKRect)(ref val)).Right - (float)((Thickness)(ref margin)).Right, ((SKRect)(ref val)).Bottom - (float)((Thickness)(ref margin)).Bottom);
child.Arrange(bounds2);
}
return bounds;
}
}

View File

@@ -1,261 +1,439 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System;
using Microsoft.Maui.Controls;
using SkiaSharp;
namespace Microsoft.Maui.Platform;
/// <summary>
/// Skia-rendered stepper control with increment/decrement buttons.
/// </summary>
public class SkiaStepper : SkiaView
{
#region BindableProperties
public static readonly BindableProperty ValueProperty = BindableProperty.Create("Value", typeof(double), typeof(SkiaStepper), (object)0.0, (BindingMode)1, (ValidateValueDelegate)null, (BindingPropertyChangedDelegate)delegate(BindableObject b, object o, object n)
{
((SkiaStepper)(object)b).OnValuePropertyChanged((double)o, (double)n);
}, (BindingPropertyChangingDelegate)null, (CoerceValueDelegate)null, (CreateDefaultValueDelegate)null);
public static readonly BindableProperty ValueProperty =
BindableProperty.Create(nameof(Value), typeof(double), typeof(SkiaStepper), 0.0, BindingMode.TwoWay,
propertyChanged: (b, o, n) => ((SkiaStepper)b).OnValuePropertyChanged((double)o, (double)n));
public static readonly BindableProperty MinimumProperty = BindableProperty.Create("Minimum", typeof(double), typeof(SkiaStepper), (object)0.0, (BindingMode)2, (ValidateValueDelegate)null, (BindingPropertyChangedDelegate)delegate(BindableObject b, object o, object n)
{
((SkiaStepper)(object)b).OnRangeChanged();
}, (BindingPropertyChangingDelegate)null, (CoerceValueDelegate)null, (CreateDefaultValueDelegate)null);
public static readonly BindableProperty MinimumProperty =
BindableProperty.Create(nameof(Minimum), typeof(double), typeof(SkiaStepper), 0.0,
propertyChanged: (b, o, n) => ((SkiaStepper)b).OnRangeChanged());
public static readonly BindableProperty MaximumProperty = BindableProperty.Create("Maximum", typeof(double), typeof(SkiaStepper), (object)100.0, (BindingMode)2, (ValidateValueDelegate)null, (BindingPropertyChangedDelegate)delegate(BindableObject b, object o, object n)
{
((SkiaStepper)(object)b).OnRangeChanged();
}, (BindingPropertyChangingDelegate)null, (CoerceValueDelegate)null, (CreateDefaultValueDelegate)null);
public static readonly BindableProperty MaximumProperty =
BindableProperty.Create(nameof(Maximum), typeof(double), typeof(SkiaStepper), 100.0,
propertyChanged: (b, o, n) => ((SkiaStepper)b).OnRangeChanged());
public static readonly BindableProperty IncrementProperty = BindableProperty.Create("Increment", typeof(double), typeof(SkiaStepper), (object)1.0, (BindingMode)2, (ValidateValueDelegate)null, (BindingPropertyChangedDelegate)null, (BindingPropertyChangingDelegate)null, (CoerceValueDelegate)null, (CreateDefaultValueDelegate)null);
public static readonly BindableProperty IncrementProperty =
BindableProperty.Create(nameof(Increment), typeof(double), typeof(SkiaStepper), 1.0);
public static readonly BindableProperty ButtonBackgroundColorProperty = BindableProperty.Create("ButtonBackgroundColor", typeof(SKColor), typeof(SkiaStepper), (object)new SKColor((byte)224, (byte)224, (byte)224), (BindingMode)2, (ValidateValueDelegate)null, (BindingPropertyChangedDelegate)delegate(BindableObject b, object o, object n)
{
((SkiaStepper)(object)b).Invalidate();
}, (BindingPropertyChangingDelegate)null, (CoerceValueDelegate)null, (CreateDefaultValueDelegate)null);
public static readonly BindableProperty ButtonBackgroundColorProperty =
BindableProperty.Create(nameof(ButtonBackgroundColor), typeof(SKColor), typeof(SkiaStepper), new SKColor(0xE0, 0xE0, 0xE0),
propertyChanged: (b, o, n) => ((SkiaStepper)b).Invalidate());
public static readonly BindableProperty ButtonPressedColorProperty = BindableProperty.Create("ButtonPressedColor", typeof(SKColor), typeof(SkiaStepper), (object)new SKColor((byte)189, (byte)189, (byte)189), (BindingMode)2, (ValidateValueDelegate)null, (BindingPropertyChangedDelegate)delegate(BindableObject b, object o, object n)
{
((SkiaStepper)(object)b).Invalidate();
}, (BindingPropertyChangingDelegate)null, (CoerceValueDelegate)null, (CreateDefaultValueDelegate)null);
public static readonly BindableProperty ButtonPressedColorProperty =
BindableProperty.Create(nameof(ButtonPressedColor), typeof(SKColor), typeof(SkiaStepper), new SKColor(0xBD, 0xBD, 0xBD),
propertyChanged: (b, o, n) => ((SkiaStepper)b).Invalidate());
public static readonly BindableProperty ButtonDisabledColorProperty = BindableProperty.Create("ButtonDisabledColor", typeof(SKColor), typeof(SkiaStepper), (object)new SKColor((byte)245, (byte)245, (byte)245), (BindingMode)2, (ValidateValueDelegate)null, (BindingPropertyChangedDelegate)delegate(BindableObject b, object o, object n)
{
((SkiaStepper)(object)b).Invalidate();
}, (BindingPropertyChangingDelegate)null, (CoerceValueDelegate)null, (CreateDefaultValueDelegate)null);
public static readonly BindableProperty ButtonDisabledColorProperty =
BindableProperty.Create(nameof(ButtonDisabledColor), typeof(SKColor), typeof(SkiaStepper), new SKColor(0xF5, 0xF5, 0xF5),
propertyChanged: (b, o, n) => ((SkiaStepper)b).Invalidate());
public static readonly BindableProperty BorderColorProperty = BindableProperty.Create("BorderColor", typeof(SKColor), typeof(SkiaStepper), (object)new SKColor((byte)189, (byte)189, (byte)189), (BindingMode)2, (ValidateValueDelegate)null, (BindingPropertyChangedDelegate)delegate(BindableObject b, object o, object n)
{
((SkiaStepper)(object)b).Invalidate();
}, (BindingPropertyChangingDelegate)null, (CoerceValueDelegate)null, (CreateDefaultValueDelegate)null);
public static readonly BindableProperty BorderColorProperty =
BindableProperty.Create(nameof(BorderColor), typeof(SKColor), typeof(SkiaStepper), new SKColor(0xBD, 0xBD, 0xBD),
propertyChanged: (b, o, n) => ((SkiaStepper)b).Invalidate());
public static readonly BindableProperty SymbolColorProperty = BindableProperty.Create("SymbolColor", typeof(SKColor), typeof(SkiaStepper), (object)SKColors.Black, (BindingMode)2, (ValidateValueDelegate)null, (BindingPropertyChangedDelegate)delegate(BindableObject b, object o, object n)
{
((SkiaStepper)(object)b).Invalidate();
}, (BindingPropertyChangingDelegate)null, (CoerceValueDelegate)null, (CreateDefaultValueDelegate)null);
public static readonly BindableProperty SymbolColorProperty =
BindableProperty.Create(nameof(SymbolColor), typeof(SKColor), typeof(SkiaStepper), SKColors.Black,
propertyChanged: (b, o, n) => ((SkiaStepper)b).Invalidate());
public static readonly BindableProperty SymbolDisabledColorProperty = BindableProperty.Create("SymbolDisabledColor", typeof(SKColor), typeof(SkiaStepper), (object)new SKColor((byte)189, (byte)189, (byte)189), (BindingMode)2, (ValidateValueDelegate)null, (BindingPropertyChangedDelegate)delegate(BindableObject b, object o, object n)
{
((SkiaStepper)(object)b).Invalidate();
}, (BindingPropertyChangingDelegate)null, (CoerceValueDelegate)null, (CreateDefaultValueDelegate)null);
public static readonly BindableProperty SymbolDisabledColorProperty =
BindableProperty.Create(nameof(SymbolDisabledColor), typeof(SKColor), typeof(SkiaStepper), new SKColor(0xBD, 0xBD, 0xBD),
propertyChanged: (b, o, n) => ((SkiaStepper)b).Invalidate());
public static readonly BindableProperty CornerRadiusProperty = BindableProperty.Create("CornerRadius", typeof(float), typeof(SkiaStepper), (object)4f, (BindingMode)2, (ValidateValueDelegate)null, (BindingPropertyChangedDelegate)delegate(BindableObject b, object o, object n)
{
((SkiaStepper)(object)b).Invalidate();
}, (BindingPropertyChangingDelegate)null, (CoerceValueDelegate)null, (CreateDefaultValueDelegate)null);
public static readonly BindableProperty CornerRadiusProperty =
BindableProperty.Create(nameof(CornerRadius), typeof(float), typeof(SkiaStepper), 4f,
propertyChanged: (b, o, n) => ((SkiaStepper)b).Invalidate());
public static readonly BindableProperty ButtonWidthProperty = BindableProperty.Create("ButtonWidth", typeof(float), typeof(SkiaStepper), (object)40f, (BindingMode)2, (ValidateValueDelegate)null, (BindingPropertyChangedDelegate)delegate(BindableObject b, object o, object n)
{
((SkiaStepper)(object)b).InvalidateMeasure();
}, (BindingPropertyChangingDelegate)null, (CoerceValueDelegate)null, (CreateDefaultValueDelegate)null);
public static readonly BindableProperty ButtonWidthProperty =
BindableProperty.Create(nameof(ButtonWidth), typeof(float), typeof(SkiaStepper), 40f,
propertyChanged: (b, o, n) => ((SkiaStepper)b).InvalidateMeasure());
private bool _isMinusPressed;
#endregion
private bool _isPlusPressed;
#region Properties
public double Value
{
get
{
return (double)((BindableObject)this).GetValue(ValueProperty);
}
set
{
((BindableObject)this).SetValue(ValueProperty, (object)Math.Clamp(value, Minimum, Maximum));
}
}
public double Value
{
get => (double)GetValue(ValueProperty);
set => SetValue(ValueProperty, Math.Clamp(value, Minimum, Maximum));
}
public double Minimum
{
get
{
return (double)((BindableObject)this).GetValue(MinimumProperty);
}
set
{
((BindableObject)this).SetValue(MinimumProperty, (object)value);
}
}
public double Minimum
{
get => (double)GetValue(MinimumProperty);
set => SetValue(MinimumProperty, value);
}
public double Maximum
{
get
{
return (double)((BindableObject)this).GetValue(MaximumProperty);
}
set
{
((BindableObject)this).SetValue(MaximumProperty, (object)value);
}
}
public double Maximum
{
get => (double)GetValue(MaximumProperty);
set => SetValue(MaximumProperty, value);
}
public double Increment
{
get
{
return (double)((BindableObject)this).GetValue(IncrementProperty);
}
set
{
((BindableObject)this).SetValue(IncrementProperty, (object)Math.Max(0.001, value));
}
}
public double Increment
{
get => (double)GetValue(IncrementProperty);
set => SetValue(IncrementProperty, Math.Max(0.001, value));
}
public SKColor ButtonBackgroundColor
{
get
{
//IL_000b: Unknown result type (might be due to invalid IL or missing references)
return (SKColor)((BindableObject)this).GetValue(ButtonBackgroundColorProperty);
}
set
{
//IL_0006: Unknown result type (might be due to invalid IL or missing references)
((BindableObject)this).SetValue(ButtonBackgroundColorProperty, (object)value);
}
}
public SKColor ButtonBackgroundColor
{
get => (SKColor)GetValue(ButtonBackgroundColorProperty);
set => SetValue(ButtonBackgroundColorProperty, value);
}
public SKColor ButtonPressedColor
{
get
{
//IL_000b: Unknown result type (might be due to invalid IL or missing references)
return (SKColor)((BindableObject)this).GetValue(ButtonPressedColorProperty);
}
set
{
//IL_0006: Unknown result type (might be due to invalid IL or missing references)
((BindableObject)this).SetValue(ButtonPressedColorProperty, (object)value);
}
}
public SKColor ButtonPressedColor
{
get => (SKColor)GetValue(ButtonPressedColorProperty);
set => SetValue(ButtonPressedColorProperty, value);
}
public SKColor ButtonDisabledColor
{
get
{
//IL_000b: Unknown result type (might be due to invalid IL or missing references)
return (SKColor)((BindableObject)this).GetValue(ButtonDisabledColorProperty);
}
set
{
//IL_0006: Unknown result type (might be due to invalid IL or missing references)
((BindableObject)this).SetValue(ButtonDisabledColorProperty, (object)value);
}
}
public SKColor ButtonDisabledColor
{
get => (SKColor)GetValue(ButtonDisabledColorProperty);
set => SetValue(ButtonDisabledColorProperty, value);
}
public SKColor BorderColor
{
get
{
//IL_000b: Unknown result type (might be due to invalid IL or missing references)
return (SKColor)((BindableObject)this).GetValue(BorderColorProperty);
}
set
{
//IL_0006: Unknown result type (might be due to invalid IL or missing references)
((BindableObject)this).SetValue(BorderColorProperty, (object)value);
}
}
public SKColor BorderColor
{
get => (SKColor)GetValue(BorderColorProperty);
set => SetValue(BorderColorProperty, value);
}
public SKColor SymbolColor
{
get
{
//IL_000b: Unknown result type (might be due to invalid IL or missing references)
return (SKColor)((BindableObject)this).GetValue(SymbolColorProperty);
}
set
{
//IL_0006: Unknown result type (might be due to invalid IL or missing references)
((BindableObject)this).SetValue(SymbolColorProperty, (object)value);
}
}
public SKColor SymbolColor
{
get => (SKColor)GetValue(SymbolColorProperty);
set => SetValue(SymbolColorProperty, value);
}
public SKColor SymbolDisabledColor
{
get
{
//IL_000b: Unknown result type (might be due to invalid IL or missing references)
return (SKColor)((BindableObject)this).GetValue(SymbolDisabledColorProperty);
}
set
{
//IL_0006: Unknown result type (might be due to invalid IL or missing references)
((BindableObject)this).SetValue(SymbolDisabledColorProperty, (object)value);
}
}
public SKColor SymbolDisabledColor
{
get => (SKColor)GetValue(SymbolDisabledColorProperty);
set => SetValue(SymbolDisabledColorProperty, value);
}
public float CornerRadius
{
get
{
return (float)((BindableObject)this).GetValue(CornerRadiusProperty);
}
set
{
((BindableObject)this).SetValue(CornerRadiusProperty, (object)value);
}
}
public float CornerRadius
{
get => (float)GetValue(CornerRadiusProperty);
set => SetValue(CornerRadiusProperty, value);
}
public float ButtonWidth
{
get
{
return (float)((BindableObject)this).GetValue(ButtonWidthProperty);
}
set
{
((BindableObject)this).SetValue(ButtonWidthProperty, (object)value);
}
}
public float ButtonWidth
{
get => (float)GetValue(ButtonWidthProperty);
set => SetValue(ButtonWidthProperty, value);
}
public event EventHandler? ValueChanged;
#endregion
public SkiaStepper()
{
base.IsFocusable = true;
}
private bool _isMinusPressed;
private bool _isPlusPressed;
private void OnValuePropertyChanged(double oldValue, double newValue)
{
this.ValueChanged?.Invoke(this, EventArgs.Empty);
Invalidate();
}
public event EventHandler? ValueChanged;
private void OnRangeChanged()
{
double num = Math.Clamp(Value, Minimum, Maximum);
if (Value != num)
{
Value = num;
}
Invalidate();
}
public SkiaStepper()
{
IsFocusable = true;
}
protected override void OnDraw(SKCanvas canvas, SKRect bounds)
{
//IL_0056: Unknown result type (might be due to invalid IL or missing references)
//IL_0072: Unknown result type (might be due to invalid IL or missing references)
//IL_008c: Unknown result type (might be due to invalid IL or missing references)
//IL_0091: Unknown result type (might be due to invalid IL or missing references)
//IL_0093: Unknown result type (might be due to invalid IL or missing references)
//IL_009d: Unknown result type (might be due to invalid IL or missing references)
//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
//IL_00af: Unknown result type (might be due to invalid IL or missing references)
//IL_00b7: Expected O, but got Unknown
//IL_00d3: Unknown result type (might be due to invalid IL or missing references)
//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
//IL_00da: Unknown result type (might be due to invalid IL or missing references)
//IL_00e1: Unknown result type (might be due to invalid IL or missing references)
//IL_00ec: Expected O, but got Unknown
SKRect rect = default(SKRect);
((SKRect)(ref rect))._002Ector(((SKRect)(ref bounds)).Left, ((SKRect)(ref bounds)).Top, ((SKRect)(ref bounds)).Left + ButtonWidth, ((SKRect)(ref bounds)).Bottom);
SKRect rect2 = default(SKRect);
((SKRect)(ref rect2))._002Ector(((SKRect)(ref bounds)).Right - ButtonWidth, ((SKRect)(ref bounds)).Top, ((SKRect)(ref bounds)).Right, ((SKRect)(ref bounds)).Bottom);
DrawButton(canvas, rect, "-", _isMinusPressed, !CanDecrement());
DrawButton(canvas, rect2, "+", _isPlusPressed, !CanIncrement());
SKPaint val = new SKPaint
{
Color = BorderColor,
Style = (SKPaintStyle)1,
StrokeWidth = 1f,
IsAntialias = true
};
try
{
SKRect val2 = new SKRect(((SKRect)(ref bounds)).Left, ((SKRect)(ref bounds)).Top, ((SKRect)(ref bounds)).Right, ((SKRect)(ref bounds)).Bottom);
canvas.DrawRoundRect(new SKRoundRect(val2, CornerRadius), val);
float midX = ((SKRect)(ref bounds)).MidX;
canvas.DrawLine(midX, ((SKRect)(ref bounds)).Top, midX, ((SKRect)(ref bounds)).Bottom, val);
}
finally
{
((IDisposable)val)?.Dispose();
}
}
private void OnValuePropertyChanged(double oldValue, double newValue)
{
ValueChanged?.Invoke(this, EventArgs.Empty);
Invalidate();
}
private void DrawButton(SKCanvas canvas, SKRect rect, string symbol, bool isPressed, bool isDisabled)
{
//IL_0000: Unknown result type (might be due to invalid IL or missing references)
//IL_0005: Unknown result type (might be due to invalid IL or missing references)
//IL_001f: Unknown result type (might be due to invalid IL or missing references)
//IL_0029: Unknown result type (might be due to invalid IL or missing references)
//IL_0030: Unknown result type (might be due to invalid IL or missing references)
//IL_0038: Expected O, but got Unknown
//IL_0017: Unknown result type (might be due to invalid IL or missing references)
//IL_000f: Unknown result type (might be due to invalid IL or missing references)
//IL_0039: Unknown result type (might be due to invalid IL or missing references)
//IL_0054: Unknown result type (might be due to invalid IL or missing references)
//IL_005a: Expected O, but got Unknown
//IL_005b: Unknown result type (might be due to invalid IL or missing references)
//IL_0060: Unknown result type (might be due to invalid IL or missing references)
//IL_006e: Unknown result type (might be due to invalid IL or missing references)
//IL_0066: Unknown result type (might be due to invalid IL or missing references)
//IL_0078: Unknown result type (might be due to invalid IL or missing references)
//IL_0080: Expected O, but got Unknown
//IL_0082: Unknown result type (might be due to invalid IL or missing references)
SKPaint val = new SKPaint
{
Color = (isDisabled ? ButtonDisabledColor : (isPressed ? ButtonPressedColor : ButtonBackgroundColor)),
Style = (SKPaintStyle)0,
IsAntialias = true
};
try
{
canvas.DrawRect(rect, val);
SKFont val2 = new SKFont(SKTypeface.Default, 20f, 1f, 0f);
try
{
SKPaint val3 = new SKPaint(val2)
{
Color = (isDisabled ? SymbolDisabledColor : SymbolColor),
IsAntialias = true
};
try
{
SKRect val4 = default(SKRect);
val3.MeasureText(symbol, ref val4);
canvas.DrawText(symbol, ((SKRect)(ref rect)).MidX - ((SKRect)(ref val4)).MidX, ((SKRect)(ref rect)).MidY - ((SKRect)(ref val4)).MidY, val3);
}
finally
{
((IDisposable)val3)?.Dispose();
}
}
finally
{
((IDisposable)val2)?.Dispose();
}
}
finally
{
((IDisposable)val)?.Dispose();
}
}
private void OnRangeChanged()
{
var clamped = Math.Clamp(Value, Minimum, Maximum);
if (Value != clamped)
{
Value = clamped;
}
Invalidate();
}
private bool CanIncrement()
{
if (base.IsEnabled)
{
return Value < Maximum;
}
return false;
}
protected override void OnDraw(SKCanvas canvas, SKRect bounds)
{
var minusRect = new SKRect(bounds.Left, bounds.Top, bounds.Left + ButtonWidth, bounds.Bottom);
var plusRect = new SKRect(bounds.Right - ButtonWidth, bounds.Top, bounds.Right, bounds.Bottom);
private bool CanDecrement()
{
if (base.IsEnabled)
{
return Value > Minimum;
}
return false;
}
DrawButton(canvas, minusRect, "-", _isMinusPressed, !CanDecrement());
DrawButton(canvas, plusRect, "+", _isPlusPressed, !CanIncrement());
public override void OnPointerPressed(PointerEventArgs e)
{
//IL_0042: Unknown result type (might be due to invalid IL or missing references)
//IL_0047: Unknown result type (might be due to invalid IL or missing references)
if (!base.IsEnabled)
{
return;
}
if (e.X < ButtonWidth)
{
_isMinusPressed = true;
if (CanDecrement())
{
Value -= Increment;
}
}
else
{
float x = e.X;
SKRect bounds = base.Bounds;
if (x > ((SKRect)(ref bounds)).Width - ButtonWidth)
{
_isPlusPressed = true;
if (CanIncrement())
{
Value += Increment;
}
}
}
Invalidate();
}
using var borderPaint = new SKPaint
{
Color = BorderColor,
Style = SKPaintStyle.Stroke,
StrokeWidth = 1,
IsAntialias = true
};
public override void OnPointerReleased(PointerEventArgs e)
{
_isMinusPressed = false;
_isPlusPressed = false;
Invalidate();
}
var totalRect = new SKRect(bounds.Left, bounds.Top, bounds.Right, bounds.Bottom);
canvas.DrawRoundRect(new SKRoundRect(totalRect, CornerRadius), borderPaint);
public override void OnKeyDown(KeyEventArgs e)
{
if (!base.IsEnabled)
{
return;
}
switch (e.Key)
{
case Key.Up:
case Key.Right:
if (CanIncrement())
{
Value += Increment;
}
e.Handled = true;
break;
case Key.Left:
case Key.Down:
if (CanDecrement())
{
Value -= Increment;
}
e.Handled = true;
break;
}
}
var centerX = bounds.MidX;
canvas.DrawLine(centerX, bounds.Top, centerX, bounds.Bottom, borderPaint);
}
private void DrawButton(SKCanvas canvas, SKRect rect, string symbol, bool isPressed, bool isDisabled)
{
using var bgPaint = new SKPaint
{
Color = isDisabled ? ButtonDisabledColor : (isPressed ? ButtonPressedColor : ButtonBackgroundColor),
Style = SKPaintStyle.Fill,
IsAntialias = true
};
canvas.DrawRect(rect, bgPaint);
using var font = new SKFont(SKTypeface.Default, 20);
using var textPaint = new SKPaint(font)
{
Color = isDisabled ? SymbolDisabledColor : SymbolColor,
IsAntialias = true
};
var textBounds = new SKRect();
textPaint.MeasureText(symbol, ref textBounds);
canvas.DrawText(symbol, rect.MidX - textBounds.MidX, rect.MidY - textBounds.MidY, textPaint);
}
private bool CanIncrement() => IsEnabled && Value < Maximum;
private bool CanDecrement() => IsEnabled && Value > Minimum;
public override void OnPointerPressed(PointerEventArgs e)
{
if (!IsEnabled) return;
if (e.X < ButtonWidth)
{
_isMinusPressed = true;
if (CanDecrement()) Value -= Increment;
}
else if (e.X > Bounds.Width - ButtonWidth)
{
_isPlusPressed = true;
if (CanIncrement()) Value += Increment;
}
Invalidate();
}
public override void OnPointerReleased(PointerEventArgs e)
{
_isMinusPressed = false;
_isPlusPressed = false;
Invalidate();
}
public override void OnKeyDown(KeyEventArgs e)
{
if (!IsEnabled) return;
switch (e.Key)
{
case Key.Up:
case Key.Right:
if (CanIncrement()) Value += Increment;
e.Handled = true;
break;
case Key.Down:
case Key.Left:
if (CanDecrement()) Value -= Increment;
e.Handled = true;
break;
}
}
protected override SKSize MeasureOverride(SKSize availableSize)
{
return new SKSize(ButtonWidth * 2 + 1, 32);
}
protected override SKSize MeasureOverride(SKSize availableSize)
{
//IL_0017: Unknown result type (might be due to invalid IL or missing references)
return new SKSize(ButtonWidth * 2f + 1f, 32f);
}
}

View File

@@ -1,469 +1,375 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System;
using System.Collections.Generic;
using SkiaSharp;
namespace Microsoft.Maui.Platform;
/// <summary>
/// A view that supports swipe gestures to reveal actions.
/// </summary>
public class SkiaSwipeView : SkiaLayoutView
{
private SkiaView? _content;
private readonly List<SwipeItem> _leftItems = new();
private readonly List<SwipeItem> _rightItems = new();
private readonly List<SwipeItem> _topItems = new();
private readonly List<SwipeItem> _bottomItems = new();
private SkiaView? _content;
private float _swipeOffset = 0f;
private SwipeDirection _activeDirection = SwipeDirection.None;
private bool _isSwiping = false;
private float _swipeStartX;
private float _swipeStartY;
private float _swipeStartOffset;
private bool _isOpen = false;
private readonly List<SwipeItem> _leftItems = new List<SwipeItem>();
private const float SwipeThreshold = 60f;
private const float VelocityThreshold = 500f;
private float _velocity;
private DateTime _lastMoveTime;
private float _lastMovePosition;
private readonly List<SwipeItem> _rightItems = new List<SwipeItem>();
/// <summary>
/// Gets or sets the content view.
/// </summary>
public SkiaView? Content
{
get => _content;
set
{
if (_content != value)
{
if (_content != null)
{
RemoveChild(_content);
}
private readonly List<SwipeItem> _topItems = new List<SwipeItem>();
_content = value;
private readonly List<SwipeItem> _bottomItems = new List<SwipeItem>();
if (_content != null)
{
AddChild(_content);
}
private float _swipeOffset;
InvalidateMeasure();
Invalidate();
}
}
}
private SwipeDirection _activeDirection;
/// <summary>
/// Gets the left swipe items.
/// </summary>
public IList<SwipeItem> LeftItems => _leftItems;
private bool _isSwiping;
/// <summary>
/// Gets the right swipe items.
/// </summary>
public IList<SwipeItem> RightItems => _rightItems;
private float _swipeStartX;
/// <summary>
/// Gets the top swipe items.
/// </summary>
public IList<SwipeItem> TopItems => _topItems;
private float _swipeStartY;
/// <summary>
/// Gets the bottom swipe items.
/// </summary>
public IList<SwipeItem> BottomItems => _bottomItems;
private float _swipeStartOffset;
/// <summary>
/// Gets or sets the swipe mode.
/// </summary>
public SwipeMode Mode { get; set; } = SwipeMode.Reveal;
private bool _isOpen;
/// <summary>
/// Gets or sets the left swipe threshold.
/// </summary>
public float LeftSwipeThreshold { get; set; } = 100f;
private const float SwipeThreshold = 60f;
/// <summary>
/// Gets or sets the right swipe threshold.
/// </summary>
public float RightSwipeThreshold { get; set; } = 100f;
private const float VelocityThreshold = 500f;
/// <summary>
/// Event raised when swipe is started.
/// </summary>
public event EventHandler<SwipeStartedEventArgs>? SwipeStarted;
private float _velocity;
/// <summary>
/// Event raised when swipe ends.
/// </summary>
public event EventHandler<SwipeEndedEventArgs>? SwipeEnded;
private DateTime _lastMoveTime;
/// <summary>
/// Opens the swipe view in the specified direction.
/// </summary>
public void Open(SwipeDirection direction)
{
_activeDirection = direction;
_isOpen = true;
private float _lastMovePosition;
float targetOffset = direction switch
{
SwipeDirection.Left => -RightSwipeThreshold,
SwipeDirection.Right => LeftSwipeThreshold,
_ => 0
};
public SkiaView? Content
{
get
{
return _content;
}
set
{
if (_content != value)
{
if (_content != null)
{
RemoveChild(_content);
}
_content = value;
if (_content != null)
{
AddChild(_content);
}
InvalidateMeasure();
Invalidate();
}
}
}
AnimateTo(targetOffset);
}
public IList<SwipeItem> LeftItems => _leftItems;
/// <summary>
/// Closes the swipe view.
/// </summary>
public void Close()
{
_isOpen = false;
AnimateTo(0);
}
public IList<SwipeItem> RightItems => _rightItems;
private void AnimateTo(float target)
{
// Simple animation - in production would use proper animation
_swipeOffset = target;
Invalidate();
}
public IList<SwipeItem> TopItems => _topItems;
protected override SKSize MeasureOverride(SKSize availableSize)
{
if (_content != null)
{
_content.Measure(availableSize);
}
return availableSize;
}
public IList<SwipeItem> BottomItems => _bottomItems;
protected override SKRect ArrangeOverride(SKRect bounds)
{
if (_content != null)
{
var contentBounds = new SKRect(
bounds.Left + _swipeOffset,
bounds.Top,
bounds.Right + _swipeOffset,
bounds.Bottom);
_content.Arrange(contentBounds);
}
return bounds;
}
public SwipeMode Mode { get; set; }
protected override void OnDraw(SKCanvas canvas, SKRect bounds)
{
canvas.Save();
canvas.ClipRect(bounds);
public float LeftSwipeThreshold { get; set; } = 100f;
// Draw swipe items behind content
if (_swipeOffset > 0)
{
DrawSwipeItems(canvas, bounds, _leftItems, true);
}
else if (_swipeOffset < 0)
{
DrawSwipeItems(canvas, bounds, _rightItems, false);
}
public float RightSwipeThreshold { get; set; } = 100f;
// Draw content
_content?.Draw(canvas);
public event EventHandler<SwipeStartedEventArgs>? SwipeStarted;
canvas.Restore();
}
public event EventHandler<SwipeEndedEventArgs>? SwipeEnded;
private void DrawSwipeItems(SKCanvas canvas, SKRect bounds, List<SwipeItem> items, bool isLeft)
{
if (items.Count == 0) return;
public void Open(SwipeDirection direction)
{
_activeDirection = direction;
_isOpen = true;
AnimateTo(direction switch
{
SwipeDirection.Left => 0f - RightSwipeThreshold,
SwipeDirection.Right => LeftSwipeThreshold,
_ => 0f,
});
}
float revealWidth = Math.Abs(_swipeOffset);
float itemWidth = revealWidth / items.Count;
public void Close()
{
_isOpen = false;
AnimateTo(0f);
}
for (int i = 0; i < items.Count; i++)
{
var item = items[i];
float x = isLeft ? bounds.Left + i * itemWidth : bounds.Right - (items.Count - i) * itemWidth;
private void AnimateTo(float target)
{
_swipeOffset = target;
Invalidate();
}
var itemBounds = new SKRect(
x,
bounds.Top,
x + itemWidth,
bounds.Bottom);
protected override SKSize MeasureOverride(SKSize availableSize)
{
//IL_0015: Unknown result type (might be due to invalid IL or missing references)
//IL_000e: Unknown result type (might be due to invalid IL or missing references)
//IL_000f: Unknown result type (might be due to invalid IL or missing references)
if (_content != null)
{
_content.Measure(availableSize);
}
return availableSize;
}
// Draw background
using var bgPaint = new SKPaint
{
Color = item.BackgroundColor,
Style = SKPaintStyle.Fill
};
canvas.DrawRect(itemBounds, bgPaint);
protected override SKRect ArrangeOverride(SKRect bounds)
{
//IL_0045: Unknown result type (might be due to invalid IL or missing references)
//IL_003f: Unknown result type (might be due to invalid IL or missing references)
if (_content != null)
{
SKRect bounds2 = default(SKRect);
((SKRect)(ref bounds2))._002Ector(((SKRect)(ref bounds)).Left + _swipeOffset, ((SKRect)(ref bounds)).Top, ((SKRect)(ref bounds)).Right + _swipeOffset, ((SKRect)(ref bounds)).Bottom);
_content.Arrange(bounds2);
}
return bounds;
}
// Draw icon or text
if (!string.IsNullOrEmpty(item.Text))
{
using var textPaint = new SKPaint
{
Color = item.TextColor,
TextSize = 14f,
IsAntialias = true,
TextAlign = SKTextAlign.Center
};
protected override void OnDraw(SKCanvas canvas, SKRect bounds)
{
//IL_0008: Unknown result type (might be due to invalid IL or missing references)
//IL_001f: Unknown result type (might be due to invalid IL or missing references)
//IL_003d: Unknown result type (might be due to invalid IL or missing references)
canvas.Save();
canvas.ClipRect(bounds, (SKClipOperation)1, false);
if (_swipeOffset > 0f)
{
DrawSwipeItems(canvas, bounds, _leftItems, isLeft: true);
}
else if (_swipeOffset < 0f)
{
DrawSwipeItems(canvas, bounds, _rightItems, isLeft: false);
}
_content?.Draw(canvas);
canvas.Restore();
}
float textY = itemBounds.MidY + 5;
canvas.DrawText(item.Text, itemBounds.MidX, textY, textPaint);
}
}
}
private void DrawSwipeItems(SKCanvas canvas, SKRect bounds, List<SwipeItem> items, bool isLeft)
{
//IL_006b: Unknown result type (might be due to invalid IL or missing references)
//IL_0070: Unknown result type (might be due to invalid IL or missing references)
//IL_0072: Unknown result type (might be due to invalid IL or missing references)
//IL_007c: Unknown result type (might be due to invalid IL or missing references)
//IL_0085: Expected O, but got Unknown
//IL_0086: Unknown result type (might be due to invalid IL or missing references)
//IL_009c: Unknown result type (might be due to invalid IL or missing references)
//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
//IL_00c8: Expected O, but got Unknown
if (items.Count == 0)
{
return;
}
float num = Math.Abs(_swipeOffset) / (float)items.Count;
SKRect val = default(SKRect);
for (int i = 0; i < items.Count; i++)
{
SwipeItem swipeItem = items[i];
float num2 = (isLeft ? (((SKRect)(ref bounds)).Left + (float)i * num) : (((SKRect)(ref bounds)).Right - (float)(items.Count - i) * num));
((SKRect)(ref val))._002Ector(num2, ((SKRect)(ref bounds)).Top, num2 + num, ((SKRect)(ref bounds)).Bottom);
SKPaint val2 = new SKPaint
{
Color = swipeItem.BackgroundColor,
Style = (SKPaintStyle)0
};
try
{
canvas.DrawRect(val, val2);
if (!string.IsNullOrEmpty(swipeItem.Text))
{
SKPaint val3 = new SKPaint
{
Color = swipeItem.TextColor,
TextSize = 14f,
IsAntialias = true,
TextAlign = (SKTextAlign)1
};
try
{
float num3 = ((SKRect)(ref val)).MidY + 5f;
canvas.DrawText(swipeItem.Text, ((SKRect)(ref val)).MidX, num3, val3);
}
finally
{
((IDisposable)val3)?.Dispose();
}
}
}
finally
{
((IDisposable)val2)?.Dispose();
}
}
}
public override SkiaView? HitTest(float x, float y)
{
if (!IsVisible || !Bounds.Contains(x, y)) return null;
public override SkiaView? HitTest(float x, float y)
{
//IL_0009: Unknown result type (might be due to invalid IL or missing references)
//IL_000e: Unknown result type (might be due to invalid IL or missing references)
//IL_0033: Unknown result type (might be due to invalid IL or missing references)
//IL_0038: Unknown result type (might be due to invalid IL or missing references)
//IL_005a: Unknown result type (might be due to invalid IL or missing references)
//IL_005f: Unknown result type (might be due to invalid IL or missing references)
if (base.IsVisible)
{
SKRect bounds = base.Bounds;
if (((SKRect)(ref bounds)).Contains(x, y))
{
if (_isOpen)
{
if (_swipeOffset > 0f)
{
bounds = base.Bounds;
if (x < ((SKRect)(ref bounds)).Left + _swipeOffset)
{
return this;
}
}
if (_swipeOffset < 0f)
{
bounds = base.Bounds;
if (x > ((SKRect)(ref bounds)).Right + _swipeOffset)
{
return this;
}
}
}
if (_content != null)
{
SkiaView skiaView = _content.HitTest(x, y);
if (skiaView != null)
{
return skiaView;
}
}
return this;
}
}
return null;
}
// Check if hit is on swipe items
if (_isOpen)
{
if (_swipeOffset > 0 && x < Bounds.Left + _swipeOffset)
{
return this; // Hit on left items
}
else if (_swipeOffset < 0 && x > Bounds.Right + _swipeOffset)
{
return this; // Hit on right items
}
}
public override void OnPointerPressed(PointerEventArgs e)
{
//IL_002a: Unknown result type (might be due to invalid IL or missing references)
//IL_002f: Unknown result type (might be due to invalid IL or missing references)
//IL_009f: Unknown result type (might be due to invalid IL or missing references)
//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
if (!base.IsEnabled)
{
return;
}
if (_isOpen)
{
SwipeItem swipeItem = null;
SKRect bounds;
if (_swipeOffset > 0f)
{
float x = e.X;
bounds = base.Bounds;
int num = (int)((x - ((SKRect)(ref bounds)).Left) / (_swipeOffset / (float)_leftItems.Count));
if (num >= 0 && num < _leftItems.Count)
{
swipeItem = _leftItems[num];
}
}
else if (_swipeOffset < 0f)
{
float num2 = Math.Abs(_swipeOffset) / (float)_rightItems.Count;
float x2 = e.X;
bounds = base.Bounds;
int num3 = (int)((x2 - (((SKRect)(ref bounds)).Right + _swipeOffset)) / num2);
if (num3 >= 0 && num3 < _rightItems.Count)
{
swipeItem = _rightItems[num3];
}
}
if (swipeItem != null)
{
swipeItem.OnInvoked();
Close();
e.Handled = true;
return;
}
}
_isSwiping = true;
_swipeStartX = e.X;
_swipeStartY = e.Y;
_swipeStartOffset = _swipeOffset;
_lastMovePosition = e.X;
_lastMoveTime = DateTime.UtcNow;
_velocity = 0f;
base.OnPointerPressed(e);
}
if (_content != null)
{
var hit = _content.HitTest(x, y);
if (hit != null) return hit;
}
public override void OnPointerMoved(PointerEventArgs e)
{
if (!_isSwiping)
{
return;
}
float num = e.X - _swipeStartX;
_ = e.Y;
_ = _swipeStartY;
if (_activeDirection == SwipeDirection.None && Math.Abs(num) > 10f)
{
_activeDirection = ((!(num > 0f)) ? SwipeDirection.Left : SwipeDirection.Right);
this.SwipeStarted?.Invoke(this, new SwipeStartedEventArgs(_activeDirection));
}
if (_activeDirection == SwipeDirection.Right || _activeDirection == SwipeDirection.Left)
{
_swipeOffset = _swipeStartOffset + num;
float max = ((_leftItems.Count > 0) ? LeftSwipeThreshold : 0f);
float min = ((_rightItems.Count > 0) ? (0f - RightSwipeThreshold) : 0f);
_swipeOffset = Math.Clamp(_swipeOffset, min, max);
DateTime utcNow = DateTime.UtcNow;
float num2 = (float)(utcNow - _lastMoveTime).TotalSeconds;
if (num2 > 0f)
{
_velocity = (e.X - _lastMovePosition) / num2;
}
_lastMovePosition = e.X;
_lastMoveTime = utcNow;
Invalidate();
e.Handled = true;
}
base.OnPointerMoved(e);
}
return this;
}
public override void OnPointerPressed(PointerEventArgs e)
{
if (!IsEnabled) return;
// Check for swipe item tap when open
if (_isOpen)
{
SwipeItem? tappedItem = null;
if (_swipeOffset > 0)
{
int index = (int)((e.X - Bounds.Left) / (_swipeOffset / _leftItems.Count));
if (index >= 0 && index < _leftItems.Count)
{
tappedItem = _leftItems[index];
}
}
else if (_swipeOffset < 0)
{
float itemWidth = Math.Abs(_swipeOffset) / _rightItems.Count;
int index = (int)((e.X - (Bounds.Right + _swipeOffset)) / itemWidth);
if (index >= 0 && index < _rightItems.Count)
{
tappedItem = _rightItems[index];
}
}
if (tappedItem != null)
{
tappedItem.OnInvoked();
Close();
e.Handled = true;
return;
}
}
_isSwiping = true;
_swipeStartX = e.X;
_swipeStartY = e.Y;
_swipeStartOffset = _swipeOffset;
_lastMovePosition = e.X;
_lastMoveTime = DateTime.UtcNow;
_velocity = 0;
base.OnPointerPressed(e);
}
public override void OnPointerMoved(PointerEventArgs e)
{
if (!_isSwiping) return;
float deltaX = e.X - _swipeStartX;
float deltaY = e.Y - _swipeStartY;
// Determine swipe direction
if (_activeDirection == SwipeDirection.None)
{
if (Math.Abs(deltaX) > 10)
{
_activeDirection = deltaX > 0 ? SwipeDirection.Right : SwipeDirection.Left;
SwipeStarted?.Invoke(this, new SwipeStartedEventArgs(_activeDirection));
}
}
if (_activeDirection == SwipeDirection.Right || _activeDirection == SwipeDirection.Left)
{
_swipeOffset = _swipeStartOffset + deltaX;
// Clamp offset based on available items
float maxRight = _leftItems.Count > 0 ? LeftSwipeThreshold : 0;
float maxLeft = _rightItems.Count > 0 ? -RightSwipeThreshold : 0;
_swipeOffset = Math.Clamp(_swipeOffset, maxLeft, maxRight);
// Calculate velocity
var now = DateTime.UtcNow;
float timeDelta = (float)(now - _lastMoveTime).TotalSeconds;
if (timeDelta > 0)
{
_velocity = (e.X - _lastMovePosition) / timeDelta;
}
_lastMovePosition = e.X;
_lastMoveTime = now;
Invalidate();
e.Handled = true;
}
base.OnPointerMoved(e);
}
public override void OnPointerReleased(PointerEventArgs e)
{
if (!_isSwiping) return;
_isSwiping = false;
// Determine final state
bool shouldOpen = false;
if (Math.Abs(_velocity) > VelocityThreshold)
{
// Use velocity
shouldOpen = (_velocity > 0 && _leftItems.Count > 0) || (_velocity < 0 && _rightItems.Count > 0);
}
else
{
// Use threshold
shouldOpen = Math.Abs(_swipeOffset) > SwipeThreshold;
}
if (shouldOpen)
{
if (_swipeOffset > 0)
{
Open(SwipeDirection.Right);
}
else
{
Open(SwipeDirection.Left);
}
}
else
{
Close();
}
SwipeEnded?.Invoke(this, new SwipeEndedEventArgs(_activeDirection, _isOpen));
_activeDirection = SwipeDirection.None;
base.OnPointerReleased(e);
}
}
/// <summary>
/// Represents a swipe action item.
/// </summary>
public class SwipeItem
{
/// <summary>
/// Gets or sets the text.
/// </summary>
public string Text { get; set; } = string.Empty;
/// <summary>
/// Gets or sets the icon source.
/// </summary>
public string? IconSource { get; set; }
/// <summary>
/// Gets or sets the background color.
/// </summary>
public SKColor BackgroundColor { get; set; } = new SKColor(33, 150, 243);
/// <summary>
/// Gets or sets the text color.
/// </summary>
public SKColor TextColor { get; set; } = SKColors.White;
/// <summary>
/// Event raised when the item is invoked.
/// </summary>
public event EventHandler? Invoked;
internal void OnInvoked()
{
Invoked?.Invoke(this, EventArgs.Empty);
}
}
/// <summary>
/// Swipe direction.
/// </summary>
public enum SwipeDirection
{
None,
Left,
Right,
Up,
Down
}
/// <summary>
/// Swipe mode.
/// </summary>
public enum SwipeMode
{
Reveal,
Execute
}
/// <summary>
/// Event args for swipe started.
/// </summary>
public class SwipeStartedEventArgs : EventArgs
{
public SwipeDirection Direction { get; }
public SwipeStartedEventArgs(SwipeDirection direction)
{
Direction = direction;
}
}
/// <summary>
/// Event args for swipe ended.
/// </summary>
public class SwipeEndedEventArgs : EventArgs
{
public SwipeDirection Direction { get; }
public bool IsOpen { get; }
public SwipeEndedEventArgs(SwipeDirection direction, bool isOpen)
{
Direction = direction;
IsOpen = isOpen;
}
public override void OnPointerReleased(PointerEventArgs e)
{
if (!_isSwiping)
{
return;
}
_isSwiping = false;
bool flag = false;
if ((!(Math.Abs(_velocity) > 500f)) ? (Math.Abs(_swipeOffset) > 60f) : ((_velocity > 0f && _leftItems.Count > 0) || (_velocity < 0f && _rightItems.Count > 0)))
{
if (_swipeOffset > 0f)
{
Open(SwipeDirection.Right);
}
else
{
Open(SwipeDirection.Left);
}
}
else
{
Close();
}
this.SwipeEnded?.Invoke(this, new SwipeEndedEventArgs(_activeDirection, _isOpen));
_activeDirection = SwipeDirection.None;
base.OnPointerReleased(e);
}
}

View File

@@ -1,339 +1,343 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System;
using Microsoft.Maui.Controls;
using SkiaSharp;
namespace Microsoft.Maui.Platform;
/// <summary>
/// Skia-rendered toggle switch control with full XAML styling support.
/// </summary>
public class SkiaSwitch : SkiaView
{
#region BindableProperties
public static readonly BindableProperty IsOnProperty = BindableProperty.Create("IsOn", typeof(bool), typeof(SkiaSwitch), (object)false, (BindingMode)1, (ValidateValueDelegate)null, (BindingPropertyChangedDelegate)delegate(BindableObject b, object o, object n)
{
((SkiaSwitch)(object)b).OnIsOnChanged();
}, (BindingPropertyChangingDelegate)null, (CoerceValueDelegate)null, (CreateDefaultValueDelegate)null);
/// <summary>
/// Bindable property for IsOn.
/// </summary>
public static readonly BindableProperty IsOnProperty =
BindableProperty.Create(
nameof(IsOn),
typeof(bool),
typeof(SkiaSwitch),
false,
BindingMode.TwoWay,
propertyChanged: (b, o, n) => ((SkiaSwitch)b).OnIsOnChanged());
public static readonly BindableProperty OnTrackColorProperty = BindableProperty.Create("OnTrackColor", typeof(SKColor), typeof(SkiaSwitch), (object)new SKColor((byte)33, (byte)150, (byte)243), (BindingMode)2, (ValidateValueDelegate)null, (BindingPropertyChangedDelegate)delegate(BindableObject b, object o, object n)
{
((SkiaSwitch)(object)b).Invalidate();
}, (BindingPropertyChangingDelegate)null, (CoerceValueDelegate)null, (CreateDefaultValueDelegate)null);
/// <summary>
/// Bindable property for OnTrackColor.
/// </summary>
public static readonly BindableProperty OnTrackColorProperty =
BindableProperty.Create(
nameof(OnTrackColor),
typeof(SKColor),
typeof(SkiaSwitch),
new SKColor(0x21, 0x96, 0xF3),
propertyChanged: (b, o, n) => ((SkiaSwitch)b).Invalidate());
public static readonly BindableProperty OffTrackColorProperty = BindableProperty.Create("OffTrackColor", typeof(SKColor), typeof(SkiaSwitch), (object)new SKColor((byte)158, (byte)158, (byte)158), (BindingMode)2, (ValidateValueDelegate)null, (BindingPropertyChangedDelegate)delegate(BindableObject b, object o, object n)
{
((SkiaSwitch)(object)b).Invalidate();
}, (BindingPropertyChangingDelegate)null, (CoerceValueDelegate)null, (CreateDefaultValueDelegate)null);
/// <summary>
/// Bindable property for OffTrackColor.
/// </summary>
public static readonly BindableProperty OffTrackColorProperty =
BindableProperty.Create(
nameof(OffTrackColor),
typeof(SKColor),
typeof(SkiaSwitch),
new SKColor(0x9E, 0x9E, 0x9E),
propertyChanged: (b, o, n) => ((SkiaSwitch)b).Invalidate());
public static readonly BindableProperty ThumbColorProperty = BindableProperty.Create("ThumbColor", typeof(SKColor), typeof(SkiaSwitch), (object)SKColors.White, (BindingMode)2, (ValidateValueDelegate)null, (BindingPropertyChangedDelegate)delegate(BindableObject b, object o, object n)
{
((SkiaSwitch)(object)b).Invalidate();
}, (BindingPropertyChangingDelegate)null, (CoerceValueDelegate)null, (CreateDefaultValueDelegate)null);
/// <summary>
/// Bindable property for ThumbColor.
/// </summary>
public static readonly BindableProperty ThumbColorProperty =
BindableProperty.Create(
nameof(ThumbColor),
typeof(SKColor),
typeof(SkiaSwitch),
SKColors.White,
propertyChanged: (b, o, n) => ((SkiaSwitch)b).Invalidate());
public static readonly BindableProperty DisabledColorProperty = BindableProperty.Create("DisabledColor", typeof(SKColor), typeof(SkiaSwitch), (object)new SKColor((byte)189, (byte)189, (byte)189), (BindingMode)2, (ValidateValueDelegate)null, (BindingPropertyChangedDelegate)delegate(BindableObject b, object o, object n)
{
((SkiaSwitch)(object)b).Invalidate();
}, (BindingPropertyChangingDelegate)null, (CoerceValueDelegate)null, (CreateDefaultValueDelegate)null);
/// <summary>
/// Bindable property for DisabledColor.
/// </summary>
public static readonly BindableProperty DisabledColorProperty =
BindableProperty.Create(
nameof(DisabledColor),
typeof(SKColor),
typeof(SkiaSwitch),
new SKColor(0xBD, 0xBD, 0xBD),
propertyChanged: (b, o, n) => ((SkiaSwitch)b).Invalidate());
public static readonly BindableProperty TrackWidthProperty = BindableProperty.Create("TrackWidth", typeof(float), typeof(SkiaSwitch), (object)52f, (BindingMode)2, (ValidateValueDelegate)null, (BindingPropertyChangedDelegate)delegate(BindableObject b, object o, object n)
{
((SkiaSwitch)(object)b).InvalidateMeasure();
}, (BindingPropertyChangingDelegate)null, (CoerceValueDelegate)null, (CreateDefaultValueDelegate)null);
/// <summary>
/// Bindable property for TrackWidth.
/// </summary>
public static readonly BindableProperty TrackWidthProperty =
BindableProperty.Create(
nameof(TrackWidth),
typeof(float),
typeof(SkiaSwitch),
52f,
propertyChanged: (b, o, n) => ((SkiaSwitch)b).InvalidateMeasure());
public static readonly BindableProperty TrackHeightProperty = BindableProperty.Create("TrackHeight", typeof(float), typeof(SkiaSwitch), (object)32f, (BindingMode)2, (ValidateValueDelegate)null, (BindingPropertyChangedDelegate)delegate(BindableObject b, object o, object n)
{
((SkiaSwitch)(object)b).InvalidateMeasure();
}, (BindingPropertyChangingDelegate)null, (CoerceValueDelegate)null, (CreateDefaultValueDelegate)null);
/// <summary>
/// Bindable property for TrackHeight.
/// </summary>
public static readonly BindableProperty TrackHeightProperty =
BindableProperty.Create(
nameof(TrackHeight),
typeof(float),
typeof(SkiaSwitch),
32f,
propertyChanged: (b, o, n) => ((SkiaSwitch)b).InvalidateMeasure());
public static readonly BindableProperty ThumbRadiusProperty = BindableProperty.Create("ThumbRadius", typeof(float), typeof(SkiaSwitch), (object)12f, (BindingMode)2, (ValidateValueDelegate)null, (BindingPropertyChangedDelegate)delegate(BindableObject b, object o, object n)
{
((SkiaSwitch)(object)b).Invalidate();
}, (BindingPropertyChangingDelegate)null, (CoerceValueDelegate)null, (CreateDefaultValueDelegate)null);
/// <summary>
/// Bindable property for ThumbRadius.
/// </summary>
public static readonly BindableProperty ThumbRadiusProperty =
BindableProperty.Create(
nameof(ThumbRadius),
typeof(float),
typeof(SkiaSwitch),
12f,
propertyChanged: (b, o, n) => ((SkiaSwitch)b).Invalidate());
public static readonly BindableProperty ThumbPaddingProperty = BindableProperty.Create("ThumbPadding", typeof(float), typeof(SkiaSwitch), (object)4f, (BindingMode)2, (ValidateValueDelegate)null, (BindingPropertyChangedDelegate)delegate(BindableObject b, object o, object n)
{
((SkiaSwitch)(object)b).Invalidate();
}, (BindingPropertyChangingDelegate)null, (CoerceValueDelegate)null, (CreateDefaultValueDelegate)null);
/// <summary>
/// Bindable property for ThumbPadding.
/// </summary>
public static readonly BindableProperty ThumbPaddingProperty =
BindableProperty.Create(
nameof(ThumbPadding),
typeof(float),
typeof(SkiaSwitch),
4f,
propertyChanged: (b, o, n) => ((SkiaSwitch)b).Invalidate());
private float _animationProgress;
#endregion
public bool IsOn
{
get
{
return (bool)((BindableObject)this).GetValue(IsOnProperty);
}
set
{
((BindableObject)this).SetValue(IsOnProperty, (object)value);
}
}
#region Properties
public SKColor OnTrackColor
{
get
{
//IL_000b: Unknown result type (might be due to invalid IL or missing references)
return (SKColor)((BindableObject)this).GetValue(OnTrackColorProperty);
}
set
{
//IL_0006: Unknown result type (might be due to invalid IL or missing references)
((BindableObject)this).SetValue(OnTrackColorProperty, (object)value);
}
}
/// <summary>
/// Gets or sets whether the switch is on.
/// </summary>
public bool IsOn
{
get => (bool)GetValue(IsOnProperty);
set => SetValue(IsOnProperty, value);
}
public SKColor OffTrackColor
{
get
{
//IL_000b: Unknown result type (might be due to invalid IL or missing references)
return (SKColor)((BindableObject)this).GetValue(OffTrackColorProperty);
}
set
{
//IL_0006: Unknown result type (might be due to invalid IL or missing references)
((BindableObject)this).SetValue(OffTrackColorProperty, (object)value);
}
}
/// <summary>
/// Gets or sets the on track color.
/// </summary>
public SKColor OnTrackColor
{
get => (SKColor)GetValue(OnTrackColorProperty);
set => SetValue(OnTrackColorProperty, value);
}
public SKColor ThumbColor
{
get
{
//IL_000b: Unknown result type (might be due to invalid IL or missing references)
return (SKColor)((BindableObject)this).GetValue(ThumbColorProperty);
}
set
{
//IL_0006: Unknown result type (might be due to invalid IL or missing references)
((BindableObject)this).SetValue(ThumbColorProperty, (object)value);
}
}
/// <summary>
/// Gets or sets the off track color.
/// </summary>
public SKColor OffTrackColor
{
get => (SKColor)GetValue(OffTrackColorProperty);
set => SetValue(OffTrackColorProperty, value);
}
public SKColor DisabledColor
{
get
{
//IL_000b: Unknown result type (might be due to invalid IL or missing references)
return (SKColor)((BindableObject)this).GetValue(DisabledColorProperty);
}
set
{
//IL_0006: Unknown result type (might be due to invalid IL or missing references)
((BindableObject)this).SetValue(DisabledColorProperty, (object)value);
}
}
/// <summary>
/// Gets or sets the thumb color.
/// </summary>
public SKColor ThumbColor
{
get => (SKColor)GetValue(ThumbColorProperty);
set => SetValue(ThumbColorProperty, value);
}
public float TrackWidth
{
get
{
return (float)((BindableObject)this).GetValue(TrackWidthProperty);
}
set
{
((BindableObject)this).SetValue(TrackWidthProperty, (object)value);
}
}
/// <summary>
/// Gets or sets the disabled color.
/// </summary>
public SKColor DisabledColor
{
get => (SKColor)GetValue(DisabledColorProperty);
set => SetValue(DisabledColorProperty, value);
}
public float TrackHeight
{
get
{
return (float)((BindableObject)this).GetValue(TrackHeightProperty);
}
set
{
((BindableObject)this).SetValue(TrackHeightProperty, (object)value);
}
}
/// <summary>
/// Gets or sets the track width.
/// </summary>
public float TrackWidth
{
get => (float)GetValue(TrackWidthProperty);
set => SetValue(TrackWidthProperty, value);
}
public float ThumbRadius
{
get
{
return (float)((BindableObject)this).GetValue(ThumbRadiusProperty);
}
set
{
((BindableObject)this).SetValue(ThumbRadiusProperty, (object)value);
}
}
/// <summary>
/// Gets or sets the track height.
/// </summary>
public float TrackHeight
{
get => (float)GetValue(TrackHeightProperty);
set => SetValue(TrackHeightProperty, value);
}
public float ThumbPadding
{
get
{
return (float)((BindableObject)this).GetValue(ThumbPaddingProperty);
}
set
{
((BindableObject)this).SetValue(ThumbPaddingProperty, (object)value);
}
}
/// <summary>
/// Gets or sets the thumb radius.
/// </summary>
public float ThumbRadius
{
get => (float)GetValue(ThumbRadiusProperty);
set => SetValue(ThumbRadiusProperty, value);
}
public event EventHandler<ToggledEventArgs>? Toggled;
/// <summary>
/// Gets or sets the thumb padding.
/// </summary>
public float ThumbPadding
{
get => (float)GetValue(ThumbPaddingProperty);
set => SetValue(ThumbPaddingProperty, value);
}
public SkiaSwitch()
{
base.IsFocusable = true;
}
#endregion
private void OnIsOnChanged()
{
_animationProgress = (IsOn ? 1f : 0f);
this.Toggled?.Invoke(this, new ToggledEventArgs(IsOn));
SkiaVisualStateManager.GoToState(this, IsOn ? "On" : "Off");
Invalidate();
}
private float _animationProgress; // 0 = off, 1 = on
protected override void OnDraw(SKCanvas canvas, SKRect bounds)
{
//IL_0067: Unknown result type (might be due to invalid IL or missing references)
//IL_006d: Unknown result type (might be due to invalid IL or missing references)
//IL_0078: Unknown result type (might be due to invalid IL or missing references)
//IL_005f: Unknown result type (might be due to invalid IL or missing references)
//IL_007d: Unknown result type (might be due to invalid IL or missing references)
//IL_007f: Unknown result type (might be due to invalid IL or missing references)
//IL_0084: Unknown result type (might be due to invalid IL or missing references)
//IL_0085: Unknown result type (might be due to invalid IL or missing references)
//IL_008c: Unknown result type (might be due to invalid IL or missing references)
//IL_0093: Unknown result type (might be due to invalid IL or missing references)
//IL_009c: Expected O, but got Unknown
//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
//IL_00cb: Unknown result type (might be due to invalid IL or missing references)
//IL_00d2: Expected O, but got Unknown
//IL_013e: Unknown result type (might be due to invalid IL or missing references)
//IL_0143: Unknown result type (might be due to invalid IL or missing references)
//IL_00e4: Unknown result type (might be due to invalid IL or missing references)
//IL_00e9: Unknown result type (might be due to invalid IL or missing references)
//IL_00ef: Unknown result type (might be due to invalid IL or missing references)
//IL_00f9: Unknown result type (might be due to invalid IL or missing references)
//IL_0100: Unknown result type (might be due to invalid IL or missing references)
//IL_0113: Expected O, but got Unknown
//IL_0163: Unknown result type (might be due to invalid IL or missing references)
//IL_015b: Unknown result type (might be due to invalid IL or missing references)
//IL_016d: Unknown result type (might be due to invalid IL or missing references)
//IL_0174: Unknown result type (might be due to invalid IL or missing references)
//IL_017d: Expected O, but got Unknown
//IL_0196: Unknown result type (might be due to invalid IL or missing references)
//IL_019b: Unknown result type (might be due to invalid IL or missing references)
//IL_019d: Unknown result type (might be due to invalid IL or missing references)
//IL_01a2: Unknown result type (might be due to invalid IL or missing references)
//IL_01a8: Unknown result type (might be due to invalid IL or missing references)
//IL_01b2: Unknown result type (might be due to invalid IL or missing references)
//IL_01b9: Unknown result type (might be due to invalid IL or missing references)
//IL_01c0: Unknown result type (might be due to invalid IL or missing references)
//IL_01cd: Expected O, but got Unknown
//IL_01cf: Unknown result type (might be due to invalid IL or missing references)
//IL_01e0: Unknown result type (might be due to invalid IL or missing references)
//IL_01e7: Expected O, but got Unknown
float midY = ((SKRect)(ref bounds)).MidY;
float num = ((SKRect)(ref bounds)).MidX - TrackWidth / 2f;
float num2 = num + TrackWidth;
float num3 = num + ThumbPadding + ThumbRadius;
float num4 = num2 - ThumbPadding - ThumbRadius;
float num5 = num3 + _animationProgress * (num4 - num3);
SKColor color = (base.IsEnabled ? InterpolateColor(OffTrackColor, OnTrackColor, _animationProgress) : DisabledColor);
SKPaint val = new SKPaint
{
Color = color,
IsAntialias = true,
Style = (SKPaintStyle)0
};
try
{
SKRoundRect val2 = new SKRoundRect(new SKRect(num, midY - TrackHeight / 2f, num2, midY + TrackHeight / 2f), TrackHeight / 2f);
canvas.DrawRoundRect(val2, val);
if (base.IsEnabled)
{
SKPaint val3 = new SKPaint
{
Color = new SKColor((byte)0, (byte)0, (byte)0, (byte)40),
IsAntialias = true,
MaskFilter = SKMaskFilter.CreateBlur((SKBlurStyle)0, 2f)
};
try
{
canvas.DrawCircle(num5 + 1f, midY + 1f, ThumbRadius, val3);
}
finally
{
((IDisposable)val3)?.Dispose();
}
}
SKPaint val4 = new SKPaint
{
Color = (SKColor)(base.IsEnabled ? ThumbColor : new SKColor((byte)245, (byte)245, (byte)245)),
IsAntialias = true,
Style = (SKPaintStyle)0
};
try
{
canvas.DrawCircle(num5, midY, ThumbRadius, val4);
if (base.IsFocused)
{
SKPaint val5 = new SKPaint();
SKColor onTrackColor = OnTrackColor;
val5.Color = ((SKColor)(ref onTrackColor)).WithAlpha((byte)60);
val5.IsAntialias = true;
val5.Style = (SKPaintStyle)1;
val5.StrokeWidth = 3f;
SKPaint val6 = val5;
try
{
SKRoundRect val7 = new SKRoundRect(val2.Rect, TrackHeight / 2f);
val7.Inflate(3f, 3f);
canvas.DrawRoundRect(val7, val6);
return;
}
finally
{
((IDisposable)val6)?.Dispose();
}
}
}
finally
{
((IDisposable)val4)?.Dispose();
}
}
finally
{
((IDisposable)val)?.Dispose();
}
}
/// <summary>
/// Event raised when the switch is toggled.
/// </summary>
public event EventHandler<ToggledEventArgs>? Toggled;
private static SKColor InterpolateColor(SKColor from, SKColor to, float t)
{
//IL_0070: Unknown result type (might be due to invalid IL or missing references)
return new SKColor((byte)((float)(int)((SKColor)(ref from)).Red + (float)(((SKColor)(ref to)).Red - ((SKColor)(ref from)).Red) * t), (byte)((float)(int)((SKColor)(ref from)).Green + (float)(((SKColor)(ref to)).Green - ((SKColor)(ref from)).Green) * t), (byte)((float)(int)((SKColor)(ref from)).Blue + (float)(((SKColor)(ref to)).Blue - ((SKColor)(ref from)).Blue) * t), (byte)((float)(int)((SKColor)(ref from)).Alpha + (float)(((SKColor)(ref to)).Alpha - ((SKColor)(ref from)).Alpha) * t));
}
public SkiaSwitch()
{
IsFocusable = true;
}
public override void OnPointerPressed(PointerEventArgs e)
{
if (base.IsEnabled)
{
IsOn = !IsOn;
e.Handled = true;
}
}
private void OnIsOnChanged()
{
_animationProgress = IsOn ? 1f : 0f;
Toggled?.Invoke(this, new ToggledEventArgs(IsOn));
SkiaVisualStateManager.GoToState(this, IsOn ? SkiaVisualStateManager.CommonStates.On : SkiaVisualStateManager.CommonStates.Off);
Invalidate();
}
public override void OnPointerReleased(PointerEventArgs e)
{
}
protected override void OnDraw(SKCanvas canvas, SKRect bounds)
{
var centerY = bounds.MidY;
var trackLeft = bounds.MidX - TrackWidth / 2;
var trackRight = trackLeft + TrackWidth;
public override void OnKeyDown(KeyEventArgs e)
{
if (base.IsEnabled && (e.Key == Key.Space || e.Key == Key.Enter))
{
IsOn = !IsOn;
e.Handled = true;
}
}
// Calculate thumb position
var thumbMinX = trackLeft + ThumbPadding + ThumbRadius;
var thumbMaxX = trackRight - ThumbPadding - ThumbRadius;
var thumbX = thumbMinX + _animationProgress * (thumbMaxX - thumbMinX);
protected override void OnEnabledChanged()
{
base.OnEnabledChanged();
SkiaVisualStateManager.GoToState(this, base.IsEnabled ? "Normal" : "Disabled");
}
// Interpolate track color
var trackColor = IsEnabled
? InterpolateColor(OffTrackColor, OnTrackColor, _animationProgress)
: DisabledColor;
// Draw track
using var trackPaint = new SKPaint
{
Color = trackColor,
IsAntialias = true,
Style = SKPaintStyle.Fill
};
var trackRect = new SKRoundRect(
new SKRect(trackLeft, centerY - TrackHeight / 2, trackRight, centerY + TrackHeight / 2),
TrackHeight / 2);
canvas.DrawRoundRect(trackRect, trackPaint);
// Draw thumb shadow
if (IsEnabled)
{
using var shadowPaint = new SKPaint
{
Color = new SKColor(0, 0, 0, 40),
IsAntialias = true,
MaskFilter = SKMaskFilter.CreateBlur(SKBlurStyle.Normal, 2)
};
canvas.DrawCircle(thumbX + 1, centerY + 1, ThumbRadius, shadowPaint);
}
// Draw thumb
using var thumbPaint = new SKPaint
{
Color = IsEnabled ? ThumbColor : new SKColor(0xF5, 0xF5, 0xF5),
IsAntialias = true,
Style = SKPaintStyle.Fill
};
canvas.DrawCircle(thumbX, centerY, ThumbRadius, thumbPaint);
// Draw focus ring
if (IsFocused)
{
using var focusPaint = new SKPaint
{
Color = OnTrackColor.WithAlpha(60),
IsAntialias = true,
Style = SKPaintStyle.Stroke,
StrokeWidth = 3
};
var focusRect = new SKRoundRect(trackRect.Rect, TrackHeight / 2);
focusRect.Inflate(3, 3);
canvas.DrawRoundRect(focusRect, focusPaint);
}
}
private static SKColor InterpolateColor(SKColor from, SKColor to, float t)
{
return new SKColor(
(byte)(from.Red + (to.Red - from.Red) * t),
(byte)(from.Green + (to.Green - from.Green) * t),
(byte)(from.Blue + (to.Blue - from.Blue) * t),
(byte)(from.Alpha + (to.Alpha - from.Alpha) * t));
}
public override void OnPointerPressed(PointerEventArgs e)
{
if (!IsEnabled) return;
IsOn = !IsOn;
e.Handled = true;
}
public override void OnPointerReleased(PointerEventArgs e)
{
// Toggle handled in OnPointerPressed
}
public override void OnKeyDown(KeyEventArgs e)
{
if (!IsEnabled) return;
if (e.Key == Key.Space || e.Key == Key.Enter)
{
IsOn = !IsOn;
e.Handled = true;
}
}
protected override void OnEnabledChanged()
{
base.OnEnabledChanged();
SkiaVisualStateManager.GoToState(this, IsEnabled ? SkiaVisualStateManager.CommonStates.Normal : SkiaVisualStateManager.CommonStates.Disabled);
}
protected override SKSize MeasureOverride(SKSize availableSize)
{
return new SKSize(TrackWidth + 8, TrackHeight + 8);
}
}
/// <summary>
/// Event args for toggled events.
/// </summary>
public class ToggledEventArgs : EventArgs
{
public bool Value { get; }
public ToggledEventArgs(bool value) => Value = value;
protected override SKSize MeasureOverride(SKSize availableSize)
{
//IL_0018: Unknown result type (might be due to invalid IL or missing references)
return new SKSize(TrackWidth + 8f, TrackHeight + 8f);
}
}

View File

@@ -1,422 +1,443 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System;
using System.Collections.Generic;
using SkiaSharp;
namespace Microsoft.Maui.Platform;
/// <summary>
/// A page that displays tabs for navigation between child pages.
/// </summary>
public class SkiaTabbedPage : SkiaLayoutView
{
private readonly List<TabItem> _tabs = new();
private int _selectedIndex = 0;
private float _tabBarHeight = 48f;
private bool _tabBarOnBottom = false;
private readonly List<TabItem> _tabs = new List<TabItem>();
/// <summary>
/// Gets or sets the height of the tab bar.
/// </summary>
public float TabBarHeight
{
get => _tabBarHeight;
set
{
if (_tabBarHeight != value)
{
_tabBarHeight = value;
InvalidateMeasure();
Invalidate();
}
}
}
private int _selectedIndex;
/// <summary>
/// Gets or sets whether the tab bar is positioned at the bottom.
/// </summary>
public bool TabBarOnBottom
{
get => _tabBarOnBottom;
set
{
if (_tabBarOnBottom != value)
{
_tabBarOnBottom = value;
Invalidate();
}
}
}
private float _tabBarHeight = 48f;
/// <summary>
/// Gets or sets the selected tab index.
/// </summary>
public int SelectedIndex
{
get => _selectedIndex;
set
{
if (value >= 0 && value < _tabs.Count && _selectedIndex != value)
{
_selectedIndex = value;
SelectedIndexChanged?.Invoke(this, EventArgs.Empty);
Invalidate();
}
}
}
private bool _tabBarOnBottom;
/// <summary>
/// Gets the currently selected tab.
/// </summary>
public TabItem? SelectedTab => _selectedIndex >= 0 && _selectedIndex < _tabs.Count
? _tabs[_selectedIndex]
: null;
public float TabBarHeight
{
get
{
return _tabBarHeight;
}
set
{
if (_tabBarHeight != value)
{
_tabBarHeight = value;
InvalidateMeasure();
Invalidate();
}
}
}
/// <summary>
/// Gets the tabs in this page.
/// </summary>
public IReadOnlyList<TabItem> Tabs => _tabs;
public bool TabBarOnBottom
{
get
{
return _tabBarOnBottom;
}
set
{
if (_tabBarOnBottom != value)
{
_tabBarOnBottom = value;
Invalidate();
}
}
}
/// <summary>
/// Background color for the tab bar.
/// </summary>
public SKColor TabBarBackgroundColor { get; set; } = new SKColor(33, 150, 243); // Material Blue
public int SelectedIndex
{
get
{
return _selectedIndex;
}
set
{
if (value >= 0 && value < _tabs.Count && _selectedIndex != value)
{
_selectedIndex = value;
this.SelectedIndexChanged?.Invoke(this, EventArgs.Empty);
Invalidate();
}
}
}
/// <summary>
/// Color for selected tab text/icon.
/// </summary>
public SKColor SelectedTabColor { get; set; } = SKColors.White;
public TabItem? SelectedTab
{
get
{
if (_selectedIndex < 0 || _selectedIndex >= _tabs.Count)
{
return null;
}
return _tabs[_selectedIndex];
}
}
/// <summary>
/// Color for unselected tab text/icon.
/// </summary>
public SKColor UnselectedTabColor { get; set; } = new SKColor(255, 255, 255, 180);
public IReadOnlyList<TabItem> Tabs => _tabs;
/// <summary>
/// Color of the selection indicator.
/// </summary>
public SKColor IndicatorColor { get; set; } = SKColors.White;
public SKColor TabBarBackgroundColor { get; set; } = new SKColor((byte)33, (byte)150, (byte)243);
/// <summary>
/// Height of the selection indicator.
/// </summary>
public float IndicatorHeight { get; set; } = 3f;
public SKColor SelectedTabColor { get; set; } = SKColors.White;
/// <summary>
/// Event raised when the selected index changes.
/// </summary>
public event EventHandler? SelectedIndexChanged;
public SKColor UnselectedTabColor { get; set; } = new SKColor(byte.MaxValue, byte.MaxValue, byte.MaxValue, (byte)180);
/// <summary>
/// Adds a tab with the specified title and content.
/// </summary>
public void AddTab(string title, SkiaView content, string? iconPath = null)
{
var tab = new TabItem
{
Title = title,
Content = content,
IconPath = iconPath
};
public SKColor IndicatorColor { get; set; } = SKColors.White;
_tabs.Add(tab);
AddChild(content);
public float IndicatorHeight { get; set; } = 3f;
if (_tabs.Count == 1)
{
_selectedIndex = 0;
}
public event EventHandler? SelectedIndexChanged;
InvalidateMeasure();
Invalidate();
}
public void AddTab(string title, SkiaView content, string? iconPath = null)
{
TabItem item = new TabItem
{
Title = title,
Content = content,
IconPath = iconPath
};
_tabs.Add(item);
AddChild(content);
if (_tabs.Count == 1)
{
_selectedIndex = 0;
}
InvalidateMeasure();
Invalidate();
}
/// <summary>
/// Removes a tab at the specified index.
/// </summary>
public void RemoveTab(int index)
{
if (index >= 0 && index < _tabs.Count)
{
var tab = _tabs[index];
_tabs.RemoveAt(index);
RemoveChild(tab.Content);
public void RemoveTab(int index)
{
if (index >= 0 && index < _tabs.Count)
{
TabItem tabItem = _tabs[index];
_tabs.RemoveAt(index);
RemoveChild(tabItem.Content);
if (_selectedIndex >= _tabs.Count)
{
_selectedIndex = Math.Max(0, _tabs.Count - 1);
}
InvalidateMeasure();
Invalidate();
}
}
if (_selectedIndex >= _tabs.Count)
{
_selectedIndex = Math.Max(0, _tabs.Count - 1);
}
public void ClearTabs()
{
foreach (TabItem tab in _tabs)
{
RemoveChild(tab.Content);
}
_tabs.Clear();
_selectedIndex = 0;
InvalidateMeasure();
Invalidate();
}
InvalidateMeasure();
Invalidate();
}
}
protected override SKSize MeasureOverride(SKSize availableSize)
{
//IL_0038: Unknown result type (might be due to invalid IL or missing references)
//IL_0039: Unknown result type (might be due to invalid IL or missing references)
//IL_0058: Unknown result type (might be due to invalid IL or missing references)
float num = ((SKSize)(ref availableSize)).Height - TabBarHeight;
SKSize availableSize2 = default(SKSize);
((SKSize)(ref availableSize2))._002Ector(((SKSize)(ref availableSize)).Width, num);
foreach (TabItem tab in _tabs)
{
tab.Content.Measure(availableSize2);
}
return availableSize;
}
/// <summary>
/// Clears all tabs.
/// </summary>
public void ClearTabs()
{
foreach (var tab in _tabs)
{
RemoveChild(tab.Content);
}
_tabs.Clear();
_selectedIndex = 0;
InvalidateMeasure();
Invalidate();
}
protected override SKRect ArrangeOverride(SKRect bounds)
{
//IL_0078: Unknown result type (might be due to invalid IL or missing references)
//IL_0097: Unknown result type (might be due to invalid IL or missing references)
SKRect bounds2 = default(SKRect);
if (TabBarOnBottom)
{
((SKRect)(ref bounds2))._002Ector(((SKRect)(ref bounds)).Left, ((SKRect)(ref bounds)).Top, ((SKRect)(ref bounds)).Right, ((SKRect)(ref bounds)).Bottom - TabBarHeight);
}
else
{
((SKRect)(ref bounds2))._002Ector(((SKRect)(ref bounds)).Left, ((SKRect)(ref bounds)).Top + TabBarHeight, ((SKRect)(ref bounds)).Right, ((SKRect)(ref bounds)).Bottom);
}
foreach (TabItem tab in _tabs)
{
tab.Content.Arrange(bounds2);
}
return bounds;
}
protected override SKSize MeasureOverride(SKSize availableSize)
{
// Measure the content area (excluding tab bar)
var contentHeight = availableSize.Height - TabBarHeight;
var contentSize = new SKSize(availableSize.Width, contentHeight);
protected override void OnDraw(SKCanvas canvas, SKRect bounds)
{
//IL_0008: Unknown result type (might be due to invalid IL or missing references)
canvas.Save();
canvas.ClipRect(bounds, (SKClipOperation)1, false);
DrawTabBar(canvas);
if (_selectedIndex >= 0 && _selectedIndex < _tabs.Count)
{
_tabs[_selectedIndex].Content.Draw(canvas);
}
canvas.Restore();
}
foreach (var tab in _tabs)
{
tab.Content.Measure(contentSize);
}
private void DrawTabBar(SKCanvas canvas)
{
//IL_0057: Unknown result type (might be due to invalid IL or missing references)
//IL_005c: Unknown result type (might be due to invalid IL or missing references)
//IL_0066: Unknown result type (might be due to invalid IL or missing references)
//IL_006b: Unknown result type (might be due to invalid IL or missing references)
//IL_0075: Unknown result type (might be due to invalid IL or missing references)
//IL_007a: Unknown result type (might be due to invalid IL or missing references)
//IL_0084: Unknown result type (might be due to invalid IL or missing references)
//IL_0089: Unknown result type (might be due to invalid IL or missing references)
//IL_000b: Unknown result type (might be due to invalid IL or missing references)
//IL_0010: Unknown result type (might be due to invalid IL or missing references)
//IL_001a: Unknown result type (might be due to invalid IL or missing references)
//IL_001f: Unknown result type (might be due to invalid IL or missing references)
//IL_0030: Unknown result type (might be due to invalid IL or missing references)
//IL_0035: Unknown result type (might be due to invalid IL or missing references)
//IL_003f: Unknown result type (might be due to invalid IL or missing references)
//IL_0044: Unknown result type (might be due to invalid IL or missing references)
//IL_009e: Unknown result type (might be due to invalid IL or missing references)
//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
//IL_00af: Unknown result type (might be due to invalid IL or missing references)
//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
//IL_00be: Expected O, but got Unknown
//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
//IL_00ed: Unknown result type (might be due to invalid IL or missing references)
//IL_00f2: Unknown result type (might be due to invalid IL or missing references)
//IL_00f9: Unknown result type (might be due to invalid IL or missing references)
//IL_0104: Unknown result type (might be due to invalid IL or missing references)
//IL_0110: Expected O, but got Unknown
//IL_0172: Unknown result type (might be due to invalid IL or missing references)
//IL_016a: Unknown result type (might be due to invalid IL or missing references)
//IL_0186: Unknown result type (might be due to invalid IL or missing references)
//IL_020a: Unknown result type (might be due to invalid IL or missing references)
//IL_020f: Unknown result type (might be due to invalid IL or missing references)
//IL_0211: Unknown result type (might be due to invalid IL or missing references)
//IL_021b: Unknown result type (might be due to invalid IL or missing references)
//IL_0222: Unknown result type (might be due to invalid IL or missing references)
//IL_022b: Expected O, but got Unknown
//IL_0270: Unknown result type (might be due to invalid IL or missing references)
//IL_0275: Unknown result type (might be due to invalid IL or missing references)
//IL_0278: Unknown result type (might be due to invalid IL or missing references)
SKRect bounds;
SKRect val = default(SKRect);
if (TabBarOnBottom)
{
bounds = base.Bounds;
float left = ((SKRect)(ref bounds)).Left;
bounds = base.Bounds;
float num = ((SKRect)(ref bounds)).Bottom - TabBarHeight;
bounds = base.Bounds;
float right = ((SKRect)(ref bounds)).Right;
bounds = base.Bounds;
((SKRect)(ref val))._002Ector(left, num, right, ((SKRect)(ref bounds)).Bottom);
}
else
{
bounds = base.Bounds;
float left2 = ((SKRect)(ref bounds)).Left;
bounds = base.Bounds;
float top = ((SKRect)(ref bounds)).Top;
bounds = base.Bounds;
float right2 = ((SKRect)(ref bounds)).Right;
bounds = base.Bounds;
((SKRect)(ref val))._002Ector(left2, top, right2, ((SKRect)(ref bounds)).Top + TabBarHeight);
}
SKPaint val2 = new SKPaint
{
Color = TabBarBackgroundColor,
Style = (SKPaintStyle)0,
IsAntialias = true
};
try
{
canvas.DrawRect(val, val2);
if (_tabs.Count == 0)
{
return;
}
float num2 = ((SKRect)(ref val)).Width / (float)_tabs.Count;
SKPaint val3 = new SKPaint
{
IsAntialias = true,
TextSize = 14f,
Typeface = SKTypeface.Default
};
try
{
SKRect val4 = default(SKRect);
for (int i = 0; i < _tabs.Count; i++)
{
TabItem tabItem = _tabs[i];
((SKRect)(ref val4))._002Ector(((SKRect)(ref val)).Left + (float)i * num2, ((SKRect)(ref val)).Top, ((SKRect)(ref val)).Left + (float)(i + 1) * num2, ((SKRect)(ref val)).Bottom);
bool flag = i == _selectedIndex;
val3.Color = (flag ? SelectedTabColor : UnselectedTabColor);
val3.FakeBoldText = flag;
SKRect val5 = default(SKRect);
val3.MeasureText(tabItem.Title, ref val5);
float num3 = ((SKRect)(ref val4)).MidX - ((SKRect)(ref val5)).MidX;
float num4 = ((SKRect)(ref val4)).MidY - ((SKRect)(ref val5)).MidY;
canvas.DrawText(tabItem.Title, num3, num4, val3);
}
if (_selectedIndex >= 0 && _selectedIndex < _tabs.Count)
{
SKPaint val6 = new SKPaint
{
Color = IndicatorColor,
Style = (SKPaintStyle)0,
IsAntialias = true
};
try
{
float num5 = ((SKRect)(ref val)).Left + (float)_selectedIndex * num2;
float num6 = (TabBarOnBottom ? ((SKRect)(ref val)).Top : (((SKRect)(ref val)).Bottom - IndicatorHeight));
SKRect val7 = new SKRect(num5, num6, num5 + num2, num6 + IndicatorHeight);
canvas.DrawRect(val7, val6);
return;
}
finally
{
((IDisposable)val6)?.Dispose();
}
}
}
finally
{
((IDisposable)val3)?.Dispose();
}
}
finally
{
((IDisposable)val2)?.Dispose();
}
}
return availableSize;
}
public override SkiaView? HitTest(float x, float y)
{
//IL_0009: Unknown result type (might be due to invalid IL or missing references)
//IL_000e: Unknown result type (might be due to invalid IL or missing references)
//IL_006f: Unknown result type (might be due to invalid IL or missing references)
//IL_0074: Unknown result type (might be due to invalid IL or missing references)
//IL_007d: Unknown result type (might be due to invalid IL or missing references)
//IL_0082: Unknown result type (might be due to invalid IL or missing references)
//IL_008b: Unknown result type (might be due to invalid IL or missing references)
//IL_0090: Unknown result type (might be due to invalid IL or missing references)
//IL_0099: Unknown result type (might be due to invalid IL or missing references)
//IL_009e: Unknown result type (might be due to invalid IL or missing references)
//IL_0027: Unknown result type (might be due to invalid IL or missing references)
//IL_002c: Unknown result type (might be due to invalid IL or missing references)
//IL_0035: Unknown result type (might be due to invalid IL or missing references)
//IL_003a: Unknown result type (might be due to invalid IL or missing references)
//IL_004a: Unknown result type (might be due to invalid IL or missing references)
//IL_004f: Unknown result type (might be due to invalid IL or missing references)
//IL_0058: Unknown result type (might be due to invalid IL or missing references)
//IL_005d: Unknown result type (might be due to invalid IL or missing references)
if (base.IsVisible)
{
SKRect bounds = base.Bounds;
if (((SKRect)(ref bounds)).Contains(x, y))
{
SKRect val = default(SKRect);
if (TabBarOnBottom)
{
bounds = base.Bounds;
float left = ((SKRect)(ref bounds)).Left;
bounds = base.Bounds;
float num = ((SKRect)(ref bounds)).Bottom - TabBarHeight;
bounds = base.Bounds;
float right = ((SKRect)(ref bounds)).Right;
bounds = base.Bounds;
((SKRect)(ref val))._002Ector(left, num, right, ((SKRect)(ref bounds)).Bottom);
}
else
{
bounds = base.Bounds;
float left2 = ((SKRect)(ref bounds)).Left;
bounds = base.Bounds;
float top = ((SKRect)(ref bounds)).Top;
bounds = base.Bounds;
float right2 = ((SKRect)(ref bounds)).Right;
bounds = base.Bounds;
((SKRect)(ref val))._002Ector(left2, top, right2, ((SKRect)(ref bounds)).Top + TabBarHeight);
}
if (((SKRect)(ref val)).Contains(x, y))
{
return this;
}
if (_selectedIndex >= 0 && _selectedIndex < _tabs.Count)
{
SkiaView skiaView = _tabs[_selectedIndex].Content.HitTest(x, y);
if (skiaView != null)
{
return skiaView;
}
}
return this;
}
}
return null;
}
protected override SKRect ArrangeOverride(SKRect bounds)
{
// Calculate content bounds based on tab bar position
SKRect contentBounds;
if (TabBarOnBottom)
{
contentBounds = new SKRect(
bounds.Left,
bounds.Top,
bounds.Right,
bounds.Bottom - TabBarHeight);
}
else
{
contentBounds = new SKRect(
bounds.Left,
bounds.Top + TabBarHeight,
bounds.Right,
bounds.Bottom);
}
// Arrange each tab's content to fill the content area
foreach (var tab in _tabs)
{
tab.Content.Arrange(contentBounds);
}
return bounds;
}
protected override void OnDraw(SKCanvas canvas, SKRect bounds)
{
canvas.Save();
canvas.ClipRect(bounds);
// Draw tab bar background
DrawTabBar(canvas);
// Draw selected content
if (_selectedIndex >= 0 && _selectedIndex < _tabs.Count)
{
_tabs[_selectedIndex].Content.Draw(canvas);
}
canvas.Restore();
}
private void DrawTabBar(SKCanvas canvas)
{
// Calculate tab bar bounds
SKRect tabBarBounds;
if (TabBarOnBottom)
{
tabBarBounds = new SKRect(
Bounds.Left,
Bounds.Bottom - TabBarHeight,
Bounds.Right,
Bounds.Bottom);
}
else
{
tabBarBounds = new SKRect(
Bounds.Left,
Bounds.Top,
Bounds.Right,
Bounds.Top + TabBarHeight);
}
// Draw background
using var bgPaint = new SKPaint
{
Color = TabBarBackgroundColor,
Style = SKPaintStyle.Fill,
IsAntialias = true
};
canvas.DrawRect(tabBarBounds, bgPaint);
if (_tabs.Count == 0) return;
// Calculate tab width
float tabWidth = tabBarBounds.Width / _tabs.Count;
// Draw tabs
using var textPaint = new SKPaint
{
IsAntialias = true,
TextSize = 14f,
Typeface = SKTypeface.Default
};
for (int i = 0; i < _tabs.Count; i++)
{
var tab = _tabs[i];
var tabBounds = new SKRect(
tabBarBounds.Left + i * tabWidth,
tabBarBounds.Top,
tabBarBounds.Left + (i + 1) * tabWidth,
tabBarBounds.Bottom);
bool isSelected = i == _selectedIndex;
textPaint.Color = isSelected ? SelectedTabColor : UnselectedTabColor;
textPaint.FakeBoldText = isSelected;
// Draw tab title centered
var textBounds = new SKRect();
textPaint.MeasureText(tab.Title, ref textBounds);
float textX = tabBounds.MidX - textBounds.MidX;
float textY = tabBounds.MidY - textBounds.MidY;
canvas.DrawText(tab.Title, textX, textY, textPaint);
}
// Draw selection indicator
if (_selectedIndex >= 0 && _selectedIndex < _tabs.Count)
{
using var indicatorPaint = new SKPaint
{
Color = IndicatorColor,
Style = SKPaintStyle.Fill,
IsAntialias = true
};
float indicatorLeft = tabBarBounds.Left + _selectedIndex * tabWidth;
float indicatorTop = TabBarOnBottom
? tabBarBounds.Top
: tabBarBounds.Bottom - IndicatorHeight;
var indicatorRect = new SKRect(
indicatorLeft,
indicatorTop,
indicatorLeft + tabWidth,
indicatorTop + IndicatorHeight);
canvas.DrawRect(indicatorRect, indicatorPaint);
}
}
public override SkiaView? HitTest(float x, float y)
{
if (!IsVisible || !Bounds.Contains(x, y)) return null;
// Check if hit is in tab bar
SKRect tabBarBounds;
if (TabBarOnBottom)
{
tabBarBounds = new SKRect(
Bounds.Left,
Bounds.Bottom - TabBarHeight,
Bounds.Right,
Bounds.Bottom);
}
else
{
tabBarBounds = new SKRect(
Bounds.Left,
Bounds.Top,
Bounds.Right,
Bounds.Top + TabBarHeight);
}
if (tabBarBounds.Contains(x, y))
{
return this; // Tab bar handles its own hits
}
// Check selected content
if (_selectedIndex >= 0 && _selectedIndex < _tabs.Count)
{
var hit = _tabs[_selectedIndex].Content.HitTest(x, y);
if (hit != null) return hit;
}
return this;
}
public override void OnPointerPressed(PointerEventArgs e)
{
if (!IsEnabled) return;
// Check if click is in tab bar
SKRect tabBarBounds;
if (TabBarOnBottom)
{
tabBarBounds = new SKRect(
Bounds.Left,
Bounds.Bottom - TabBarHeight,
Bounds.Right,
Bounds.Bottom);
}
else
{
tabBarBounds = new SKRect(
Bounds.Left,
Bounds.Top,
Bounds.Right,
Bounds.Top + TabBarHeight);
}
if (tabBarBounds.Contains(e.X, e.Y) && _tabs.Count > 0)
{
// Calculate which tab was clicked
float tabWidth = tabBarBounds.Width / _tabs.Count;
int clickedIndex = (int)((e.X - tabBarBounds.Left) / tabWidth);
clickedIndex = Math.Clamp(clickedIndex, 0, _tabs.Count - 1);
SelectedIndex = clickedIndex;
e.Handled = true;
}
base.OnPointerPressed(e);
}
}
/// <summary>
/// Represents a tab item with title, icon, and content.
/// </summary>
public class TabItem
{
/// <summary>
/// The title displayed in the tab.
/// </summary>
public string Title { get; set; } = string.Empty;
/// <summary>
/// Optional icon path for the tab.
/// </summary>
public string? IconPath { get; set; }
/// <summary>
/// The content view displayed when this tab is selected.
/// </summary>
public SkiaView Content { get; set; } = null!;
/// <summary>
/// Optional badge text to display on the tab.
/// </summary>
public string? Badge { get; set; }
public override void OnPointerPressed(PointerEventArgs e)
{
//IL_005c: Unknown result type (might be due to invalid IL or missing references)
//IL_0061: Unknown result type (might be due to invalid IL or missing references)
//IL_006a: Unknown result type (might be due to invalid IL or missing references)
//IL_006f: Unknown result type (might be due to invalid IL or missing references)
//IL_0078: Unknown result type (might be due to invalid IL or missing references)
//IL_007d: Unknown result type (might be due to invalid IL or missing references)
//IL_0086: Unknown result type (might be due to invalid IL or missing references)
//IL_008b: Unknown result type (might be due to invalid IL or missing references)
//IL_0014: Unknown result type (might be due to invalid IL or missing references)
//IL_0019: Unknown result type (might be due to invalid IL or missing references)
//IL_0022: Unknown result type (might be due to invalid IL or missing references)
//IL_0027: Unknown result type (might be due to invalid IL or missing references)
//IL_0037: Unknown result type (might be due to invalid IL or missing references)
//IL_003c: Unknown result type (might be due to invalid IL or missing references)
//IL_0045: Unknown result type (might be due to invalid IL or missing references)
//IL_004a: Unknown result type (might be due to invalid IL or missing references)
if (base.IsEnabled)
{
SKRect bounds;
SKRect val = default(SKRect);
if (TabBarOnBottom)
{
bounds = base.Bounds;
float left = ((SKRect)(ref bounds)).Left;
bounds = base.Bounds;
float num = ((SKRect)(ref bounds)).Bottom - TabBarHeight;
bounds = base.Bounds;
float right = ((SKRect)(ref bounds)).Right;
bounds = base.Bounds;
((SKRect)(ref val))._002Ector(left, num, right, ((SKRect)(ref bounds)).Bottom);
}
else
{
bounds = base.Bounds;
float left2 = ((SKRect)(ref bounds)).Left;
bounds = base.Bounds;
float top = ((SKRect)(ref bounds)).Top;
bounds = base.Bounds;
float right2 = ((SKRect)(ref bounds)).Right;
bounds = base.Bounds;
((SKRect)(ref val))._002Ector(left2, top, right2, ((SKRect)(ref bounds)).Top + TabBarHeight);
}
if (((SKRect)(ref val)).Contains(e.X, e.Y) && _tabs.Count > 0)
{
float num2 = ((SKRect)(ref val)).Width / (float)_tabs.Count;
int value = (int)((e.X - ((SKRect)(ref val)).Left) / num2);
value = Math.Clamp(value, 0, _tabs.Count - 1);
SelectedIndex = value;
e.Handled = true;
}
base.OnPointerPressed(e);
}
}
}

View File

@@ -1,367 +1,413 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System;
using Microsoft.Maui.Controls;
using Microsoft.Maui.Controls.Shapes;
using Microsoft.Maui.Graphics;
using SkiaSharp;
namespace Microsoft.Maui.Platform;
/// <summary>
/// Base class for Skia controls that support ControlTemplates.
/// Provides infrastructure for completely redefining control appearance via XAML.
/// </summary>
public abstract class SkiaTemplatedView : SkiaView
{
private SkiaView? _templateRoot;
private bool _templateApplied;
private SkiaView? _templateRoot;
#region BindableProperties
private bool _templateApplied;
public static readonly BindableProperty ControlTemplateProperty =
BindableProperty.Create(nameof(ControlTemplate), typeof(ControlTemplate), typeof(SkiaTemplatedView), null,
propertyChanged: OnControlTemplateChanged);
public static readonly BindableProperty ControlTemplateProperty = BindableProperty.Create("ControlTemplate", typeof(ControlTemplate), typeof(SkiaTemplatedView), (object)null, (BindingMode)2, (ValidateValueDelegate)null, new BindingPropertyChangedDelegate(OnControlTemplateChanged), (BindingPropertyChangingDelegate)null, (CoerceValueDelegate)null, (CreateDefaultValueDelegate)null);
#endregion
public ControlTemplate? ControlTemplate
{
get
{
//IL_000b: Unknown result type (might be due to invalid IL or missing references)
//IL_0011: Expected O, but got Unknown
return (ControlTemplate)((BindableObject)this).GetValue(ControlTemplateProperty);
}
set
{
((BindableObject)this).SetValue(ControlTemplateProperty, (object)value);
}
}
#region Properties
protected SkiaView? TemplateRoot => _templateRoot;
/// <summary>
/// Gets or sets the control template that defines the visual appearance.
/// </summary>
public ControlTemplate? ControlTemplate
{
get => (ControlTemplate?)GetValue(ControlTemplateProperty);
set => SetValue(ControlTemplateProperty, value);
}
protected bool IsTemplateApplied => _templateApplied;
/// <summary>
/// Gets the root element created from the ControlTemplate.
/// </summary>
protected SkiaView? TemplateRoot => _templateRoot;
private static void OnControlTemplateChanged(BindableObject bindable, object oldValue, object newValue)
{
//IL_000c: Unknown result type (might be due to invalid IL or missing references)
//IL_0012: Unknown result type (might be due to invalid IL or missing references)
//IL_001c: Expected O, but got Unknown
//IL_001c: Expected O, but got Unknown
if (bindable is SkiaTemplatedView skiaTemplatedView)
{
skiaTemplatedView.OnControlTemplateChanged((ControlTemplate)oldValue, (ControlTemplate)newValue);
}
}
/// <summary>
/// Gets a value indicating whether a template has been applied.
/// </summary>
protected bool IsTemplateApplied => _templateApplied;
protected virtual void OnControlTemplateChanged(ControlTemplate? oldTemplate, ControlTemplate? newTemplate)
{
_templateApplied = false;
_templateRoot = null;
if (newTemplate != null)
{
ApplyTemplate();
}
InvalidateMeasure();
}
#endregion
protected virtual void ApplyTemplate()
{
if (ControlTemplate == null || _templateApplied)
{
return;
}
try
{
object obj = ((ElementTemplate)ControlTemplate).CreateContent();
Element val = (Element)((obj is Element) ? obj : null);
if (val != null)
{
_templateRoot = ConvertElementToSkiaView(val);
}
else if (obj is SkiaView templateRoot)
{
_templateRoot = templateRoot;
}
if (_templateRoot != null)
{
_templateRoot.Parent = this;
OnTemplateApplied();
}
_templateApplied = true;
}
catch (Exception)
{
}
}
private static void OnControlTemplateChanged(BindableObject bindable, object oldValue, object newValue)
{
if (bindable is SkiaTemplatedView view)
{
view.OnControlTemplateChanged((ControlTemplate?)oldValue, (ControlTemplate?)newValue);
}
}
protected virtual void OnTemplateApplied()
{
SkiaContentPresenter skiaContentPresenter = FindTemplateChild<SkiaContentPresenter>("PART_ContentPresenter");
if (skiaContentPresenter != null)
{
OnContentPresenterFound(skiaContentPresenter);
}
}
/// <summary>
/// Called when the ControlTemplate changes.
/// </summary>
protected virtual void OnControlTemplateChanged(ControlTemplate? oldTemplate, ControlTemplate? newTemplate)
{
_templateApplied = false;
_templateRoot = null;
protected virtual void OnContentPresenterFound(SkiaContentPresenter presenter)
{
}
if (newTemplate != null)
{
ApplyTemplate();
}
protected T? FindTemplateChild<T>(string name) where T : SkiaView
{
if (_templateRoot == null)
{
return null;
}
return FindChild<T>(_templateRoot, name);
}
InvalidateMeasure();
}
private static T? FindChild<T>(SkiaView root, string name) where T : SkiaView
{
if (root is T result && root.Name == name)
{
return result;
}
if (root is SkiaLayoutView skiaLayoutView)
{
foreach (SkiaView child in skiaLayoutView.Children)
{
T val = FindChild<T>(child, name);
if (val != null)
{
return val;
}
}
}
else if (root is SkiaContentPresenter { Content: not null } skiaContentPresenter)
{
return FindChild<T>(skiaContentPresenter.Content, name);
}
return null;
}
/// <summary>
/// Applies the current ControlTemplate if one is set.
/// </summary>
protected virtual void ApplyTemplate()
{
if (ControlTemplate == null || _templateApplied)
return;
protected virtual SkiaView? ConvertElementToSkiaView(Element element)
{
//IL_008d: Unknown result type (might be due to invalid IL or missing references)
StackLayout val = (StackLayout)(object)((element is StackLayout) ? element : null);
if (val == null)
{
Grid val2 = (Grid)(object)((element is Grid) ? element : null);
if (val2 == null)
{
Border val3 = (Border)(object)((element is Border) ? element : null);
if (val3 == null)
{
Label val4 = (Label)(object)((element is Label) ? element : null);
if (val4 == null)
{
if (element is ContentPresenter)
{
return new SkiaContentPresenter();
}
return new SkiaLabel
{
Text = "[" + ((object)element).GetType().Name + "]",
TextColor = SKColors.Gray
};
}
return CreateSkiaLabel(val4);
}
return CreateSkiaBorder(val3);
}
return CreateSkiaGrid(val2);
}
return CreateSkiaStackLayout(val);
}
try
{
// Create content from template
var content = ControlTemplate.CreateContent();
private SkiaStackLayout CreateSkiaStackLayout(StackLayout sl)
{
//IL_0007: Unknown result type (might be due to invalid IL or missing references)
SkiaStackLayout skiaStackLayout = new SkiaStackLayout
{
Orientation = (((int)sl.Orientation != 0) ? StackOrientation.Horizontal : StackOrientation.Vertical),
Spacing = (float)((StackBase)sl).Spacing
};
foreach (IView child in ((Layout)sl).Children)
{
Element val = (Element)(object)((child is Element) ? child : null);
if (val != null)
{
SkiaView skiaView = ConvertElementToSkiaView(val);
if (skiaView != null)
{
skiaStackLayout.AddChild(skiaView);
}
}
}
return skiaStackLayout;
}
// If the content is a MAUI Element, try to convert it to a SkiaView
if (content is Element element)
{
_templateRoot = ConvertElementToSkiaView(element);
}
else if (content is SkiaView skiaView)
{
_templateRoot = skiaView;
}
private SkiaGrid CreateSkiaGrid(Grid grid)
{
//IL_001c: Unknown result type (might be due to invalid IL or missing references)
//IL_0021: Unknown result type (might be due to invalid IL or missing references)
//IL_002d: Unknown result type (might be due to invalid IL or missing references)
//IL_0032: Unknown result type (might be due to invalid IL or missing references)
//IL_0056: Unknown result type (might be due to invalid IL or missing references)
//IL_005b: Unknown result type (might be due to invalid IL or missing references)
//IL_003e: Unknown result type (might be due to invalid IL or missing references)
//IL_0043: Unknown result type (might be due to invalid IL or missing references)
//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
//IL_00ea: Unknown result type (might be due to invalid IL or missing references)
//IL_00ef: Unknown result type (might be due to invalid IL or missing references)
//IL_00d1: Unknown result type (might be due to invalid IL or missing references)
//IL_00d6: Unknown result type (might be due to invalid IL or missing references)
//IL_0161: Unknown result type (might be due to invalid IL or missing references)
//IL_016b: Expected O, but got Unknown
//IL_016f: Unknown result type (might be due to invalid IL or missing references)
//IL_0179: Expected O, but got Unknown
//IL_017d: Unknown result type (might be due to invalid IL or missing references)
//IL_0187: Expected O, but got Unknown
//IL_018b: Unknown result type (might be due to invalid IL or missing references)
//IL_0195: Expected O, but got Unknown
SkiaGrid skiaGrid = new SkiaGrid();
GridLength val;
foreach (RowDefinition item3 in (DefinitionCollection<RowDefinition>)(object)grid.RowDefinitions)
{
val = item3.Height;
GridLength gridLength;
if (!((GridLength)(ref val)).IsAuto)
{
val = item3.Height;
if (!((GridLength)(ref val)).IsStar)
{
val = item3.Height;
gridLength = new GridLength((float)((GridLength)(ref val)).Value);
}
else
{
val = item3.Height;
gridLength = new GridLength((float)((GridLength)(ref val)).Value, GridUnitType.Star);
}
}
else
{
gridLength = GridLength.Auto;
}
GridLength item = gridLength;
skiaGrid.RowDefinitions.Add(item);
}
foreach (ColumnDefinition item4 in (DefinitionCollection<ColumnDefinition>)(object)grid.ColumnDefinitions)
{
val = item4.Width;
GridLength gridLength2;
if (!((GridLength)(ref val)).IsAuto)
{
val = item4.Width;
if (!((GridLength)(ref val)).IsStar)
{
val = item4.Width;
gridLength2 = new GridLength((float)((GridLength)(ref val)).Value);
}
else
{
val = item4.Width;
gridLength2 = new GridLength((float)((GridLength)(ref val)).Value, GridUnitType.Star);
}
}
else
{
gridLength2 = GridLength.Auto;
}
GridLength item2 = gridLength2;
skiaGrid.ColumnDefinitions.Add(item2);
}
foreach (IView child in ((Layout)grid).Children)
{
Element val2 = (Element)(object)((child is Element) ? child : null);
if (val2 != null)
{
SkiaView skiaView = ConvertElementToSkiaView(val2);
if (skiaView != null)
{
int row = Grid.GetRow((BindableObject)child);
int column = Grid.GetColumn((BindableObject)child);
int rowSpan = Grid.GetRowSpan((BindableObject)child);
int columnSpan = Grid.GetColumnSpan((BindableObject)child);
skiaGrid.AddChild(skiaView, row, column, rowSpan, columnSpan);
}
}
}
return skiaGrid;
}
if (_templateRoot != null)
{
_templateRoot.Parent = this;
OnTemplateApplied();
}
private SkiaBorder CreateSkiaBorder(Border border)
{
//IL_0016: Unknown result type (might be due to invalid IL or missing references)
//IL_001b: Unknown result type (might be due to invalid IL or missing references)
//IL_0056: Unknown result type (might be due to invalid IL or missing references)
//IL_0079: Unknown result type (might be due to invalid IL or missing references)
float cornerRadius = 0f;
IShape strokeShape = border.StrokeShape;
RoundRectangle val = (RoundRectangle)(object)((strokeShape is RoundRectangle) ? strokeShape : null);
if (val != null)
{
CornerRadius cornerRadius2 = val.CornerRadius;
cornerRadius = (float)((CornerRadius)(ref cornerRadius2)).TopLeft;
}
SkiaBorder skiaBorder = new SkiaBorder
{
CornerRadius = cornerRadius,
StrokeThickness = (float)border.StrokeThickness
};
Brush stroke = border.Stroke;
SolidColorBrush val2 = (SolidColorBrush)(object)((stroke is SolidColorBrush) ? stroke : null);
if (val2 != null)
{
skiaBorder.Stroke = val2.Color.ToSKColor();
}
Brush background = ((VisualElement)border).Background;
SolidColorBrush val3 = (SolidColorBrush)(object)((background is SolidColorBrush) ? background : null);
if (val3 != null)
{
skiaBorder.BackgroundColor = val3.Color.ToSKColor();
}
Element content = (Element)(object)border.Content;
if (content != null)
{
SkiaView skiaView = ConvertElementToSkiaView(content);
if (skiaView != null)
{
skiaBorder.AddChild(skiaView);
}
}
return skiaBorder;
}
_templateApplied = true;
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine($"Error applying template: {ex.Message}");
}
}
private SkiaLabel CreateSkiaLabel(Label label)
{
//IL_0037: Unknown result type (might be due to invalid IL or missing references)
SkiaLabel skiaLabel = new SkiaLabel
{
Text = (label.Text ?? ""),
FontSize = (float)label.FontSize
};
if (label.TextColor != null)
{
skiaLabel.TextColor = label.TextColor.ToSKColor();
}
return skiaLabel;
}
/// <summary>
/// Called after a template has been successfully applied.
/// Override to perform template-specific initialization.
/// </summary>
protected virtual void OnTemplateApplied()
{
// Find and bind ContentPresenter if present
var presenter = FindTemplateChild<SkiaContentPresenter>("PART_ContentPresenter");
if (presenter != null)
{
OnContentPresenterFound(presenter);
}
}
protected override void OnDraw(SKCanvas canvas, SKRect bounds)
{
//IL_001f: Unknown result type (might be due to invalid IL or missing references)
if (_templateRoot != null && _templateApplied)
{
_templateRoot.Draw(canvas);
}
else
{
DrawDefaultAppearance(canvas, bounds);
}
}
/// <summary>
/// Called when a ContentPresenter is found in the template.
/// Override to set up the content binding.
/// </summary>
protected virtual void OnContentPresenterFound(SkiaContentPresenter presenter)
{
// Derived classes should override to bind their content
}
protected abstract void DrawDefaultAppearance(SKCanvas canvas, SKRect bounds);
/// <summary>
/// Finds a named element in the template tree.
/// </summary>
protected T? FindTemplateChild<T>(string name) where T : SkiaView
{
if (_templateRoot == null)
return null;
protected override SKSize MeasureOverride(SKSize availableSize)
{
//IL_001e: Unknown result type (might be due to invalid IL or missing references)
//IL_001f: Unknown result type (might be due to invalid IL or missing references)
//IL_0016: Unknown result type (might be due to invalid IL or missing references)
//IL_0017: Unknown result type (might be due to invalid IL or missing references)
if (_templateRoot != null && _templateApplied)
{
return _templateRoot.Measure(availableSize);
}
return MeasureDefaultAppearance(availableSize);
}
return FindChild<T>(_templateRoot, name);
}
protected virtual SKSize MeasureDefaultAppearance(SKSize availableSize)
{
//IL_000a: Unknown result type (might be due to invalid IL or missing references)
return new SKSize(100f, 40f);
}
private static T? FindChild<T>(SkiaView root, string name) where T : SkiaView
{
if (root is T typed && root.Name == name)
return typed;
public new void Arrange(SKRect bounds)
{
//IL_0001: Unknown result type (might be due to invalid IL or missing references)
//IL_001d: Unknown result type (might be due to invalid IL or missing references)
base.Arrange(bounds);
if (_templateRoot != null && _templateApplied)
{
_templateRoot.Arrange(bounds);
}
}
if (root is SkiaLayoutView layout)
{
foreach (var child in layout.Children)
{
var found = FindChild<T>(child, name);
if (found != null)
return found;
}
}
else if (root is SkiaContentPresenter presenter && presenter.Content != null)
{
return FindChild<T>(presenter.Content, name);
}
return null;
}
/// <summary>
/// Converts a MAUI Element to a SkiaView.
/// Override to provide custom conversion logic.
/// </summary>
protected virtual SkiaView? ConvertElementToSkiaView(Element element)
{
// This is a simplified conversion - in a full implementation,
// you would use the handler system to create proper platform views
return element switch
{
// Handle common layout types
Microsoft.Maui.Controls.StackLayout sl => CreateSkiaStackLayout(sl),
Microsoft.Maui.Controls.Grid grid => CreateSkiaGrid(grid),
Microsoft.Maui.Controls.Border border => CreateSkiaBorder(border),
Microsoft.Maui.Controls.Label label => CreateSkiaLabel(label),
Microsoft.Maui.Controls.ContentPresenter cp => new SkiaContentPresenter(),
_ => new SkiaLabel { Text = $"[{element.GetType().Name}]", TextColor = SKColors.Gray }
};
}
private SkiaStackLayout CreateSkiaStackLayout(Microsoft.Maui.Controls.StackLayout sl)
{
var layout = new SkiaStackLayout
{
Orientation = sl.Orientation == Microsoft.Maui.Controls.StackOrientation.Vertical
? StackOrientation.Vertical
: StackOrientation.Horizontal,
Spacing = (float)sl.Spacing
};
foreach (var child in sl.Children)
{
if (child is Element element)
{
var skiaChild = ConvertElementToSkiaView(element);
if (skiaChild != null)
layout.AddChild(skiaChild);
}
}
return layout;
}
private SkiaGrid CreateSkiaGrid(Microsoft.Maui.Controls.Grid grid)
{
var layout = new SkiaGrid();
// Set row definitions
foreach (var rowDef in grid.RowDefinitions)
{
var gridLength = rowDef.Height.IsAuto ? GridLength.Auto :
rowDef.Height.IsStar ? new GridLength((float)rowDef.Height.Value, GridUnitType.Star) :
new GridLength((float)rowDef.Height.Value, GridUnitType.Absolute);
layout.RowDefinitions.Add(gridLength);
}
// Set column definitions
foreach (var colDef in grid.ColumnDefinitions)
{
var gridLength = colDef.Width.IsAuto ? GridLength.Auto :
colDef.Width.IsStar ? new GridLength((float)colDef.Width.Value, GridUnitType.Star) :
new GridLength((float)colDef.Width.Value, GridUnitType.Absolute);
layout.ColumnDefinitions.Add(gridLength);
}
// Add children
foreach (var child in grid.Children)
{
if (child is Element element)
{
var skiaChild = ConvertElementToSkiaView(element);
if (skiaChild != null)
{
var row = Microsoft.Maui.Controls.Grid.GetRow((BindableObject)child);
var col = Microsoft.Maui.Controls.Grid.GetColumn((BindableObject)child);
var rowSpan = Microsoft.Maui.Controls.Grid.GetRowSpan((BindableObject)child);
var colSpan = Microsoft.Maui.Controls.Grid.GetColumnSpan((BindableObject)child);
layout.AddChild(skiaChild, row, col, rowSpan, colSpan);
}
}
}
return layout;
}
private SkiaBorder CreateSkiaBorder(Microsoft.Maui.Controls.Border border)
{
float cornerRadius = 0;
if (border.StrokeShape is Microsoft.Maui.Controls.Shapes.RoundRectangle rr)
{
cornerRadius = (float)rr.CornerRadius.TopLeft;
}
var skiaBorder = new SkiaBorder
{
CornerRadius = cornerRadius,
StrokeThickness = (float)border.StrokeThickness
};
if (border.Stroke is SolidColorBrush strokeBrush)
{
skiaBorder.Stroke = strokeBrush.Color.ToSKColor();
}
if (border.Background is SolidColorBrush bgBrush)
{
skiaBorder.BackgroundColor = bgBrush.Color.ToSKColor();
}
if (border.Content is Element content)
{
var skiaContent = ConvertElementToSkiaView(content);
if (skiaContent != null)
skiaBorder.AddChild(skiaContent);
}
return skiaBorder;
}
private SkiaLabel CreateSkiaLabel(Microsoft.Maui.Controls.Label label)
{
var skiaLabel = new SkiaLabel
{
Text = label.Text ?? "",
FontSize = (float)label.FontSize
};
if (label.TextColor != null)
{
skiaLabel.TextColor = label.TextColor.ToSKColor();
}
return skiaLabel;
}
protected override void OnDraw(SKCanvas canvas, SKRect bounds)
{
if (_templateRoot != null && _templateApplied)
{
// Render the template
_templateRoot.Draw(canvas);
}
else
{
// Render default appearance
DrawDefaultAppearance(canvas, bounds);
}
}
/// <summary>
/// Draws the default appearance when no template is applied.
/// Override in derived classes to provide default rendering.
/// </summary>
protected abstract void DrawDefaultAppearance(SKCanvas canvas, SKRect bounds);
protected override SKSize MeasureOverride(SKSize availableSize)
{
if (_templateRoot != null && _templateApplied)
{
return _templateRoot.Measure(availableSize);
}
return MeasureDefaultAppearance(availableSize);
}
/// <summary>
/// Measures the default appearance when no template is applied.
/// Override in derived classes.
/// </summary>
protected virtual SKSize MeasureDefaultAppearance(SKSize availableSize)
{
return new SKSize(100, 40);
}
public new void Arrange(SKRect bounds)
{
base.Arrange(bounds);
if (_templateRoot != null && _templateApplied)
{
_templateRoot.Arrange(bounds);
}
}
public override SkiaView? HitTest(float x, float y)
{
if (!IsVisible || !Bounds.Contains(x, y))
return null;
if (_templateRoot != null && _templateApplied)
{
var hit = _templateRoot.HitTest(x, y);
if (hit != null)
return hit;
}
return this;
}
public override SkiaView? HitTest(float x, float y)
{
//IL_0009: Unknown result type (might be due to invalid IL or missing references)
//IL_000e: Unknown result type (might be due to invalid IL or missing references)
if (base.IsVisible)
{
SKRect bounds = base.Bounds;
if (((SKRect)(ref bounds)).Contains(x, y))
{
if (_templateRoot != null && _templateApplied)
{
SkiaView skiaView = _templateRoot.HitTest(x, y);
if (skiaView != null)
{
return skiaView;
}
}
return this;
}
}
return null;
}
}

View File

@@ -0,0 +1,8 @@
namespace Microsoft.Maui.Platform;
public enum SkiaTextAlignment
{
Left,
Center,
Right
}

28
Views/SkiaTextSpan.cs Normal file
View File

@@ -0,0 +1,28 @@
using SkiaSharp;
namespace Microsoft.Maui.Platform;
public class SkiaTextSpan
{
public string Text { get; set; } = "";
public SKColor? TextColor { get; set; }
public SKColor? BackgroundColor { get; set; }
public string? FontFamily { get; set; }
public float FontSize { get; set; }
public bool IsBold { get; set; }
public bool IsItalic { get; set; }
public bool IsUnderline { get; set; }
public bool IsStrikethrough { get; set; }
public float CharacterSpacing { get; set; }
public float LineHeight { get; set; } = 1f;
}

View File

File diff suppressed because it is too large Load Diff

17
Views/SkiaToolbarItem.cs Normal file
View File

@@ -0,0 +1,17 @@
using System.Windows.Input;
using SkiaSharp;
namespace Microsoft.Maui.Platform;
public class SkiaToolbarItem
{
public string Text { get; set; } = "";
public SKBitmap? Icon { get; set; }
public SkiaToolbarItemOrder Order { get; set; }
public ICommand? Command { get; set; }
public SKRect HitBounds { get; set; }
}

View File

@@ -0,0 +1,7 @@
namespace Microsoft.Maui.Platform;
public enum SkiaToolbarItemOrder
{
Primary,
Secondary
}

View File

@@ -0,0 +1,8 @@
namespace Microsoft.Maui.Platform;
public enum SkiaVerticalAlignment
{
Top,
Center,
Bottom
}

View File

File diff suppressed because it is too large Load Diff

10
Views/SkiaVisualState.cs Normal file
View File

@@ -0,0 +1,10 @@
using System.Collections.Generic;
namespace Microsoft.Maui.Platform;
public class SkiaVisualState
{
public string Name { get; set; } = "";
public List<SkiaVisualStateSetter> Setters { get; } = new List<SkiaVisualStateSetter>();
}

View File

@@ -0,0 +1,12 @@
using System.Collections.Generic;
namespace Microsoft.Maui.Platform;
public class SkiaVisualStateGroup
{
public string Name { get; set; } = "";
public List<SkiaVisualState> States { get; } = new List<SkiaVisualState>();
public SkiaVisualState? CurrentState { get; set; }
}

View File

@@ -0,0 +1,7 @@
using System.Collections.Generic;
namespace Microsoft.Maui.Platform;
public class SkiaVisualStateGroupList : List<SkiaVisualStateGroup>
{
}

View File

@@ -1,216 +1,98 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using Microsoft.Maui.Controls;
namespace Microsoft.Maui.Platform;
/// <summary>
/// Visual State Manager for Skia-rendered controls.
/// Provides state-based styling through XAML VisualStateGroups.
/// </summary>
public static class SkiaVisualStateManager
{
/// <summary>
/// Common visual state names.
/// </summary>
public static class CommonStates
{
public const string Normal = "Normal";
public const string Disabled = "Disabled";
public const string Focused = "Focused";
public const string PointerOver = "PointerOver";
public const string Pressed = "Pressed";
public const string Selected = "Selected";
public const string Checked = "Checked";
public const string Unchecked = "Unchecked";
public const string On = "On";
public const string Off = "Off";
}
public static class CommonStates
{
public const string Normal = "Normal";
/// <summary>
/// Attached property for VisualStateGroups.
/// </summary>
public static readonly BindableProperty VisualStateGroupsProperty =
BindableProperty.CreateAttached(
"VisualStateGroups",
typeof(SkiaVisualStateGroupList),
typeof(SkiaVisualStateManager),
null,
propertyChanged: OnVisualStateGroupsChanged);
public const string Disabled = "Disabled";
/// <summary>
/// Gets the visual state groups for the specified view.
/// </summary>
public static SkiaVisualStateGroupList? GetVisualStateGroups(SkiaView view)
{
return (SkiaVisualStateGroupList?)view.GetValue(VisualStateGroupsProperty);
}
public const string Focused = "Focused";
/// <summary>
/// Sets the visual state groups for the specified view.
/// </summary>
public static void SetVisualStateGroups(SkiaView view, SkiaVisualStateGroupList? value)
{
view.SetValue(VisualStateGroupsProperty, value);
}
public const string PointerOver = "PointerOver";
private static void OnVisualStateGroupsChanged(BindableObject bindable, object? oldValue, object? newValue)
{
if (bindable is SkiaView view && newValue is SkiaVisualStateGroupList groups)
{
// Initialize to default state
GoToState(view, CommonStates.Normal);
}
}
public const string Pressed = "Pressed";
/// <summary>
/// Transitions the view to the specified visual state.
/// </summary>
/// <param name="view">The view to transition.</param>
/// <param name="stateName">The name of the state to transition to.</param>
/// <returns>True if the state was found and applied, false otherwise.</returns>
public static bool GoToState(SkiaView view, string stateName)
{
var groups = GetVisualStateGroups(view);
if (groups == null || groups.Count == 0)
return false;
public const string Selected = "Selected";
bool stateFound = false;
public const string Checked = "Checked";
foreach (var group in groups)
{
// Find the state in this group
SkiaVisualState? targetState = null;
foreach (var state in group.States)
{
if (state.Name == stateName)
{
targetState = state;
break;
}
}
public const string Unchecked = "Unchecked";
if (targetState != null)
{
// Unapply current state if different
if (group.CurrentState != null && group.CurrentState != targetState)
{
UnapplyState(view, group.CurrentState);
}
public const string On = "On";
// Apply new state
ApplyState(view, targetState);
group.CurrentState = targetState;
stateFound = true;
}
}
public const string Off = "Off";
}
return stateFound;
}
public static readonly BindableProperty VisualStateGroupsProperty = BindableProperty.CreateAttached("VisualStateGroups", typeof(SkiaVisualStateGroupList), typeof(SkiaVisualStateManager), (object)null, (BindingMode)2, (ValidateValueDelegate)null, new BindingPropertyChangedDelegate(OnVisualStateGroupsChanged), (BindingPropertyChangingDelegate)null, (CoerceValueDelegate)null, (CreateDefaultValueDelegate)null);
private static void ApplyState(SkiaView view, SkiaVisualState state)
{
foreach (var setter in state.Setters)
{
setter.Apply(view);
}
}
public static SkiaVisualStateGroupList? GetVisualStateGroups(SkiaView view)
{
return (SkiaVisualStateGroupList)((BindableObject)view).GetValue(VisualStateGroupsProperty);
}
private static void UnapplyState(SkiaView view, SkiaVisualState state)
{
foreach (var setter in state.Setters)
{
setter.Unapply(view);
}
}
}
/// <summary>
/// A list of visual state groups.
/// </summary>
public class SkiaVisualStateGroupList : List<SkiaVisualStateGroup>
{
}
/// <summary>
/// A group of mutually exclusive visual states.
/// </summary>
public class SkiaVisualStateGroup
{
/// <summary>
/// Gets or sets the name of this group.
/// </summary>
public string Name { get; set; } = "";
/// <summary>
/// Gets the collection of states in this group.
/// </summary>
public List<SkiaVisualState> States { get; } = new();
/// <summary>
/// Gets or sets the currently active state.
/// </summary>
public SkiaVisualState? CurrentState { get; set; }
}
/// <summary>
/// Represents a single visual state with its setters.
/// </summary>
public class SkiaVisualState
{
/// <summary>
/// Gets or sets the name of this state.
/// </summary>
public string Name { get; set; } = "";
/// <summary>
/// Gets the collection of setters for this state.
/// </summary>
public List<SkiaVisualStateSetter> Setters { get; } = new();
}
/// <summary>
/// Sets a property value when a visual state is active.
/// </summary>
public class SkiaVisualStateSetter
{
/// <summary>
/// Gets or sets the property to set.
/// </summary>
public BindableProperty? Property { get; set; }
/// <summary>
/// Gets or sets the value to set.
/// </summary>
public object? Value { get; set; }
// Store original value for unapply
private object? _originalValue;
private bool _hasOriginalValue;
/// <summary>
/// Applies this setter to the target view.
/// </summary>
public void Apply(SkiaView view)
{
if (Property == null) return;
// Store original value if not already stored
if (!_hasOriginalValue)
{
_originalValue = view.GetValue(Property);
_hasOriginalValue = true;
}
view.SetValue(Property, Value);
}
/// <summary>
/// Unapplies this setter, restoring the original value.
/// </summary>
public void Unapply(SkiaView view)
{
if (Property == null || !_hasOriginalValue) return;
view.SetValue(Property, _originalValue);
}
public static void SetVisualStateGroups(SkiaView view, SkiaVisualStateGroupList? value)
{
((BindableObject)view).SetValue(VisualStateGroupsProperty, (object)value);
}
private static void OnVisualStateGroupsChanged(BindableObject bindable, object? oldValue, object? newValue)
{
if (bindable is SkiaView view && newValue is SkiaVisualStateGroupList)
{
GoToState(view, "Normal");
}
}
public static bool GoToState(SkiaView view, string stateName)
{
SkiaVisualStateGroupList visualStateGroups = GetVisualStateGroups(view);
if (visualStateGroups == null || visualStateGroups.Count == 0)
{
return false;
}
bool result = false;
foreach (SkiaVisualStateGroup item in visualStateGroups)
{
SkiaVisualState skiaVisualState = null;
foreach (SkiaVisualState state in item.States)
{
if (state.Name == stateName)
{
skiaVisualState = state;
break;
}
}
if (skiaVisualState != null)
{
if (item.CurrentState != null && item.CurrentState != skiaVisualState)
{
UnapplyState(view, item.CurrentState);
}
ApplyState(view, skiaVisualState);
item.CurrentState = skiaVisualState;
result = true;
}
}
return result;
}
private static void ApplyState(SkiaView view, SkiaVisualState state)
{
foreach (SkiaVisualStateSetter setter in state.Setters)
{
setter.Apply(view);
}
}
private static void UnapplyState(SkiaView view, SkiaVisualState state)
{
foreach (SkiaVisualStateSetter setter in state.Setters)
{
setter.Unapply(view);
}
}
}

View File

@@ -0,0 +1,35 @@
using Microsoft.Maui.Controls;
namespace Microsoft.Maui.Platform;
public class SkiaVisualStateSetter
{
private object? _originalValue;
private bool _hasOriginalValue;
public BindableProperty? Property { get; set; }
public object? Value { get; set; }
public void Apply(SkiaView view)
{
if (Property != null)
{
if (!_hasOriginalValue)
{
_originalValue = ((BindableObject)view).GetValue(Property);
_hasOriginalValue = true;
}
((BindableObject)view).SetValue(Property, Value);
}
}
public void Unapply(SkiaView view)
{
if (Property != null && _hasOriginalValue)
{
((BindableObject)view).SetValue(Property, _originalValue);
}
}
}

View File

File diff suppressed because it is too large Load Diff