Kies SwiftUI Canvas wanneer je zelf expliciete plaatsingsregels voor het verslepen wilt implementeren. Kies SpriteKit wanneer vormen elkaar moeten wegduwen, stuiteren of door de natuurkunde in beweging moeten blijven. Bepaal eerst wat er gebeurt wanneer een versleepte vorm een andere vorm raakt.
Deze gids behandelt één taak: de interactiearchitectuur kiezen voor een Mac-app met synthetische cirkels of rechthoeken in het geheugen, die gebruikers binnen een door de app beheerde werkruimte verslepen. De keuze hangt af van botsingsgedrag, invoerverwerking en welk onderdeel de positie van elke vorm beheert.
Wat moet er gebeuren wanneer twee vormen elkaar raken?
‘Botsingsreactie’ kan naar verschillende vereisten verwijzen. Een overlap markeren, een ongeldige positie weigeren en twee objecten laten stuiteren vereisen verschillende mechanismen. Apple maakt expliciet onderscheid tussen SpriteKit-contacten, die aanraking tussen lichamen melden, en botsingen, die een fysieke reactie berekenen en impulsen toepassen. Over botsingen en contacten
| Gewenst gedrag | Praktisch startpunt | Verantwoordelijkheid die je zelf behoudt |
|---|---|---|
| Een overlap markeren terwijl de aanwijzer een vorm vrij plaatst | Canvas met aangepaste geometrische tests | Selecteren, overlapdetectie en visuele feedback |
| Een vorm bij de eerste hindernis tegenhouden | Canvas met aangepaste bewegingsbeperkingen | Het bewegingstraject controleren en de geaccepteerde positie bepalen |
| Naburige vormen wegduwen en laten uitdempen of stuiteren | SpriteKit | Fysische configuratie en een sleepcontroller |
| Elk item gewone SwiftUI-regelaars en gebaren geven | Afzonderlijke SwiftUI-weergaven | Applicatiespecifieke overlap- of bewegingsregels |
Dit zijn architectuuraanbevelingen op basis van de gedocumenteerde mogelijkheden, geen prestatiedrempels van Apple. Een klein aantal vormen betekent niet automatisch dat Canvas de beste keuze is, en een groot aantal vereist niet automatisch SpriteKit. Kies eerst het gedrag en meet daarna de implementatie met representatieve items.
Er is ook een nuttige interactiebeperking: de aanwijzer exact volgen kan botsen met strikte non-overlap. Als de aanwijzer over een bezette positie beweegt, moet de app het item laten overlappen, het achter de aanwijzer tegenhouden of andere items verplaatsen. Leg die keuze vast voordat je de renderer kiest.
Wat biedt Canvas en wat moet je zelf bouwen?
Canvas biedt direct tekenen via een grafische context. De cirkels, paden en symbolen worden geen afzonderlijk interactieve elementen. Apple vermeldt ook dat Canvas geen toegankelijkheid biedt voor afzonderlijk getekende elementen, inclusief symbolen die als weergaven worden aangeleverd. Een gebaar op het canvas vereist daarom applicatielogica om te bepalen welk item de gebruiker heeft geselecteerd. Canvas
Houd voor een editor met expliciete plaatsingsregels de vormen in een model en behandel het tekenen als een weergave van dat model. Elk item kan een identificatie, middelpunt, afmetingen en tekenvolgorde bevatten. Swift adviseert standaard structuren voor gewone gegevens en klassen wanneer gedeelde identiteit of overerving van een framework nodig is. Een itemmodel als waardetype en een SpriteKit-scènesubklasse dienen verschillende doelen. Kiezen tussen structuren en klassen
Een Canvas-sleepbewerking kan deze stappen volgen:
- Controleer bij het begin van het gebaar de startpositie van de aanwijzer tegen de items, in omgekeerde tekenvolgorde. Selecteer het eerste item dat overeenkomt.
- Bewaar de geselecteerde identificatie en het oorspronkelijke middelpunt gedurende het hele gebaar.
- Bereken elk voorgesteld middelpunt op basis van dat oorspronkelijke middelpunt plus de totale verplaatsing van het gebaar.
- Pas de grenzen van de werkruimte en de botsingsregels toe om een geaccepteerd middelpunt te bepalen.
- Werk het model bij; laat Canvas het opnieuw tekenen op basis daarvan.
- Wis de selectie wanneer het gebaar eindigt en definieer ook opruimwerk voor onderbroken interacties.
Het onderscheid tussen totale en stapsgewijze verplaatsing is belangrijk. SwiftUI definieert translation als de verplaatsing vanaf het begin van het gebaar. Als je die totale verplaatsing telkens optelt bij een al bijgewerkt middelpunt, ontstaat er te veel beweging. Gebruik telkens het bewaarde startmiddelpunt. SwiftUI biedt startLocation, location en translation aan via de gebaarwaarde, en laat je de coördinatenruimte van het gebaar specificeren. DragGesture.Value, DragGesture
Houd de selectie stabiel tijdens het slepen. Als je de oorspronkelijke selectietest bij elke update van de aanwijzer herhaalt, kan de selectie omslaan wanneer de aanwijzer een andere vorm kruist. Door ook de oorspronkelijke verschuiving tussen aanwijzer en middelpunt te bewaren, voorkom je dat de vorm verspringt zodat het middelpunt ineens onder de aanwijzer komt. Dit zijn ontwerpregels voor de app; Canvas biedt dit niet automatisch.
Uitgewerkt voorbeeld: overlapdetectie versus geblokkeerde beweging
Neem twee cirkels als voorbeeld, elk met een straal van 20 punten. Cirkel A begint op (100, 100) en stilstaande cirkel B staat op (200, 100). De gebruiker vraagt om het middelpunt van A naar (190, 100) te verplaatsen. De afstand tussen de middelpunten zou 10 punten zijn; de som van de stralen is 40. De voorgestelde positie veroorzaakt dus overlap.
Bij een overlapindicator accepteer je de voorgestelde positie en pas je de weergave aan. Bij een horizontale, geblokkeerde sleep is de eerste raakpositie (160, 100): de middelpunten liggen dan 40 punten uit elkaar. Deze berekening veronderstelt dat B stil blijft staan, beide cirkels even groot blijven en A een horizontaal traject volgt.
Stel nu dat één update van de aanwijzer (260, 100) aanvraagt. Alleen dat eindpunt controleren levert geen overlap op, hoewel het bewegingstraject door B loopt. Een implementatie die de beweging blokkeert, moet het volledige traject op doorsnijdingen controleren of een andere expliciete methode gebruiken om het tussenliggende pad te controleren. Alleen overlappende eindpunten afwijzen implementeert niet ‘stoppen bij de eerste hindernis’.
Dit voorbeeld is de belangrijkste reden om de botsingsreactie precies te definiëren. Een paar geometrische tests op eindpunten kunnen voldoende zijn voor een functie die overlap markeert. Ondersteuning voor om obstakels heen glijden, gelijktijdige contacten of bewegende naburige vormen maakt de aangepaste oplosser aanzienlijk uitgebreider. Canvas blijft een optie om te tekenen, maar de app beheert dat extra gedrag.
Wanneer is SpriteKit een betere keuze?
SpriteKit wordt aantrekkelijk wanneer de botsingsreactie uit een simulatie moet voortkomen. Door een SKPhysicsBody aan een node te koppelen, kunnen berekeningen met zwaartekracht, wrijving en botsingen worden uitgevoerd; de simulatie werkt vervolgens de posities en oriëntaties van nodes bij. Het ondersteunt volumelichamen voor objecten en randlichamen voor grenzen. SKPhysicsBody
Gebruik voor een eerste prototype twee gescheiden cirkels en een rechthoekige grens voor de werkruimte. Geef de cirkels overeenkomende cirkelvormige lichamen, schakel zwaartekracht uit voor een werkruimte in tafelstijl en bepaal of rotatie iets toevoegt aan de interactie. Stel wrijving, restitutie en demping bewust in, in plaats van op de standaardwaarden te vertrouwen. Deze eigenschappen bepalen verschillende aspecten van het fysische gedrag. SKPhysicsBody
SwiftUI kan de scène rechtstreeks hosten met SpriteView, dat Apple documenteert als een SwiftUI-weergave die een SpriteKit-scène tekent. De gedocumenteerde beschikbaarheid ervan op de Mac begint bij macOS 11; die van Canvas begint bij macOS 12. De minimale doelversie hoort dus bij de keuze, al blijft interactiegedrag het belangrijkste criterium. SpriteView, Canvas
Configureer botsingsreacties los van meldingen
Wijs categorieën toe aan je vormen en grenzen en configureer vervolgens de twee interactiemaskers expliciet:
categoryBitMaskgeeft aan tot welke categorieën een lichaam behoort.collisionBitMaskselecteert de categorieën die dat lichaam fysiek kunnen beïnvloeden.contactTestBitMaskvraagt contactmeldingen aan voor geselecteerde categorieën.
Botsingsmaskers worden voor elk lichaam afzonderlijk geëvalueerd. Configureer voor de gewone wederzijdse reactie tussen twee dynamische vormen dat beide lichamen reageren op de categorie van het andere. Voor contactmeldingen geldt een andere regel: een overeenkomende vergelijking van categorie en contactmasker in een van beide richtingen kan een melding opleveren. Alleen meldingen inschakelen configureert geen fysieke blokkering. collisionBitMask, contactTestBitMask
Als lichamen fysiek op elkaar reageren maar er geen callback binnenkomt, controleer dan het contactmasker en de contactdelegate van de natuurkundige wereld. Als er callbacks binnenkomen terwijl vormen door elkaar heen bewegen, controleer dan de botsingsmaskers en de bewegingscontroller. Zo controleer je meldingsconfiguratie los van het daadwerkelijke bewegingsprobleem.
Welk onderdeel beheert de positie tijdens het slepen?
Voor slepen in SpriteKit is een expliciete controller nodig. De natuurkundige engine volgt niet vanzelf de aanwijzer. Kies directe plaatsing of beweging via de simulatie op basis van het eerder vastgestelde gedrag.
Bij directe plaatsing stelt applicatiecode de positie van de versleepte node in. Dit is geschikt wanneer de aanwijzer het item exact moet plaatsen, maar legt op zichzelf geen fysisch opgelost traject tussen opeenvolgende posities vast. Als je isDynamic uitschakelt, negeert het lichaam krachten en impulsen; daarmee creëer je geen sleepoplosser. Als je deze eigenschap tijdelijk wijzigt, bepaal dan wanneer je haar herstelt en of de beweging bij het loslaten behouden blijft of wordt gewist. isDynamic
Bij slepen via de simulatie bewaar je de locatie van de aanwijzer als doel en gebruik je krachten of een veercontroller om een dynamisch lichaam ernaartoe te sturen. De simulatie kan dan contacten oplossen terwijl het lichaam beweegt. De afweging is een bewuste vertraging of verplaatsing ten opzichte van de aanwijzer wanneer een ander object de beweging blokkeert. SpriteKit ondersteunt het toepassen van krachten en SKPhysicsJointSpring verbindt twee natuurkundige lichamen met veergedrag. Dit zijn bouwstenen die applicatiespecifieke afstemming vereisen. SKPhysicsBody, SKPhysicsJointSpring
Stel niet voortdurend aanwijzerposities in terwijl je verwacht dat de natuurkunde onafhankelijk dezelfde positie beheert. De gedocumenteerde framevolgorde van SpriteKit voert app-updates, acties, natuurkunde en daaropvolgende callbacks in afzonderlijke fasen uit. Een handige regel voor positiebeheer is: laat invoer het sleepdoel bijwerken, laat scenelogica de controller toepassen en laat de natuurkunde de uiteindelijke positie van het lichaam bepalen. Reageren op framecyclusgebeurtenissen
Contactcallbacks hebben ook een gedocumenteerde beperking. Apple zegt dat ze tijdens de simulatiestap voor de natuurkunde worden uitgevoerd. In die stap kun je de natuurkundige wereld niet wijzigen en zijn wijzigingen aan gesimuleerde lichamen ongedefinieerd gedrag. Leg in de callback werk vast dat later moet worden uitgevoerd en pas natuurkundige wijzigingen toe tijdens een volgende update, volgens Apples patroon van markeren en bijwerken. SKPhysicsContactDelegate
Hoe moet invoer op macOS de frameworkgrenzen oversteken?
Kies één eigenaar voor de invoer van de werkruimte. Een Canvas-implementatie kan een SwiftUI-DragGesture aan het interactieoppervlak koppelen. Een aangepast AppKit-oppervlak kan gebeurtenissen in de responderketen afhandelen; mouseDragged(with:) ontvangt bewegingen terwijl de linkermuisknop is ingedrukt. Voorkom dat een bovenliggende SwiftUI-beweging en een AppKit-handler hetzelfde geselecteerde item onafhankelijk verplaatsen. DragGesture, mouseDragged(with:)
Zet coördinaten om bij elke grens in een brug van AppKit naar SpriteKit. NSEvent.locationInWindow wordt doorgaans uitgedrukt in het basiscoördinatenstelsel van het bijbehorende venster. Zet dat punt om naar de coördinaten van de hostweergave en vervolgens van de weergave naar die van de scène. Apple biedt convertPoint(fromView:) voor die laatste stap en vereist dat de scène al wordt weergegeven voordat je deze aanroept. De positie van een node wordt uitgedrukt in het coördinatenstelsel van de bovenliggende node, dus bij geneste nodes kan nog een omzetting nodig zijn. locationInWindow, convertPoint(fromView:), position
Gebruik SpriteView voor eenvoudige hosting in SwiftUI. Als je een aangepaste AppKit-weergave nodig hebt, biedt NSViewRepresentable voorzieningen voor aanmaken, bijwerken, coördinatie en opruimen. Laat SwiftUI de indeling van de weergegeven weergave beheren: Apple waarschuwt expliciet om de beheerde frame of begrenzing niet zelf in te stellen. NSViewRepresentable
Bewaar de scène in een stabiele eigenaar in plaats van telkens een nieuwe scène te maken wanneer SwiftUI de weergave opnieuw opbouwt. Bewaar het itemmodel op dezelfde manier voor Canvas. De documentatie over modelbeheer van SwiftUI legt uit hoe beheerde status een instantie behoudt wanneer weergaven opnieuw worden aangemaakt; de Observation-aanpak vereist macOS 14 of nieuwer. Behandel scèneopdrachten en modelsnapshots als bewuste overdrachten, zodat twee veranderlijke kopieën niet met elkaar concurreren over de posities. Modelgegevens beheren in je app
Wat moet je testen voordat je een van beide opties kiest?
Gebruik een kleine synthetische werkruimte om lastige interacties te testen voordat je de visuele afwerking toevoegt:
- Pak een vorm dicht bij de rand vast en controleer of de oorspronkelijke verschuiving behouden blijft.
- Sleep langzaam tegen een ander item aan en herhaal dit met één grote beweging van de aanwijzer er dwars doorheen.
- Sleep naar een hoek met twee aangrenzende vormen.
- Laat los terwijl de vorm een ander item raakt en controleer of het verwachte uitdempen optreedt.
- Pas de grootte van de werkruimte aan en controleer de selectie, grenzen en coördinatenomzetting.
- Maak de omringende SwiftUI-inhoud opnieuw aan en controleer of de itemposities behouden blijven.
- Onderbreek een sleepbewerking en controleer of de selectie en tijdelijke natuurkundige instellingen worden opgeruimd.
Schakel in SpriteKit SKView.showsPhysics in en controleer of de geometrie van de natuurkundige lichamen overeenkomt met het bedoelde botsingsgebied. Evalueer voor kleine, snel bewegende lichamen usesPreciseCollisionDetection; Apple documenteert de hogere rekenkosten ervan en het vermogen om botsingen te detecteren die gewone controles per frame kunnen missen. Het vervangt geen samenhangende sleepcontroller. SKView, usesPreciseCollisionDetection
Kies Canvas wanneer je plaatsingsregels duidelijk, begrensd en eenvoudig rechtstreeks uit te drukken blijven. Kies SpriteKit wanneer fysieke interactie tussen vormen deel uitmaakt van de taak. Voor beide implementaties geldt: betrouwbaar slepen op een desktop begint met één geselecteerd item, expliciete coördinatenomzettingen en één onderdeel dat verantwoordelijk is voor elke positie-update.
Bronnen
- Canvas — Apple
- DragGesture — Apple
- DragGesture.Value — Apple
- Kiezen tussen structuren en klassen — Apple
- Over botsingen en contacten — Apple
- SKPhysicsBody — Apple
- SpriteView — Apple
- collisionBitMask — Apple
- contactTestBitMask — Apple
- isDynamic — Apple
- SKPhysicsJointSpring — Apple
- Reageren op framecyclusgebeurtenissen — Apple
- SKPhysicsContactDelegate — Apple
- mouseDragged(with:) — Apple
- locationInWindow — Apple
- convertPoint(fromView:) — Apple
- position — Apple
- NSViewRepresentable — Apple
- Modelgegevens beheren in je app — Apple
- SKView — Apple
- usesPreciseCollisionDetection — Apple