Files
maui-linux/Handlers/CarouselViewHandler.cs

256 lines
8.2 KiB
C#
Raw Normal View History

2026-01-17 01:18:57 +00:00
// 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.Handlers;
using Microsoft.Maui.Graphics;
using Microsoft.Maui.Controls;
using Microsoft.Maui.Platform;
using Microsoft.Maui.Platform.Linux.Hosting;
using SkiaSharp;
namespace Microsoft.Maui.Platform.Linux.Handlers;
/// <summary>
/// Handler for CarouselView on Linux using Skia rendering.
/// Maps CarouselView to SkiaCarouselView platform view.
/// </summary>
public partial class CarouselViewHandler : ViewHandler<CarouselView, SkiaCarouselView>
{
private bool _isUpdatingPosition;
public static IPropertyMapper<CarouselView, CarouselViewHandler> Mapper =
new PropertyMapper<CarouselView, CarouselViewHandler>(ViewHandler.ViewMapper)
{
// ItemsView properties
[nameof(ItemsView.ItemsSource)] = MapItemsSource,
[nameof(ItemsView.ItemTemplate)] = MapItemTemplate,
[nameof(ItemsView.EmptyView)] = MapEmptyView,
// CarouselView specific properties
[nameof(CarouselView.Position)] = MapPosition,
[nameof(CarouselView.CurrentItem)] = MapCurrentItem,
[nameof(CarouselView.IsBounceEnabled)] = MapIsBounceEnabled,
[nameof(CarouselView.IsSwipeEnabled)] = MapIsSwipeEnabled,
[nameof(CarouselView.Loop)] = MapLoop,
[nameof(CarouselView.PeekAreaInsets)] = MapPeekAreaInsets,
[nameof(IView.Background)] = MapBackground,
};
public static CommandMapper<CarouselView, CarouselViewHandler> CommandMapper =
new(ViewHandler.ViewCommandMapper)
{
["ScrollTo"] = MapScrollTo,
};
public CarouselViewHandler() : base(Mapper, CommandMapper)
{
}
public CarouselViewHandler(IPropertyMapper? mapper, CommandMapper? commandMapper = null)
: base(mapper ?? Mapper, commandMapper ?? CommandMapper)
{
}
protected override SkiaCarouselView CreatePlatformView()
{
return new SkiaCarouselView();
}
protected override void ConnectHandler(SkiaCarouselView platformView)
{
base.ConnectHandler(platformView);
platformView.PositionChanged += OnPositionChanged;
platformView.Scrolled += OnScrolled;
}
protected override void DisconnectHandler(SkiaCarouselView platformView)
{
platformView.PositionChanged -= OnPositionChanged;
platformView.Scrolled -= OnScrolled;
base.DisconnectHandler(platformView);
}
private void OnPositionChanged(object? sender, PositionChangedEventArgs e)
{
if (VirtualView is null || _isUpdatingPosition) return;
try
{
_isUpdatingPosition = true;
if (VirtualView.Position != e.CurrentPosition)
{
VirtualView.Position = e.CurrentPosition;
}
// Update CurrentItem
if (VirtualView.ItemsSource is System.Collections.IList list &&
e.CurrentPosition >= 0 && e.CurrentPosition < list.Count)
{
VirtualView.CurrentItem = list[e.CurrentPosition];
}
}
finally
{
_isUpdatingPosition = false;
}
}
private void OnScrolled(object? sender, EventArgs e)
{
// CarouselView doesn't have a direct Scrolled event in MAUI
// but we can use this for internal state tracking
}
public static void MapItemsSource(CarouselViewHandler handler, CarouselView carouselView)
{
if (handler.PlatformView is null || handler.MauiContext is null) return;
handler.PlatformView.ClearItems();
var itemsSource = carouselView.ItemsSource;
if (itemsSource == null) return;
var template = carouselView.ItemTemplate;
foreach (var item in itemsSource)
{
SkiaView? skiaView = null;
if (template != null)
{
try
{
var content = template.CreateContent();
if (content is View view)
{
view.BindingContext = item;
if (view.Handler == null)
{
view.Handler = view.ToViewHandler(handler.MauiContext);
}
if (view.Handler?.PlatformView is SkiaView sv)
{
skiaView = sv;
}
}
}
catch
{
// Ignore template errors
}
}
if (skiaView == null)
{
// Create a simple label for the item
skiaView = new SkiaLabel { Text = item?.ToString() ?? "" };
}
handler.PlatformView.AddItem(skiaView);
}
handler.PlatformView.Invalidate();
}
public static void MapItemTemplate(CarouselViewHandler handler, CarouselView carouselView)
{
// Re-map items when template changes
MapItemsSource(handler, carouselView);
}
public static void MapEmptyView(CarouselViewHandler handler, CarouselView carouselView)
{
// CarouselView doesn't typically show empty view - handled by ItemsSource
}
public static void MapPosition(CarouselViewHandler handler, CarouselView carouselView)
{
if (handler.PlatformView is null || handler._isUpdatingPosition) return;
try
{
handler._isUpdatingPosition = true;
if (handler.PlatformView.Position != carouselView.Position)
{
handler.PlatformView.Position = carouselView.Position;
}
}
finally
{
handler._isUpdatingPosition = false;
}
}
public static void MapCurrentItem(CarouselViewHandler handler, CarouselView carouselView)
{
if (handler.PlatformView is null || handler._isUpdatingPosition) return;
// Find position of current item
if (carouselView.ItemsSource is System.Collections.IList list && carouselView.CurrentItem != null)
{
int index = list.IndexOf(carouselView.CurrentItem);
if (index >= 0 && index != handler.PlatformView.Position)
{
try
{
handler._isUpdatingPosition = true;
handler.PlatformView.Position = index;
}
finally
{
handler._isUpdatingPosition = false;
}
}
}
}
public static void MapIsBounceEnabled(CarouselViewHandler handler, CarouselView carouselView)
{
// SkiaCarouselView handles bounce internally
// Could add IsBounceEnabled property if needed
}
public static void MapIsSwipeEnabled(CarouselViewHandler handler, CarouselView carouselView)
{
if (handler.PlatformView is null) return;
handler.PlatformView.IsSwipeEnabled = carouselView.IsSwipeEnabled;
}
public static void MapLoop(CarouselViewHandler handler, CarouselView carouselView)
{
if (handler.PlatformView is null) return;
handler.PlatformView.Loop = carouselView.Loop;
}
public static void MapPeekAreaInsets(CarouselViewHandler handler, CarouselView carouselView)
{
if (handler.PlatformView is null) return;
// PeekAreaInsets is a Thickness in MAUI, use Left for horizontal peek
handler.PlatformView.PeekAreaInsets = (float)carouselView.PeekAreaInsets.Left;
}
public static void MapBackground(CarouselViewHandler handler, CarouselView carouselView)
{
if (handler.PlatformView is null) return;
if (carouselView.Background is SolidColorBrush solidBrush)
{
handler.PlatformView.BackgroundColor = solidBrush.Color.ToSKColor();
}
}
public static void MapScrollTo(CarouselViewHandler handler, CarouselView carouselView, object? args)
{
if (handler.PlatformView is null) return;
if (args is ScrollToRequestEventArgs scrollArgs)
{
handler.PlatformView.ScrollTo(scrollArgs.Index, scrollArgs.IsAnimated);
}
}
}