en / de
Expertisen
Methoden
Dienstleistungen
Referenzen
Jobs & Karriere
Firma
Technologie-Trends TechCast WebCast TechBlog News Events Academy

Kreative Interaktion mit Xamarin.Forms Touch-Actions

Touch-Actions in Xamarin.Forms

Android und iOS Apps erstelle ich gerne mit Xamarin.Forms. Wegen der plattformübergreifenden Code-Basis spare ich Zeit und kann mich auf weniger Programmiersprachen konzentrieren. Auf plattformspezifische Features muss ich im Forms Projekt entweder verzichten, oder diese in den Plattformprojekten umsetzen.

Für die Interaktion mit dem Benutzer stehen mir verschiedene Touch-Actions zur Verfügung (Gesture recognizer). Gesten wie Tap, Pinch, Pan, Swipe, Drag & Drop kann ich so einfach erkennen und bereits raffinierte Interaktionsmöglichkeiten umsetzen.

Manchmal benötige ich jedoch mehr Flexibilität und möchte wissen, wo genau sich einer oder mehrere Finger des Benutzers auf dem Bildschirm befinden. Des Weiteren möchte ich die Bewegungspfade der Finger nachvollziehen können. Dafür brauche ich direkten Zugriff auf die Touch-Actions der jeweiligen Plattform.

In diesem Blog möchte ich anhand einer Demo-Applikation zeigen, wie ich Touch-Tracking in Xamarin.Forms mit minimalem Einsatz von plattformabhängigem Code eingesetzt habe.

Touch-Actions

In Xamarin.Forms selbst gibt es keine Unterstützung zur Nachverfolgung einzelner Finger Pfade. Es gibt jedoch die Möglichkeit einer plattformspezifischen Implementierung von Touch-Actions. Der Vorteil dabei ist, dass Pfade einzelner Finger unabhängig voneinander erfasst und sogar Informationen zum Druckpunkt ausgelesen werden können.

Demo – App

In meiner Demo App FourierDrawing (Xamarin Android) kann auf dem Bildschirm mit dem Finger ein Pfad gezeichnet werden. Dieser wird anschliessend durch ein Taylerpolynom approximiert und durch eine definierbare Anzahl epizyklischer Kreise reproduziert. Im Folgenden möchte ich mich jedoch lediglich auf die Implementierung der Fingerpfad-Erkennung konzentrieren:

