Durchführen von iOS-Animationen für Ansichten mit UIKit und UIView

Veröffentlicht: 2022-03-10
Kurze Zusammenfassung ↬ Dieser Artikel soll eine Einführung in iOS-Animationen sein und die verschiedenen Möglichkeiten, dies zu tun, umfassend abdecken. Wir beginnen damit, die Grundlagen von Animationen zu verstehen, gehen zu den Core Frameworks über, bauen ein einzelnes Beispiel mit den verschiedenen angebotenen Methoden und betrachten schließlich Möglichkeiten zur Leistungsoptimierung.

Ich bin jetzt seit über einem Jahrzehnt iOS-Entwickler und habe selten Artikel gesehen, die alle möglichen Möglichkeiten zur Durchführung von Animationen in iOS konsolidieren. Dieser Artikel soll eine Einführung in iOS-Animationen sein, mit der Absicht, die verschiedenen Möglichkeiten, dasselbe zu tun, erschöpfend abzudecken.

Angesichts des Umfangs des Themas würden wir jeden Teil kurz und bündig auf einem ziemlich hohen Niveau behandeln. Das Ziel ist es, den Leser mit einer Reihe von Auswahlmöglichkeiten zu schulen, um Animationen zu seiner/ihrer iOS-App hinzuzufügen.

Bevor wir mit Themen rund um iOS beginnen, werfen wir einen kurzen Blick auf die Animationsgeschwindigkeit.

Animation bei 60 FPS

Im Allgemeinen wird in Videos jeder Frame durch ein Bild dargestellt und die Framerate bestimmt die Anzahl der Bilder, die in der Sequenz gespiegelt werden. Dies wird als "Bilder pro Sekunde" oder FPS bezeichnet.

FPS bestimmt die Anzahl der Standbilder, die innerhalb einer Sekunde gespiegelt werden, was wörtlich bedeutet, dass je mehr Bilder/Frames, desto mehr Details/Informationen im Video angezeigt werden. Dies gilt auch für Animationen.

FPS wird normalerweise verwendet, um die Qualität von Animationen zu bestimmen. Es gibt eine weit verbreitete Meinung, dass jede gute Animation mit 60 fps oder höher laufen sollte – alles unter 60 fps würde sich ein bisschen schlecht anfühlen.

Möchten Sie den Unterschied zwischen 30FPS und 60FPS sehen? Überprüfen Sie dies!

Hast du den Unterschied bemerkt? Das menschliche Auge kann den Jitter bei niedrigeren fps definitiv spüren. Daher ist es immer eine gute Praxis sicherzustellen, dass jede Animation, die Sie erstellen, der Grundregel entspricht, mit 60 FPS oder höher zu laufen. Dadurch fühlt es sich realistischer und lebendiger an.

Nachdem wir uns FPS angesehen haben, wollen wir uns nun mit den verschiedenen Kern-iOS-Frameworks befassen, die uns eine Möglichkeit bieten, Animationen auszuführen.

Mehr nach dem Sprung! Lesen Sie unten weiter ↓

Core-Frameworks

In diesem Abschnitt gehen wir auf die Frameworks im iOS SDK ein, die zum Erstellen von Ansichtsanimationen verwendet werden können. Wir werden sie alle kurz durchgehen und ihre Funktionen anhand eines relevanten Beispiels erläutern.

UIKit/ UIView-Animationen

UIView ist die Basisklasse für jede Ansicht, die Inhalte in iOS-Apps anzeigt.

UIKit, das Framework, das uns UIView gibt, bietet uns bereits einige grundlegende Animationsfunktionen, die es Entwicklern bequem machen, mit weniger Aufwand mehr zu erreichen.

Die API, UIView.animate , ist die einfachste Möglichkeit, Ansichten zu animieren, da die Eigenschaften jeder Ansicht einfach animiert werden können, indem die Eigenschaftswerte in der blockbasierten Syntax bereitgestellt werden.

In UIKit-Animationen wird empfohlen, nur die animierbaren Eigenschaften von UIVIew zu ändern, da es sonst zu Rückwirkungen kommt, bei denen die Animationen dazu führen können, dass die Ansicht in einem unerwarteten Zustand endet.

Animation (mit Dauer: Animationen: Abschluss)

