2025-12-19 09:30:16 +00:00
|
|
|
// Licensed to the .NET Foundation under one or more agreements.
|
|
|
|
|
// The .NET Foundation licenses this file to you under the MIT license.
|
|
|
|
|
|
2026-01-17 03:45:05 +00:00
|
|
|
using Microsoft.Maui.Graphics;
|
2026-03-06 22:06:08 -05:00
|
|
|
using Microsoft.Maui.Platform.Linux.Services;
|
2025-12-19 09:30:16 +00:00
|
|
|
using SkiaSharp;
|
2025-12-21 13:26:56 -05:00
|
|
|
using Microsoft.Maui;
|
2025-12-19 09:30:16 +00:00
|
|
|
|
|
|
|
|
namespace Microsoft.Maui.Platform;
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Base class for layout containers that can arrange child views.
|
|
|
|
|
/// </summary>
|
|
|
|
|
public abstract class SkiaLayoutView : SkiaView
|
|
|
|
|
{
|
RC1: Full XAML support with BindableProperty, VSM, and data binding
Phase 1 - BindableProperty Foundation:
- SkiaLayoutView: Convert Spacing, Padding, ClipToBounds to BindableProperty
- SkiaStackLayout: Convert Orientation to BindableProperty
- SkiaGrid: Convert RowSpacing, ColumnSpacing to BindableProperty
- SkiaCollectionView: Convert all 12 properties to BindableProperty
- SkiaShell: Convert all 12 properties to BindableProperty
Phase 2 - Visual State Manager:
- Add VSM integration to SkiaImageButton pointer handlers
- Support Normal, PointerOver, Pressed, Disabled states
Phase 3-4 - XAML/Data Binding:
- Type converters for SKColor, SKRect, SKSize, SKPoint
- BindingContext propagation through visual tree
- Full handler registration for all MAUI controls
Documentation:
- README: Add styling/binding examples, update roadmap
- Add RC1-ROADMAP.md with implementation details
Version: 1.0.0-rc.1
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-28 09:26:04 -05:00
|
|
|
#region BindableProperties
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Bindable property for Spacing.
|
|
|
|
|
/// </summary>
|
|
|
|
|
public static readonly BindableProperty SpacingProperty =
|
|
|
|
|
BindableProperty.Create(
|
|
|
|
|
nameof(Spacing),
|
2026-01-17 03:45:05 +00:00
|
|
|
typeof(double),
|
RC1: Full XAML support with BindableProperty, VSM, and data binding
Phase 1 - BindableProperty Foundation:
- SkiaLayoutView: Convert Spacing, Padding, ClipToBounds to BindableProperty
- SkiaStackLayout: Convert Orientation to BindableProperty
- SkiaGrid: Convert RowSpacing, ColumnSpacing to BindableProperty
- SkiaCollectionView: Convert all 12 properties to BindableProperty
- SkiaShell: Convert all 12 properties to BindableProperty
Phase 2 - Visual State Manager:
- Add VSM integration to SkiaImageButton pointer handlers
- Support Normal, PointerOver, Pressed, Disabled states
Phase 3-4 - XAML/Data Binding:
- Type converters for SKColor, SKRect, SKSize, SKPoint
- BindingContext propagation through visual tree
- Full handler registration for all MAUI controls
Documentation:
- README: Add styling/binding examples, update roadmap
- Add RC1-ROADMAP.md with implementation details
Version: 1.0.0-rc.1
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-28 09:26:04 -05:00
|
|
|
typeof(SkiaLayoutView),
|
2026-01-17 03:45:05 +00:00
|
|
|
0.0,
|
2026-01-01 14:30:17 -05:00
|
|
|
BindingMode.TwoWay,
|
RC1: Full XAML support with BindableProperty, VSM, and data binding
Phase 1 - BindableProperty Foundation:
- SkiaLayoutView: Convert Spacing, Padding, ClipToBounds to BindableProperty
- SkiaStackLayout: Convert Orientation to BindableProperty
- SkiaGrid: Convert RowSpacing, ColumnSpacing to BindableProperty
- SkiaCollectionView: Convert all 12 properties to BindableProperty
- SkiaShell: Convert all 12 properties to BindableProperty
Phase 2 - Visual State Manager:
- Add VSM integration to SkiaImageButton pointer handlers
- Support Normal, PointerOver, Pressed, Disabled states
Phase 3-4 - XAML/Data Binding:
- Type converters for SKColor, SKRect, SKSize, SKPoint
- BindingContext propagation through visual tree
- Full handler registration for all MAUI controls
Documentation:
- README: Add styling/binding examples, update roadmap
- Add RC1-ROADMAP.md with implementation details
Version: 1.0.0-rc.1
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-28 09:26:04 -05:00
|
|
|
propertyChanged: (b, o, n) => ((SkiaLayoutView)b).InvalidateMeasure());
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Bindable property for Padding.
|
|
|
|
|
/// </summary>
|
|
|
|
|
public static readonly BindableProperty PaddingProperty =
|
|
|
|
|
BindableProperty.Create(
|
|
|
|
|
nameof(Padding),
|
2026-01-17 03:45:05 +00:00
|
|
|
typeof(Thickness),
|
RC1: Full XAML support with BindableProperty, VSM, and data binding
Phase 1 - BindableProperty Foundation:
- SkiaLayoutView: Convert Spacing, Padding, ClipToBounds to BindableProperty
- SkiaStackLayout: Convert Orientation to BindableProperty
- SkiaGrid: Convert RowSpacing, ColumnSpacing to BindableProperty
- SkiaCollectionView: Convert all 12 properties to BindableProperty
- SkiaShell: Convert all 12 properties to BindableProperty
Phase 2 - Visual State Manager:
- Add VSM integration to SkiaImageButton pointer handlers
- Support Normal, PointerOver, Pressed, Disabled states
Phase 3-4 - XAML/Data Binding:
- Type converters for SKColor, SKRect, SKSize, SKPoint
- BindingContext propagation through visual tree
- Full handler registration for all MAUI controls
Documentation:
- README: Add styling/binding examples, update roadmap
- Add RC1-ROADMAP.md with implementation details
Version: 1.0.0-rc.1
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-28 09:26:04 -05:00
|
|
|
typeof(SkiaLayoutView),
|
2026-01-17 03:45:05 +00:00
|
|
|
default(Thickness),
|
2026-01-01 14:30:17 -05:00
|
|
|
BindingMode.TwoWay,
|
RC1: Full XAML support with BindableProperty, VSM, and data binding
Phase 1 - BindableProperty Foundation:
- SkiaLayoutView: Convert Spacing, Padding, ClipToBounds to BindableProperty
- SkiaStackLayout: Convert Orientation to BindableProperty
- SkiaGrid: Convert RowSpacing, ColumnSpacing to BindableProperty
- SkiaCollectionView: Convert all 12 properties to BindableProperty
- SkiaShell: Convert all 12 properties to BindableProperty
Phase 2 - Visual State Manager:
- Add VSM integration to SkiaImageButton pointer handlers
- Support Normal, PointerOver, Pressed, Disabled states
Phase 3-4 - XAML/Data Binding:
- Type converters for SKColor, SKRect, SKSize, SKPoint
- BindingContext propagation through visual tree
- Full handler registration for all MAUI controls
Documentation:
- README: Add styling/binding examples, update roadmap
- Add RC1-ROADMAP.md with implementation details
Version: 1.0.0-rc.1
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-28 09:26:04 -05:00
|
|
|
propertyChanged: (b, o, n) => ((SkiaLayoutView)b).InvalidateMeasure());
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Bindable property for ClipToBounds.
|
|
|
|
|
/// </summary>
|
|
|
|
|
public static readonly BindableProperty ClipToBoundsProperty =
|
|
|
|
|
BindableProperty.Create(
|
|
|
|
|
nameof(ClipToBounds),
|
|
|
|
|
typeof(bool),
|
|
|
|
|
typeof(SkiaLayoutView),
|
|
|
|
|
false,
|
2026-01-01 14:30:17 -05:00
|
|
|
BindingMode.TwoWay,
|
RC1: Full XAML support with BindableProperty, VSM, and data binding
Phase 1 - BindableProperty Foundation:
- SkiaLayoutView: Convert Spacing, Padding, ClipToBounds to BindableProperty
- SkiaStackLayout: Convert Orientation to BindableProperty
- SkiaGrid: Convert RowSpacing, ColumnSpacing to BindableProperty
- SkiaCollectionView: Convert all 12 properties to BindableProperty
- SkiaShell: Convert all 12 properties to BindableProperty
Phase 2 - Visual State Manager:
- Add VSM integration to SkiaImageButton pointer handlers
- Support Normal, PointerOver, Pressed, Disabled states
Phase 3-4 - XAML/Data Binding:
- Type converters for SKColor, SKRect, SKSize, SKPoint
- BindingContext propagation through visual tree
- Full handler registration for all MAUI controls
Documentation:
- README: Add styling/binding examples, update roadmap
- Add RC1-ROADMAP.md with implementation details
Version: 1.0.0-rc.1
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-28 09:26:04 -05:00
|
|
|
propertyChanged: (b, o, n) => ((SkiaLayoutView)b).Invalidate());
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
2025-12-19 09:30:16 +00:00
|
|
|
private readonly List<SkiaView> _children = new();
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Gets the children of this layout.
|
|
|
|
|
/// </summary>
|
|
|
|
|
public new IReadOnlyList<SkiaView> Children => _children;
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Spacing between children.
|
|
|
|
|
/// </summary>
|
2026-01-17 03:45:05 +00:00
|
|
|
public double Spacing
|
RC1: Full XAML support with BindableProperty, VSM, and data binding
Phase 1 - BindableProperty Foundation:
- SkiaLayoutView: Convert Spacing, Padding, ClipToBounds to BindableProperty
- SkiaStackLayout: Convert Orientation to BindableProperty
- SkiaGrid: Convert RowSpacing, ColumnSpacing to BindableProperty
- SkiaCollectionView: Convert all 12 properties to BindableProperty
- SkiaShell: Convert all 12 properties to BindableProperty
Phase 2 - Visual State Manager:
- Add VSM integration to SkiaImageButton pointer handlers
- Support Normal, PointerOver, Pressed, Disabled states
Phase 3-4 - XAML/Data Binding:
- Type converters for SKColor, SKRect, SKSize, SKPoint
- BindingContext propagation through visual tree
- Full handler registration for all MAUI controls
Documentation:
- README: Add styling/binding examples, update roadmap
- Add RC1-ROADMAP.md with implementation details
Version: 1.0.0-rc.1
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-28 09:26:04 -05:00
|
|
|
{
|
2026-01-17 03:45:05 +00:00
|
|
|
get => (double)GetValue(SpacingProperty);
|
RC1: Full XAML support with BindableProperty, VSM, and data binding
Phase 1 - BindableProperty Foundation:
- SkiaLayoutView: Convert Spacing, Padding, ClipToBounds to BindableProperty
- SkiaStackLayout: Convert Orientation to BindableProperty
- SkiaGrid: Convert RowSpacing, ColumnSpacing to BindableProperty
- SkiaCollectionView: Convert all 12 properties to BindableProperty
- SkiaShell: Convert all 12 properties to BindableProperty
Phase 2 - Visual State Manager:
- Add VSM integration to SkiaImageButton pointer handlers
- Support Normal, PointerOver, Pressed, Disabled states
Phase 3-4 - XAML/Data Binding:
- Type converters for SKColor, SKRect, SKSize, SKPoint
- BindingContext propagation through visual tree
- Full handler registration for all MAUI controls
Documentation:
- README: Add styling/binding examples, update roadmap
- Add RC1-ROADMAP.md with implementation details
Version: 1.0.0-rc.1
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-28 09:26:04 -05:00
|
|
|
set => SetValue(SpacingProperty, value);
|
|
|
|
|
}
|
2025-12-19 09:30:16 +00:00
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Padding around the content.
|
|
|
|
|
/// </summary>
|
2026-01-17 03:45:05 +00:00
|
|
|
public Thickness Padding
|
RC1: Full XAML support with BindableProperty, VSM, and data binding
Phase 1 - BindableProperty Foundation:
- SkiaLayoutView: Convert Spacing, Padding, ClipToBounds to BindableProperty
- SkiaStackLayout: Convert Orientation to BindableProperty
- SkiaGrid: Convert RowSpacing, ColumnSpacing to BindableProperty
- SkiaCollectionView: Convert all 12 properties to BindableProperty
- SkiaShell: Convert all 12 properties to BindableProperty
Phase 2 - Visual State Manager:
- Add VSM integration to SkiaImageButton pointer handlers
- Support Normal, PointerOver, Pressed, Disabled states
Phase 3-4 - XAML/Data Binding:
- Type converters for SKColor, SKRect, SKSize, SKPoint
- BindingContext propagation through visual tree
- Full handler registration for all MAUI controls
Documentation:
- README: Add styling/binding examples, update roadmap
- Add RC1-ROADMAP.md with implementation details
Version: 1.0.0-rc.1
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-28 09:26:04 -05:00
|
|
|
{
|
2026-01-17 03:45:05 +00:00
|
|
|
get => (Thickness)GetValue(PaddingProperty);
|
RC1: Full XAML support with BindableProperty, VSM, and data binding
Phase 1 - BindableProperty Foundation:
- SkiaLayoutView: Convert Spacing, Padding, ClipToBounds to BindableProperty
- SkiaStackLayout: Convert Orientation to BindableProperty
- SkiaGrid: Convert RowSpacing, ColumnSpacing to BindableProperty
- SkiaCollectionView: Convert all 12 properties to BindableProperty
- SkiaShell: Convert all 12 properties to BindableProperty
Phase 2 - Visual State Manager:
- Add VSM integration to SkiaImageButton pointer handlers
- Support Normal, PointerOver, Pressed, Disabled states
Phase 3-4 - XAML/Data Binding:
- Type converters for SKColor, SKRect, SKSize, SKPoint
- BindingContext propagation through visual tree
- Full handler registration for all MAUI controls
Documentation:
- README: Add styling/binding examples, update roadmap
- Add RC1-ROADMAP.md with implementation details
Version: 1.0.0-rc.1
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-28 09:26:04 -05:00
|
|
|
set => SetValue(PaddingProperty, value);
|
|
|
|
|
}
|
2025-12-19 09:30:16 +00:00
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Gets or sets whether child views are clipped to the bounds.
|
|
|
|
|
/// </summary>
|
RC1: Full XAML support with BindableProperty, VSM, and data binding
Phase 1 - BindableProperty Foundation:
- SkiaLayoutView: Convert Spacing, Padding, ClipToBounds to BindableProperty
- SkiaStackLayout: Convert Orientation to BindableProperty
- SkiaGrid: Convert RowSpacing, ColumnSpacing to BindableProperty
- SkiaCollectionView: Convert all 12 properties to BindableProperty
- SkiaShell: Convert all 12 properties to BindableProperty
Phase 2 - Visual State Manager:
- Add VSM integration to SkiaImageButton pointer handlers
- Support Normal, PointerOver, Pressed, Disabled states
Phase 3-4 - XAML/Data Binding:
- Type converters for SKColor, SKRect, SKSize, SKPoint
- BindingContext propagation through visual tree
- Full handler registration for all MAUI controls
Documentation:
- README: Add styling/binding examples, update roadmap
- Add RC1-ROADMAP.md with implementation details
Version: 1.0.0-rc.1
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-28 09:26:04 -05:00
|
|
|
public bool ClipToBounds
|
|
|
|
|
{
|
|
|
|
|
get => (bool)GetValue(ClipToBoundsProperty);
|
|
|
|
|
set => SetValue(ClipToBoundsProperty, value);
|
|
|
|
|
}
|
2025-12-19 09:30:16 +00:00
|
|
|
|
2025-12-21 13:26:56 -05:00
|
|
|
/// <summary>
|
|
|
|
|
/// Called when binding context changes. Propagates to layout children.
|
|
|
|
|
/// </summary>
|
|
|
|
|
protected override void OnBindingContextChanged()
|
|
|
|
|
{
|
|
|
|
|
base.OnBindingContextChanged();
|
|
|
|
|
|
|
|
|
|
// Propagate binding context to layout children
|
|
|
|
|
foreach (var child in _children)
|
|
|
|
|
{
|
|
|
|
|
SetInheritedBindingContext(child, BindingContext);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-12-19 09:30:16 +00:00
|
|
|
/// <summary>
|
|
|
|
|
/// Adds a child view.
|
|
|
|
|
/// </summary>
|
|
|
|
|
public virtual void AddChild(SkiaView child)
|
|
|
|
|
{
|
|
|
|
|
if (child.Parent != null)
|
|
|
|
|
{
|
|
|
|
|
throw new InvalidOperationException("View already has a parent");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
_children.Add(child);
|
|
|
|
|
child.Parent = this;
|
2025-12-21 13:26:56 -05:00
|
|
|
|
|
|
|
|
// Propagate binding context to new child
|
|
|
|
|
if (BindingContext != null)
|
|
|
|
|
{
|
|
|
|
|
SetInheritedBindingContext(child, BindingContext);
|
|
|
|
|
}
|
|
|
|
|
|
2025-12-19 09:30:16 +00:00
|
|
|
InvalidateMeasure();
|
|
|
|
|
Invalidate();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Removes a child view.
|
|
|
|
|
/// </summary>
|
|
|
|
|
public virtual void RemoveChild(SkiaView child)
|
|
|
|
|
{
|
|
|
|
|
if (_children.Remove(child))
|
|
|
|
|
{
|
|
|
|
|
child.Parent = null;
|
|
|
|
|
InvalidateMeasure();
|
|
|
|
|
Invalidate();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Removes a child at the specified index.
|
|
|
|
|
/// </summary>
|
|
|
|
|
public virtual void RemoveChildAt(int index)
|
|
|
|
|
{
|
|
|
|
|
if (index >= 0 && index < _children.Count)
|
|
|
|
|
{
|
|
|
|
|
var child = _children[index];
|
|
|
|
|
_children.RemoveAt(index);
|
|
|
|
|
child.Parent = null;
|
|
|
|
|
InvalidateMeasure();
|
|
|
|
|
Invalidate();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Inserts a child at the specified index.
|
|
|
|
|
/// </summary>
|
|
|
|
|
public virtual void InsertChild(int index, SkiaView child)
|
|
|
|
|
{
|
|
|
|
|
if (child.Parent != null)
|
|
|
|
|
{
|
|
|
|
|
throw new InvalidOperationException("View already has a parent");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
_children.Insert(index, child);
|
|
|
|
|
child.Parent = this;
|
2025-12-21 13:26:56 -05:00
|
|
|
|
|
|
|
|
// Propagate binding context to new child
|
|
|
|
|
if (BindingContext != null)
|
|
|
|
|
{
|
|
|
|
|
SetInheritedBindingContext(child, BindingContext);
|
|
|
|
|
}
|
|
|
|
|
|
2025-12-19 09:30:16 +00:00
|
|
|
InvalidateMeasure();
|
|
|
|
|
Invalidate();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Clears all children.
|
|
|
|
|
/// </summary>
|
|
|
|
|
public virtual void ClearChildren()
|
|
|
|
|
{
|
|
|
|
|
foreach (var child in _children)
|
|
|
|
|
{
|
|
|
|
|
child.Parent = null;
|
|
|
|
|
}
|
|
|
|
|
_children.Clear();
|
|
|
|
|
InvalidateMeasure();
|
|
|
|
|
Invalidate();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Gets the content bounds (bounds minus padding).
|
|
|
|
|
/// </summary>
|
|
|
|
|
protected virtual SKRect GetContentBounds()
|
|
|
|
|
{
|
2026-01-17 05:22:37 +00:00
|
|
|
return GetContentBounds(new SKRect((float)Bounds.Left, (float)Bounds.Top, (float)(Bounds.Left + Bounds.Width), (float)(Bounds.Top + Bounds.Height)));
|
2025-12-19 09:30:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Gets the content bounds for a given bounds rectangle.
|
|
|
|
|
/// </summary>
|
|
|
|
|
protected SKRect GetContentBounds(SKRect bounds)
|
|
|
|
|
{
|
|
|
|
|
return new SKRect(
|
2026-01-17 03:45:05 +00:00
|
|
|
bounds.Left + (float)Padding.Left,
|
|
|
|
|
bounds.Top + (float)Padding.Top,
|
|
|
|
|
bounds.Right - (float)Padding.Right,
|
|
|
|
|
bounds.Bottom - (float)Padding.Bottom);
|
2025-12-19 09:30:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected override void OnDraw(SKCanvas canvas, SKRect bounds)
|
|
|
|
|
{
|
2025-12-21 13:26:56 -05:00
|
|
|
// Draw background if set (for layouts inside CollectionView items)
|
2026-01-17 03:10:29 +00:00
|
|
|
if (BackgroundColor != null && BackgroundColor != Colors.Transparent)
|
2025-12-21 13:26:56 -05:00
|
|
|
{
|
2026-01-17 03:10:29 +00:00
|
|
|
using var bgPaint = new SKPaint { Color = GetEffectiveBackgroundColor(), Style = SKPaintStyle.Fill };
|
2025-12-21 13:26:56 -05:00
|
|
|
canvas.DrawRect(bounds, bgPaint);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Log for StackLayout
|
|
|
|
|
if (this is SkiaStackLayout)
|
|
|
|
|
{
|
|
|
|
|
bool hasCV = false;
|
|
|
|
|
foreach (var c in _children)
|
|
|
|
|
{
|
|
|
|
|
if (c is SkiaCollectionView) hasCV = true;
|
|
|
|
|
}
|
|
|
|
|
if (hasCV)
|
|
|
|
|
{
|
2026-03-06 22:06:08 -05:00
|
|
|
DiagnosticLog.Debug("SkiaLayoutView", $"[SkiaStackLayout+CV] OnDraw - bounds={bounds}, children={_children.Count}");
|
2025-12-21 13:26:56 -05:00
|
|
|
foreach (var c in _children)
|
|
|
|
|
{
|
2026-03-06 22:06:08 -05:00
|
|
|
DiagnosticLog.Debug("SkiaLayoutView", $"[SkiaStackLayout+CV] Child: {c.GetType().Name}, IsVisible={c.IsVisible}, Bounds={c.Bounds}");
|
2025-12-21 13:26:56 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-12-19 09:30:16 +00:00
|
|
|
// Draw children in order
|
|
|
|
|
foreach (var child in _children)
|
|
|
|
|
{
|
|
|
|
|
if (child.IsVisible)
|
|
|
|
|
{
|
|
|
|
|
child.Draw(canvas);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public override SkiaView? HitTest(float x, float y)
|
|
|
|
|
{
|
2026-01-17 05:22:37 +00:00
|
|
|
if (!IsVisible || !IsEnabled || !Bounds.Contains(x, y))
|
2025-12-19 09:30:16 +00:00
|
|
|
return null;
|
|
|
|
|
|
|
|
|
|
// Hit test children in reverse order (top-most first)
|
|
|
|
|
for (int i = _children.Count - 1; i >= 0; i--)
|
|
|
|
|
{
|
|
|
|
|
var child = _children[i];
|
|
|
|
|
var hit = child.HitTest(x, y);
|
|
|
|
|
if (hit != null)
|
|
|
|
|
return hit;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return this;
|
|
|
|
|
}
|
2025-12-21 13:26:56 -05:00
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Forward pointer pressed events to the appropriate child.
|
|
|
|
|
/// </summary>
|
|
|
|
|
public override void OnPointerPressed(PointerEventArgs e)
|
|
|
|
|
{
|
|
|
|
|
// Find which child was hit and forward the event
|
|
|
|
|
var hit = HitTest(e.X, e.Y);
|
|
|
|
|
if (hit != null && hit != this)
|
|
|
|
|
{
|
|
|
|
|
hit.OnPointerPressed(e);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Forward pointer released events to the appropriate child.
|
|
|
|
|
/// </summary>
|
|
|
|
|
public override void OnPointerReleased(PointerEventArgs e)
|
|
|
|
|
{
|
|
|
|
|
// Find which child was hit and forward the event
|
|
|
|
|
var hit = HitTest(e.X, e.Y);
|
|
|
|
|
if (hit != null && hit != this)
|
|
|
|
|
{
|
|
|
|
|
hit.OnPointerReleased(e);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Forward pointer moved events to the appropriate child.
|
|
|
|
|
/// </summary>
|
|
|
|
|
public override void OnPointerMoved(PointerEventArgs e)
|
|
|
|
|
{
|
|
|
|
|
// Find which child was hit and forward the event
|
|
|
|
|
var hit = HitTest(e.X, e.Y);
|
|
|
|
|
if (hit != null && hit != this)
|
|
|
|
|
{
|
|
|
|
|
hit.OnPointerMoved(e);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Forward scroll events to the appropriate child.
|
|
|
|
|
/// </summary>
|
|
|
|
|
public override void OnScroll(ScrollEventArgs e)
|
|
|
|
|
{
|
|
|
|
|
// Find which child was hit and forward the event
|
|
|
|
|
var hit = HitTest(e.X, e.Y);
|
|
|
|
|
if (hit != null && hit != this)
|
|
|
|
|
{
|
|
|
|
|
hit.OnScroll(e);
|
|
|
|
|
}
|
|
|
|
|
}
|
2025-12-19 09:30:16 +00:00
|
|
|
}
|