Implementierung

  1. Gestartet habe ich mit einem leeren Xamarin.Forms Projekt.
  2. Im Android Projekt habe ich die Klasse TouchEffect.cs hinzugefügt, in welcher die Bildschirminteraktionen plattformspezifisch erfasst und über einen Event propagiert werden.
    namespace FourierDrawing.Droid
    {
        public class TouchEffect : PlatformEffect
        {
            Android.Views.View view;
            Element formsElement;
            TouchAction.TouchEffect libTouchEffect;
            bool capture;
            Func<double, double> fromPixels;
            int[] twoIntArray = new int[2];
    
            static Dictionary<Android.Views.View, TouchEffect> viewDictionary =
                new Dictionary<Android.Views.View, TouchEffect>();
    
            static Dictionary<int, TouchEffect> idToEffectDictionary =
                new Dictionary<int, TouchEffect>();
    
            protected override void OnAttached()
            {
                // Get the Android View corresponding to the Element that the effect is attached to
                view = Control ?? Container;
    
                // Get access to the TouchEffect class in the .NET Standard library
                TouchAction.TouchEffect touchEffect =
                    (TouchAction.TouchEffect)Element.Effects.
                        FirstOrDefault(e => e is TouchAction.TouchEffect);
    
                if (touchEffect != null && view != null)
                {
                    viewDictionary.Add(view, this);
    
                    formsElement = Element;
    
                    libTouchEffect = touchEffect;
    
                    // Save fromPixels function
                    fromPixels = view.Context.FromPixels;
    
                    // Set event handler on View
                    view.Touch += OnTouch;
                }
            }
    //...
  3. Im Forms Project habe ich die vom plattformspezifischen TouchEffect ableitende Klasse TouchEffect.cs mit ihren Abhängigkeiten (TouchActionEventArgs.cs, TouchActionEventHandler.cs, TouchActionType.cs) hinzugefügt. Diese ermöglicht eine Verwendung im Forms Projekt.
    namespace FourierDrawing.TouchAction
    {
        public class TouchEffect : RoutingEffect
        {
            public event TouchActionEventHandler TouchAction;
    
            public TouchEffect() : base("XamarinDocs.TouchEffect")
            {
            }
    
            public bool Capture { set; get; }
    
            public void OnTouchAction(Element element, TouchActionEventArgs args)
            {
                TouchAction?.Invoke(element, args);
            }
        }
    }
  4. Im XAML kann der spezifische TouchEffect folgendermassen verwendet werden:
  5. <ContentView VerticalOptions="FillAndExpand">
        <skia:SKCanvasView x:Name="CanvasView"
                           PaintSurface="OnCanvasViewPaintSurface"
                           BackgroundColor="White"/>
        
        <ContentView.Effects>
            <touchAction:TouchEffect Capture="True"
                            TouchAction="OnTouchEffectAction" />
        </ContentView.Effects>
    </ContentView>
  6. Im Codebehind implementiere ich die OnTouchEffectAction und verwende die TouchActionEventArgs. Bei Touch-Actions bekomme ich den Aktionstyp, die ID (es können mehrere Aktionen gleichzeitig stattfinden) und die Location mitgeliefert. Die Location kann ich einem bestehenden Pfad anhängen und diesen anschliessend auf dem Bildschirm darstellen
    private void OnTouchEffectAction(object sender, TouchActionEventArgs args)
            {
                switch (args.Type)
                {
                    case TouchActionType.Pressed:
                        if (_inProgressPaths.Count != 0) return;
                        if (!_inProgressPaths.ContainsKey(args.Id))
                        {
                            var path = new SKPath();
                            path.MoveTo(ConvertToPixel(args.Location));
                            _inProgressPaths.Add(args.Id, path);
                        }
                        break;
    
                    case TouchActionType.Moved:
                        if (_inProgressPaths.ContainsKey(args.Id))
                        {
                            var path = _inProgressPaths[args.Id];
                            path.LineTo(ConvertToPixel(args.Location));
                        }
                        break;
    
                    case TouchActionType.Released:
                        if (_inProgressPaths.ContainsKey(args.Id))
                        {
                            _completedPaths.Clear();
                            _inProgressPaths[args.Id].Close();
                            _completedPaths.Add(_inProgressPaths[args.Id]);
                            _inProgressPaths.Remove(args.Id);
                            _fixPath.Clear();
                            CreateFourierSerie();
                        }
                        break;
    
                    case TouchActionType.Cancelled:
                        if (_inProgressPaths.ContainsKey(args.Id))
                        {
                            _inProgressPaths.Remove(args.Id);
                        }
                        break;
                }
            }
  7. Wie ihr Pfade darstellen und animieren könntet, behandle ich in einem weiteren Blog. Ihr könnt eine iOS Implementierung wie im SkiaSharp-Projekt umsetzen. Im Anschluss seht ihr das Resultat meines eigenen Demo-Projektes.

Erfahrungen

Bei der Verwendung von Touch Gesten reicht mir die Flexibilität eines Gesture Recognizers in den meisten Fällen aus und ich mache kaum Gebrauch einer eigenen Implementierung. Die gezeigte Variante funktioniert jedoch sehr zuverlässig und ist auch mit mässigem Aufwand umsetzbar. Bei der Programmierung von Mobile-Apps hat Einfachheit jedoch meist Vorrang vor ausgefeilter Interaktion.

Nun wüsche ich viel Spass beim Erstellen eurer interaktiven Benutzeroberflächen!

Kommentare

Schreiben Sie einen Kommentar

Ihre E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert

Newsletter - aktuelle Angebote, exklusive Tipps und spannende Neuigkeiten

 Jetzt anmelden
NACH OBEN
Zur Webcast Übersicht