La funzionalità che stai inferendo non esiste realmente. Metti diversamente "I contesti grafici non funzionano in questo modo (gratuitamente)." Potresti aver visto le funzioni UIGraphicsPushContext
e UIGraphicsPopContext
, ma non fanno quello di cui stai parlando qui. Le operazioni "push" e "pop" che rappresentano operano sugli aspetti non ancora sottoposti al rendering del contesto grafico: i colori di riempimento e di traccia correnti, il rettangolo di ritaglio e la matrice di trasformazione, ad esempio. Una volta qualcosa viene reso nel contesto - cioè un percorso/retto/ecc. è stato accarezzato o riempito, o un'immagine è stata composta nel contesto - è resa per sempre. L'unico modo per "tornare indietro" è in qualche modo ricreare lo stato precedente. Sfortunatamente, non esiste una magia incorporata in UIGraphicsContext
che lo farà accadere per te.
Ci sono diversi modi per farlo. Come menzionato da un altro utente, puoi catturare lo stato del contesto dopo ogni azione dell'utente. In breve, ciò significa che il tuo documento "modello" è uno stack bitmap. Questo richiederà molto tempo per la memoria molto rapidamente - le bitmap sono pesanti per la memoria. Ci sono certamente delle ottimizzazioni che puoi fare con questo approccio per ottenere più chilometri da esso, come solo salvare la regione che è cambiata tra ogni frame, comprimere le bitmap, scambiarle su disco, ecc. Esistono app reali e utilizzabili nel App Store che funziona con questo approccio, ma l'approccio è intrinsecamente limitato e finirai per spendere sforzi non banali nell'ottimizzazione e nella gestione del tuo stack salvato di stati di annullamento.
Ci sono, naturalmente, altri approcci che vale la pena considerare.Il modo più semplice è di avere il modello di documento reale come una pila di piccole strutture di dati (cioè non bitmap) che descrivono le operazioni necessarie per ricreare lo stato del contesto. Quando l'utente annulla, è sufficiente rimuovere l'operazione in cima allo stack e ricreare il contesto grafico riproducendo lo stack rimanente. Questo è un approccio decente per le applicazioni di tipo "additivo" (si pensi ai "Pennelli") ma inizia a cadere anche nel semplice scenario che descrivi di spostare una forma su una tela. Inoltre definitiva soffre di alcuni degli stessi problemi approccio pila bitmap - più operazioni hai, più il tempo di ricreare lo stato, quindi si finisce inevitabilmente per fare periodicamente istantanee bitmap, ecc
per oggetto -setti scenari su tela come hai descritto tu (l'operazione 'move shape'), ci sono anche approcci multipli. Un approccio classico sarebbe quello di fare in modo che il modello del documento sia un insieme di strutture di dati più piccole e più specifiche che descrivono lo stato corrente della tela. Pensa a una classe Shape
e così via. Nel caso più semplice, quando un utente aggiunge un rettangolo all'area di disegno, un'istanza Shape
viene aggiunta a un array ordinato di z di forme. Ogni volta che l'elenco delle forme cambia, il contesto viene rigenerato disegnando ogni forma nell'ordine Z. Per ottenere la funzionalità di annullamento, ogni volta che si modifica la matrice di forme, si utilizza anche lo NSUndoManager
per registrare una chiamata che, quando viene riprodotta, causerebbe l'operazione inversa.
Se l'operazione di forma-add si presentava così:
[shapeArray insertObject: newShape atIndex: 5];
poi si sarebbe, allo stesso tempo, farlo con il NSUndoManager
:
[[undoManager prepareInvocationWithTarget: shapeArray] removeObjectAtIndex: 5];
Quando l'utente fa clic undo, il NSUndoManager
riproduce tale chiamata e lo shapeArray
viene restituito come stato precedente. Questo è il classico motivo NSUndoManager
. Funziona bene, ma ha anche alcuni svantaggi. Ad esempio, non è necessariamente semplice mantenere lo stack di annullamento attraverso le terminazioni delle app. Poiché le terminazioni delle app sono comuni su iOS, e in genere gli utenti si aspettano che un'app ripristini perfettamente lo stato tra le terminazioni, un approccio in cui lo stack di annullamento non sopravviverà alle terminazioni delle app potrebbe non essere di partenza, a seconda delle esigenze. Esistono altri approcci più complessi, ma sono principalmente variazioni su uno di questi temi. Un classico che vale la pena leggere è lo Command Pattern dello Gang of Four book, Design Patterns.
Indipendentemente dall'approccio scelto, questo tipo di applicazione sarà una sfida da sviluppare. Questa funzionalità di annullamento grafico non è semplicemente integrata in UIGraphicsContext
per "gratuito". Hai chiesto più volte nei commenti per un esempio. Mi dispiace dirlo, ma questo è un concetto abbastanza complesso che è improbabile che qualcuno possa fornire un esempio funzionante entro i limiti di una risposta StackOverflow. Speriamo che queste idee e questi suggerimenti siano utili. Esistono sicuramente anche un numero illimitato di applicazioni di disegno open source da cui puoi trarre ispirazione (anche se non sono personalmente a conoscenza di alcuna applicazione di disegno open source per iOS.)
stai usando drawrect. Se sì, stai usando il percorso benzier o la linea normale.Ho bisogno di un po 'di ulteriori informazioni –
sto usando drawrect e linee normali, nessun percorso benzier. durante il trascinamento sposto il rettangolo in una nuova posizione e lo ridisegno. ora quando premo il pulsante Annulla voglio passare alla posizione precedente del rettangolo. –
Penso che usando questa funzione puoi "UIGraphicsPopContext" – Exploring