Zum Inhalt
Kuonen.UI

MAUI-Zeichnen und Gesten

GraphicsView mit IDrawable und ICanvas; Tippen, Doppeltippen, Verschieben und Wischen über Gestenerkenner wie MAUI.

Vorführung: MAUI-Zeichnen und GestenVorführung: MAUI-Zeichnen und Gesten

KXAML

MauiZeichnenSeite.kxaml
<StackPanel xmlns="https://ui.kuonen.org/kxaml"
            xmlns:x="https://ui.kuonen.org/kxaml/x"
            x:Class="Kuonen.UI.Galerie.Seiten.MauiZeichnenVorfuehrung"
            Spacing="8">
  <!-- Gefüllt von MauiZeichnenSeite.Fuelle, derselben Methode wie die C#-Fassung. -->
  <StackPanel x:Name="Flaeche" Spacing="8" />
</StackPanel>
MauiZeichnenSeite.kxaml.cs
using Kuonen.UI;

namespace Kuonen.UI.Galerie.Seiten;

public sealed partial class MauiZeichnenSeite
{
    protected override Func<UIElement>? KxamlFabrik => () => new MauiZeichnenVorfuehrung();
}

/// <summary>KXAML-Fassung der Seite: das Gerüst steht in MauiZeichnenSeite.kxaml, das Innere füllt MauiZeichnenSeite.Fuelle.</summary>
public sealed partial class MauiZeichnenVorfuehrung
{
    public MauiZeichnenVorfuehrung()
    {
        InitializeComponent();
        MauiZeichnenSeite.Fuelle(Flaeche);
    }
}

C#

MauiZeichnenSeite.cs
using Kuonen.UI;
using Kuonen.UI.Controls;
using Kuonen.UI.Eingabe;
using Kuonen.UI.Layout;
using Kuonen.UI.Media;

namespace Kuonen.UI.Galerie.Seiten;

/// <summary>Galerie-Seite: GraphicsView und Gestenerkenner wie MAUI (Plan 6n).</summary>
public sealed partial class MauiZeichnenSeite : GalerieSeite
{
    public override string Titel => "MAUI-Zeichnen und Gesten";

    public override string Beschreibung => "GraphicsView mit IDrawable und ICanvas; Tippen, Doppeltippen, Verschieben und Wischen über Gestenerkenner wie MAUI.";

    public override string Stichworte => "MAUI Xamarin GraphicsView IDrawable ICanvas TapGestureRecognizer PanGestureRecognizer SwipeGestureRecognizer Geste Tippen Wischen";

    public override string Datei => nameof(MauiZeichnenSeite);

    public override UIElement Baue()
    {
        // Wie die KXAML-Fassung: eine Wurzel mit der Fläche darin.
        var flaeche = new StackPanel { Spacing = 8 };
        Fuelle(flaeche);
        return new StackPanel { Spacing = 8, Children = { flaeche } };
    }

    /// <summary>Ein Diagramm aus Balken, gezeichnet über die ICanvas.</summary>
    public sealed class Balken : IDrawable
    {
        public int Hervorgehoben { get; set; } = -1;

        private static readonly double[] Werte = [0.4, 0.7, 0.55, 0.9, 0.3];

        public void Draw(ICanvas canvas, Rect dirtyRect)
        {
            canvas.FillColor = Color.FromRgb(0xF2, 0xF2, 0xF2);
            canvas.FillRoundedRectangle(0, 0, dirtyRect.Width, dirtyRect.Height, 8);
            double breite = dirtyRect.Width / Werte.Length;
            for (int i = 0; i < Werte.Length; i++)
            {
                canvas.FillColor = i == Hervorgehoben ? Color.FromRgb(0xE5, 0x39, 0x35) : Color.FromRgb(0x1E, 0x88, 0xE5);
                double h = (dirtyRect.Height - 30) * Werte[i];
                canvas.FillRectangle(i * breite + 8, dirtyRect.Height - 20 - h, breite - 16, h);
                canvas.FontColor = Color.FromRgb(0x33, 0x33, 0x33);
                canvas.FontSize = 11;
                canvas.DrawString($"{Werte[i]:P0}", i * breite + breite / 2, dirtyRect.Height - 6, HorizontalAlignment.Center);
            }
        }
    }

    /// <summary>Inhalt der Seite (auch von der KXAML-Fassung benutzt).</summary>
    public static void Fuelle(StackPanel flaeche)
    {
        var balken = new Balken();
        var zeichnung = new GraphicsView { Drawable = balken, Width = 320, Height = 160, HorizontalAlignment = HorizontalAlignment.Left };
        var tippen = new TapGestureRecognizer();
        tippen.Tapped += (_, e) =>
        {
            if (e.GetPosition(zeichnung) is { } p) balken.Hervorgehoben = (int)(p.X / (zeichnung.Bounds.Width / 5));
            zeichnung.Invalidate();
        };
        zeichnung.GestureRecognizers.Add(tippen);
        flaeche.Children.Add(new TextBlock { Text = "GraphicsView (ein Tippen hebt einen Balken hervor)" });
        flaeche.Children.Add(zeichnung);

        var meldung = new TextBlock { Text = "Ziehe den Kasten, tippe doppelt oder wische." };
        var kasten = new BoxView { Color = new SolidColorBrush(Color.FromRgb(0x43, 0xA0, 0x47)), Width = 60, Height = 60, CornerRadius = new CornerRadius(8) };
        var spielfeld = new Canvas { Width = 320, Height = 140, Background = new SolidColorBrush(Color.FromRgb(0xF2, 0xF2, 0xF2)), HorizontalAlignment = HorizontalAlignment.Left, ClipToBounds = true };
        Canvas.SetLeft(kasten, 20);
        Canvas.SetTop(kasten, 40);
        spielfeld.Children.Add(kasten);
        double startX = 0, startY = 0;
        var verschieben = new PanGestureRecognizer();
        verschieben.PanUpdated += (_, e) =>
        {
            if (e.StatusType == GestureStatus.Started) (startX, startY) = (Canvas.GetLeft(kasten), Canvas.GetTop(kasten));
            if (e.StatusType != GestureStatus.Running) return;
            Canvas.SetLeft(kasten, Math.Clamp(startX + e.TotalX, 0, 260));
            Canvas.SetTop(kasten, Math.Clamp(startY + e.TotalY, 0, 80));
        };
        var doppelt = new TapGestureRecognizer { NumberOfTapsRequired = 2 };
        doppelt.Tapped += (_, _) => meldung.Text = "Doppelt getippt";
        kasten.GestureRecognizers.Add(verschieben);
        kasten.GestureRecognizers.Add(doppelt);
        var wischen = new SwipeGestureRecognizer { Direction = SwipeDirection.Left | SwipeDirection.Right | SwipeDirection.Up | SwipeDirection.Down };
        wischen.Swiped += (_, e) => meldung.Text = "Gewischt: " + e.Direction;
        spielfeld.GestureRecognizers.Add(wischen);
        flaeche.Children.Add(new TextBlock { Text = "Gestenerkenner" });
        flaeche.Children.Add(spielfeld);
        flaeche.Children.Add(meldung);
    }
}