Diese Methode berücksichtigt die Animationsdauer, eine Reihe von animierbaren Eigenschaftsänderungen einer Ansicht, die animiert werden müssen. Der Abschlussblock gibt einen Rückruf aus, wenn die Ansicht mit der Ausführung der Animation fertig ist.

Nahezu jede Art von Animation wie Bewegen, Skalieren, Drehen, Ausblenden usw. in einer Ansicht kann mit dieser einzigen API erreicht werden.

Stellen Sie sich nun vor, dass Sie eine Änderung der Schaltflächengröße animieren oder eine bestimmte Ansicht in den Bildschirm hineinzoomen möchten. So können wir es mit der UIView.animate API machen:

 let newButtonWidth: CGFloat = 60 UIView.animate(withDuration: 2.0) { //1 self.button.frame = CGRect(x: 0, y: 0, width: newButtonWidth, height: newButtonWidth) //2 self.button.center = self.view.center //3 }

Hier ist, was wir hier tun:

  1. Wir rufen die UIView.animate Methode auf, wobei ihr ein Dauerwert übergeben wird, der angibt, wie lange die im Block beschriebene Animation ausgeführt werden soll.
  2. Wir setzen den neuen Rahmen des Buttons, der den Endzustand der Animation darstellen soll.
  3. Wir legen die Schaltflächenmitte mit der center ihrer Übersicht so fest, dass sie in der Mitte des Bildschirms bleibt.

Der obige Block des Animationscodes sollte die Animation des Rahmens der Schaltfläche auslösen, der sich vom aktuellen Rahmen ändert:

Width = 0, Height = 0

Zum letzten Rahmen:

Width = Height = newButtonWidth

Und so würde die Animation aussehen:

animierenMitDauer

Diese Methode ist wie eine Erweiterung der Animate-Methode, bei der Sie alles tun können, was Sie in der vorherigen API ausführen können, wobei einige physikalische Verhaltensweisen zu den Ansichtsanimationen hinzugefügt werden.

Wenn Sie zum Beispiel Federdämpfungseffekte in der Animation erzielen möchten, die wir oben gemacht haben, dann würde der Code so aussehen:

 let newButtonWidth: CGFloat = 60 UIView.animate(withDuration: 1.0, //1 delay: 0.0, //2 usingSpringWithDamping: 0.3, //3 initialSpringVelocity: 1, //4 options: UIView.AnimationOptions.curveEaseInOut, //5 animations: ({ //6 self.button.frame = CGRect(x: 0, y: 0, width: newButtonWidth, height: newButtonWidth) self.button.center = self.view.center }), completion: nil)

Hier ist der Satz von Parametern, die wir verwenden:

  1. duration
    Stellt die Dauer der Animation dar, die bestimmt, wie lange der Codeblock ausgeführt werden soll.
  2. delay
    Stellt die anfängliche Verzögerung dar, die wir vor dem Start der Animation haben möchten.
  3. SpringWithDamping
    Stellt den Wert des Federeffekts dar, den die Ansicht verhalten soll. Der Wert muss zwischen 0 und 1 liegen. Je niedriger der Wert, desto höher die Federschwingung.
  4. velocity
    Stellt die Geschwindigkeit dar, mit der die Animation beginnen soll.
  5. options
    Art der Animationskurve, die Sie auf Ihre Ansichtsanimation anwenden möchten.
  6. Schließlich der Codeblock, in dem wir den Rahmen der Schaltfläche festlegen, die animiert werden muss. Es ist dasselbe wie in der vorherigen Animation.

Und so würde die Animation mit der obigen Animationskonfiguration aussehen:

UIViewPropertyAnimator

Für ein bisschen mehr Kontrolle über Animationen ist UIViewPropertyAnimator praktisch, wo es uns eine Möglichkeit bietet, Animationen anzuhalten und fortzusetzen. Sie können ein benutzerdefiniertes Timing haben und Ihre Animation interaktiv und unterbrechbar machen. Dies ist sehr hilfreich, wenn Animationen ausgeführt werden, die auch mit Benutzeraktionen interagierbar sind.

Die klassische „Slide to Unlock“-Geste und die Animation zum Schließen/Erweitern der Player-Ansicht (in der Musik-App) sind Beispiele für interaktive und unterbrechbare Animationen. Sie können eine Ansicht mit Ihrem Finger verschieben, ihn dann loslassen und die Ansicht kehrt zu ihrer ursprünglichen Position zurück. Alternativ können Sie die Ansicht während der Animation einfangen und mit dem Finger weiterziehen.

Es folgt ein einfaches Beispiel dafür, wie wir die Animation mit UIViewPropertyAnimator erreichen könnten:

 let newButtonWidth: CGFloat = 60 let animator = UIViewPropertyAnimator(duration:0.3, curve: .linear) { //1 self.button.frame = CGRect(x: 0, y: 0, width: newButtonWidth, height: newButtonWidth) self.button.center = self.view.center } animator.startAnimation() //2

Folgendes tun wir:

  1. Wir rufen die UIViewProperty API auf, indem wir die Dauer und die Animationskurve übergeben.
  2. Im Gegensatz zu den beiden oben genannten UIView.animate-APIs wird die Animation nicht gestartet, es sei denn, Sie geben sie selbst an, dh Sie haben die volle Kontrolle über den gesamten Animationsprozess/-ablauf.

Nehmen wir nun an, Sie möchten noch mehr Kontrolle über die Animationen. Beispielsweise möchten Sie jeden einzelnen Frame in der Animation entwerfen und steuern. Dafür gibt es eine andere API, animateKeyframes . Aber bevor wir uns damit befassen, schauen wir uns schnell an, was ein Frame in einer Animation ist.

Was ist ein frame ?

Eine Sammlung von Frameänderungen/-übergängen der Ansicht vom Startzustand zum Endzustand wird als animation definiert, und jede Position der Ansicht während der Animation wird als frame bezeichnet.

Keyframes animieren

Diese API bietet eine Möglichkeit, die Animation so zu gestalten, dass Sie mehrere Animationen mit unterschiedlichen Zeiten und Übergängen definieren können. Post this, die API integriert einfach alle Animationen in ein nahtloses Erlebnis.

Nehmen wir an, wir möchten unseren Button zufällig auf dem Bildschirm bewegen. Sehen wir uns an, wie wir die Keyframe-Animations-API dafür verwenden können.

 UIView.animateKeyframes(withDuration: 5, //1 delay: 0, //2 options: .calculationModeLinear, //3 animations: { //4 UIView.addKeyframe( //5 withRelativeStartTime: 0.25, //6 relativeDuration: 0.25) { //7 self.button.center = CGPoint(x: self.view.bounds.midX, y: self.view.bounds.maxY) //8 } UIView.addKeyframe(withRelativeStartTime: 0.5, relativeDuration: 0.25) { self.button.center = CGPoint(x: self.view.bounds.width, y: start.y) } UIView.addKeyframe(withRelativeStartTime: 0.75, relativeDuration: 0.25) { self.button.center = start } })

Hier ist die Aufschlüsselung:

  1. duration
    Rufen Sie die API auf, indem Sie die Dauer der Animation übergeben.
  2. delay
    Anfängliche Verzögerungsdauer der Animation.
  3. options
    Der Animationskurventyp, den Sie auf Ihre Ansichtsanimation anwenden möchten.
  4. animations
    Block, der alle vom Entwickler/Benutzer entworfenen Keyframe-Animationen aufnimmt.
  5. addKeyFrame
    Rufen Sie die API auf, um jede einzelne Animation zu entwerfen. In unserem Fall haben wir jede Bewegung der Schaltfläche definiert. Wir können dem Block beliebig viele solcher Animationen hinzufügen.
  6. relativeStartTime
    Definiert die Startzeit der Animation in der Sammlung des Animationsblocks.
  7. relativeDuration
    Definiert die Gesamtdauer dieser speziellen Animation.
  8. center
    In unserem Fall ändern wir einfach die Center-Eigenschaft der Schaltfläche, um die Schaltfläche auf dem Bildschirm zu verschieben.

Und so sehen die finalen Animationen aus:

CoreAnimation

Jede UIKit-basierte Animation wird intern in Kernanimationen übersetzt. Somit fungiert das Core Animation Framework als Trägerschicht oder Rückgrat für jede UIKit-Animation. Daher sind alle UIKit-Animations-APIs nichts anderes als gekapselte Schichten der Kern-Animations-APIs in einer leicht konsumierbaren oder bequemen Weise.

UIKit-Animations-APIs bieten nicht viel Kontrolle über Animationen, die für eine Ansicht ausgeführt wurden, da sie hauptsächlich für animierbare Eigenschaften der Ansicht verwendet werden. Daher ist es in solchen Fällen, in denen Sie die Kontrolle über jeden Frame der Animation haben möchten, besser, die zugrunde liegenden Core-Animations-APIs direkt zu verwenden. Alternativ können sowohl die UIView-Animationen als auch die Kernanimationen auch in Verbindung verwendet werden.

UIView + Core-Animation

Sehen wir uns an, wie wir dieselbe Schaltflächenänderungsanimation zusammen mit der Angabe der Zeitkurve mithilfe der UIView- und Core-Animations-APIs neu erstellen können.

Wir können die Timing-Funktionen von CATransaction verwenden, mit denen Sie die Animationskurve spezifizieren und steuern können.

Sehen wir uns ein Beispiel für eine Animation zum Ändern der Schaltflächengröße mit Eckenradius an, die die Zeitsteuerungsfunktion von CATransaction und eine Kombination von UIView-Animationen verwendet:

 let oldValue = button.frame.width/2 let newButtonWidth: CGFloat = 60 /* Do Animations */ CATransaction.begin() //1 CATransaction.setAnimationDuration(2.0) //2 CATransaction.setAnimationTimingFunction(CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeInEaseOut)) //3 // View animations //4 UIView.animate(withDuration: 1.0) { self.button.frame = CGRect(x: 0, y: 0, width: newButtonWidth, height: newButtonWidth) self.button.center = self.view.center } // Layer animations let cornerAnimation = CABasicAnimation(keyPath: #keyPath(CALayer.cornerRadius)) //5 cornerAnimation.fromValue = oldValue //6 cornerAnimation.toValue = newButtonWidth/2 //7 button.layer.cornerRadius = newButtonWidth/2 //8 button.layer.add(cornerAnimation, forKey: #keyPath(CALayer.cornerRadius)) //9 CATransaction.commit() //10

Hier ist die Aufschlüsselung:

  1. begin
    Repräsentiert den Beginn des Animationscodeblocks.
  2. duration
    Gesamtanimationsdauer.
  3. curve
    Stellt die Zeitkurve dar, die auf die Animation angewendet werden muss.
  4. UIView.animate
    Unsere erste Animation, um den Rahmen der Schaltfläche zu ändern.
  5. CABasicAnimation
    Wir erstellen das CABasicAnimation Objekt, indem wir auf den cornerRadius der Schaltfläche als Keypath verweisen, da wir diesen animieren möchten. Wenn Sie die Keyframe-Animationen genau steuern möchten, können Sie die CAKeyframeAnimation -Klasse verwenden.
  6. fromValue
    Stellt den Startwert der Animation dar, dh den Anfangswert von cornerRadius der Schaltfläche, von der aus die Animation beginnen muss.
  7. toValue
    Stellt den Endwert der Animation dar, dh den Endwert von cornerRadius der Schaltfläche, an der die Animation enden muss.
  8. cornerRadius
    Wir müssen die Eigenschaft cornerRadius der Schaltfläche mit dem endgültigen Wert der Animation festlegen, sonst wird der Wert von cornerRadius der Schaltfläche nach Abschluss der Animation automatisch auf seinen Anfangswert zurückgesetzt.
  9. addAnimation
    Wir hängen das Animationsobjekt, das die Konfiguration des gesamten Animationsprozesses enthält, an die Ebene an, indem wir den Schlüsselpfad darstellen, für den die Animation durchgeführt werden muss.
  10. commit
    Stellt das Ende des Animationscodeblocks dar und startet die Animation.

So würde die fertige Animation aussehen:

Dieser Blog ist eine großartige Lektüre, um fortgeschrittenere Animationen zu erstellen, da er Sie ordentlich durch die meisten APIs des Core Animation-Frameworks führt und Sie durch jeden Schritt des Weges führt.

UIKitDynamics

UIKit Dynamics ist die Physik-Engine für UIKit, mit der Sie den UIKit-Steuerelementen beliebige physikalische Verhaltensweisen wie Kollision, Schwerkraft, Stoß, Einrasten usw. hinzufügen können.

UIKitDynamicAnimator

Dies ist die Admin-Klasse des UIKit Dynamics-Frameworks, das alle Animationen reguliert, die von einem bestimmten UI-Steuerelement ausgelöst werden.

UIKitDynamicBehavior

Es ermöglicht Ihnen, einem Animator ein beliebiges physikalisches Verhalten hinzuzufügen, das es ihm dann ermöglicht, die ihm zugeordnete Ansicht auszuführen.

Zu den verschiedenen Arten von Verhalten für UIKitDynamics gehören:

  • UIAttachmentBehavior
  • UICollisionBehavior
  • UIFieldBehavior
  • UIGravityBehavior
  • UIPushBehavior
  • UISnapBehavior

Die Architektur von UIKitDynamics sieht etwa so aus. Beachten Sie, dass die Punkte 1 bis 5 durch eine einzelne Ansicht ersetzt werden können.

Lassen Sie uns ein physikalisches Verhalten auf unsere Schaltfläche anwenden. Wir werden sehen, wie man die Schwerkraft auf den Knopf anwendet, damit wir das Gefühl haben, mit einem realen Objekt umzugehen.

 var dynamicAnimator : UIDynamicAnimator! var gravityBehavior : UIGravityBehavior! dynamicAnimator = UIDynamicAnimator(referenceView: self.view) //1 gravityBehavior = UIGravityBehavior(items: [button]) //2 dynamicAnimator.addBehavior(gravityBehavior) //3

Hier ist die Aufschlüsselung:

  1. UIKitDynamicAnimator
    Wir haben ein UIKitDynamicAnimator Objekt erstellt, das als Orchestrator für die Ausführung von Animationen fungiert. Als Referenzansicht haben wir auch die Übersicht unseres Buttons übergeben.
  2. UIGravityBehavior
    Wir haben ein UIGravityBehavior Objekt erstellt und übergeben unsere Schaltfläche an die Array-Elemente, denen dieses Verhalten injiziert wird.
  3. addBehavior
    Wir haben das Gravitationsobjekt zum Animator hinzugefügt.

    Dies sollte eine Animation wie unten gezeigt erzeugen:
    Beachten Sie, wie die Schaltfläche von der Mitte (ihrer ursprünglichen Position) des Bildschirms nach unten und darüber hinaus abfällt.
    Wir sollten dem Animator sagen, dass er den unteren Rand des Bildschirms als Boden betrachten soll. Hier kommt UICollisionBehavior ins Bild.

     var dynamicAnimator : UIDynamicAnimator! var gravityBehavior : UIGravityBehavior! var collisionBehavior : UICollisionBehavior! dynamicAnimator = UIDynamicAnimator(referenceView: self.view) //1 gravityBehavior = UIGravityBehavior(items: [button]) //2 dynamicAnimator.addBehavior(gravityBehavior) //3 collisionBehavior = UICollisionBehavior(items: [button]) //4 collisionBehavior.translatesReferenceBoundsIntoBoundary = true //5 dynamicAnimator.addBehavior(collisionBehavior) //6
  4. UICollisionBehavior
    Wir haben ein UICollisionBehavior Objekt erstellt und die Schaltfläche weitergegeben, damit das Verhalten dem Element hinzugefügt wird.
  5. translatesReferenceBoundsIntoBoundary
    Das Aktivieren dieser Eigenschaft weist den Animator an, die Grenze der Referenzansichten als Ende zu nehmen, was in unserem Fall der untere Bildschirmrand ist.
  6. addBehavior
    Wir haben dem Animator hier ein Kollisionsverhalten hinzugefügt.

    Jetzt sollte unser Knopf den Boden berühren und wie unten gezeigt stillstehen:

    Das ist ziemlich ordentlich, nicht wahr?

    Lassen Sie uns nun versuchen, einen Sprungeffekt hinzuzufügen, damit sich unser Objekt realistischer anfühlt. Dazu verwenden wir die UIDynamicItemBehavior -Klasse.
     var dynamicAnimator : UIDynamicAnimator! var gravityBehavior : UIGravityBehavior! var collisionBehavior : UICollisionBehavior! var bouncingBehavior : UIDynamicItemBehavior! dynamicAnimator = UIDynamicAnimator(referenceView: self.view) //1 gravityBehavior = UIGravityBehavior(items: [button]) //2 dynamicAnimator.addBehavior(gravityBehavior) //3 collisionBehavior = UICollisionBehavior(items: [button]) //4 collisionBehavior.translatesReferenceBoundsIntoBoundary = true //5 dynamicAnimator.addBehavior(collisionBehavior) //6 //Adding the bounce effect bouncingBehavior = UIDynamicItemBehavior(items: [button]) //7 bouncingBehavior.elasticity = 0.75 //8 dynamicAnimator.addBehavior(bouncingBehavior) //9
  7. UIDynamicItemBehavior
    Wir haben ein UIDynamicItemBehavior Objekt erstellt und übergeben die Schaltfläche, damit das Verhalten dem Element hinzugefügt wird.
  8. elasticity
    Der Wert muss zwischen 0 und 1 liegen, er stellt die Elastizität dar, dh die Anzahl der Male, die das Objekt auf den Boden springen muss, wenn es getroffen wird. Hier passiert die Magie – indem Sie diese Eigenschaft optimieren, können Sie zwischen verschiedenen Arten von Objekten wie Bällen, Flaschen, harten Objekten und so weiter unterscheiden.
  9. addBehavior
    Wir haben dem Animator hier ein Kollisionsverhalten hinzugefügt.

Jetzt sollte unser Button abprallen, wenn er auf den Boden trifft, wie unten gezeigt:

Dieses Repo ist sehr hilfreich und zeigt alle UIKitDynamics-Verhaltensweisen in Aktion. Es bietet auch Quellcode, um mit jedem Verhalten herumzuspielen. Das sollte meiner Meinung nach als umfangreiche Liste von Möglichkeiten dienen, iOS-Animationen für Ansichten auszuführen!

Im nächsten Abschnitt werfen wir einen kurzen Blick auf die Tools, die uns bei der Messung der Leistung von Animationen helfen. Ich würde Ihnen auch empfehlen, nach Möglichkeiten zur Optimierung Ihres Xcode-Builds zu suchen, da dies eine große Menge Ihrer Entwicklungszeit einspart.

Leistungsoptimierung

In diesem Abschnitt sehen wir uns Möglichkeiten an, die Leistung von iOS-Animationen zu messen und zu optimieren. Als iOS-Entwickler haben Sie möglicherweise bereits Xcode-Instrumente wie Memory Leaks und Allocations verwendet, um die Leistung der gesamten App zu messen. Ebenso gibt es Instrumente, mit denen sich die Performance von Animationen messen lässt.

Core Animation

Probieren Sie das Core Animation -Instrument aus und Sie sollten in der Lage sein, die FPS zu sehen, die Ihr App-Bildschirm liefert. Dies ist eine großartige Möglichkeit, die Leistung/Geschwindigkeit jeder Animation zu messen, die in Ihrer iOS-App gerendert wird.

Zeichnung

FPS wird in der App, die schwere Inhalte wie Bilder mit Effekten wie Schatten anzeigt, erheblich gesenkt. Versuchen Sie in solchen Fällen, anstatt das Image direkt der image -Eigenschaft von UIImageView , das Bild mithilfe von Core Graphics-APIs separat in einem Kontext zu zeichnen. Dadurch wird die Bildanzeigezeit übermäßig reduziert, indem die Bilddekomprimierungslogik asynchron ausgeführt wird, wenn dies in einem separaten Thread anstelle des Haupt-Threads erfolgt.

Rasterung

Die Rasterung ist ein Prozess, mit dem komplexe Ebeneninformationen zwischengespeichert werden, damit diese Ansichten nicht neu gezeichnet werden, wenn sie gerendert werden. Das Neuzeichnen von Ansichten ist die Hauptursache für die Verringerung der FPS, und daher ist es am besten, die Rasterung auf Ansichten anzuwenden, die mehrmals wiederverwendet werden.

Einpacken

Abschließend habe ich noch eine Liste nützlicher Ressourcen für iOS-Animationen zusammengefasst. Sie finden dies möglicherweise sehr praktisch, wenn Sie an iOS-Animationen arbeiten. Darüber hinaus können Sie diese Reihe von Design-Tools auch als (Design-)Schritt hilfreich finden, bevor Sie sich mit Animationen befassen.

Ich hoffe, ich konnte so viele Themen wie möglich rund um iOS-Animationen abdecken. Wenn ich in diesem Artikel etwas übersehen haben sollte, lassen Sie es mich bitte im Kommentarbereich unten wissen, und ich würde mich freuen, die Ergänzung vorzunehmen!