2013-02-01 6 views
5

मैं अपने ड्राइंग ऐप में ग्राफिक्स संदर्भ पर पूर्ववत संचालन करना चाहता हूं। जब पूर्ववत दबाया जाता है तो मैं पुराने संदर्भ में पिछले संदर्भ में जाना चाहता हूं।UIGraphicsContext को संग्रहीत करने के लिए आईओएस में पूर्ववत ऑपरेशन कैसे करें?

उदाहरण के लिए:

मैं संदर्भ में एक आयत है। खींचने पर, मैं आयताकार को एक नई स्थिति में ले जाता हूं और इसे फिर से चलाता हूं। अब जब मैं पूर्ववत बटन दबाता हूं तो मैं आयताकार को पिछली स्थिति में ले जाना चाहता हूं। मैं यह कैसे कर सकता हूँ?

मेरे पास NSUndoManager के बारे में केवल मूलभूत विचार है।

कृपया मदद करें!

धन्यवाद।

+0

क्या आप सही उपयोग कर रहे हैं। यदि हां, तो आप बेंज़ीर पथ या सामान्य रेखा का उपयोग कर रहे हैं।थोड़ी अधिक जानकारी की आवश्यकता है –

+0

मैं सही और सामान्य रेखाओं का उपयोग कर रहा हूं, कोई बेंज़ीर पथ नहीं। खींचने पर मैं आयताकार को एक नई स्थिति में ले जाता हूं और इसे फिर से चलाता हूं। अब जब मैं पूर्ववत बटन दबाता हूं तो मैं आयताकार की पिछली स्थिति में जाना चाहता हूं। –

+0

मुझे लगता है कि इस फ़ंक्शन का उपयोग करके आप "UIGraphicsPopContext" – Exploring

उत्तर

5

आपके द्वारा अनुमानित कार्यक्षमता वास्तव में मौजूद नहीं है। अलग-अलग रखें "ग्राफिक्स संदर्भ इस तरह से काम नहीं करते हैं (मुफ्त में)।" आपने UIGraphicsPushContext और UIGraphicsPopContext फ़ंक्शंस देखे होंगे, लेकिन वे जो भी आप यहां बात कर रहे हैं वह नहीं करते हैं। "पुश" और "पॉप" ऑपरेशंस वे ग्राफिक्स संदर्भ के गैर-प्रस्तुत किए गए पहलुओं पर काम करते हैं: वर्तमान भरने और स्ट्रोक रंग, क्लिप रेक्ट, और ट्रांसफॉर्म मैट्रिक्स उदाहरण के लिए। एक बार संदर्भ में कुछ प्रस्तुत किया जाता है - यानी एक पथ/rect/आदि। स्ट्रोक या भर दिया गया है, या एक छवि संदर्भ में मिश्रित किया गया है - यह हमेशा के लिए प्रस्तुत किया जाता है। "वापस जाने" का एकमात्र तरीका किसी भी तरह से पिछली स्थिति को फिर से बनाना है। दुर्भाग्यवश, UIGraphicsContext पर कोई जादू निर्मित नहीं है जो आपके लिए ऐसा करेगा।

इस बारे में जाने के कई तरीके हैं। जैसा कि एक और उपयोगकर्ता ने उल्लेख किया है, आप प्रत्येक उपयोगकर्ता कार्रवाई के बाद संदर्भ की स्थिति को कैप्चर कर सकते हैं। संक्षेप में, इसका मतलब है कि आपका दस्तावेज़ "मॉडल" एक बिटमैप स्टैक है। यह बहुत जल्दी गहन गहन हो जाएगा - बिटमैप्स स्मृति-भारी हैं। निश्चित रूप से ऑप्टिमाइज़ेशन हैं जो आप इस दृष्टिकोण से अधिक लाभ प्राप्त करने के लिए कर सकते हैं, जैसे कि प्रत्येक फ्रेम के बीच बदल गए क्षेत्र को सहेजना, बिटमैप्स को संपीड़ित करना, डिस्क पर उन्हें स्वैप करना आदि। वास्तविक, उपयोग करने योग्य ऐप्स हैं ऐप स्टोर जो इस दृष्टिकोण का उपयोग कर काम करता है, लेकिन दृष्टिकोण स्वाभाविक रूप से सीमित है, और आप पूर्ववत राज्यों के अपने सहेजे गए ढेर को अनुकूलित और प्रबंधित करने में गैर-मामूली प्रयासों को समाप्त कर देंगे।

स्वाभाविक रूप से, विचार करने के लायक अन्य दृष्टिकोण हैं।सबसे सरल यह है कि आपका वास्तविक दस्तावेज़ मॉडल छोटे (यानी गैर-बिटमैप) डेटा संरचनाओं का ढेर होना चाहिए जो संदर्भ की स्थिति को फिर से बनाने के लिए आवश्यक संचालन का वर्णन करते हैं। जब उपयोगकर्ता अनदेखा करता है, तो आप बस स्टैक के शीर्ष पर ऑपरेशन को हटाते हैं और शेष स्टैक को वापस चलाकर ग्राफिक्स संदर्भ को फिर से बनाते हैं। यह "योजक" प्रकार के अनुप्रयोगों के लिए एक सभ्य दृष्टिकोण है (सोचें "ब्रश") लेकिन कैनवास पर एक आकार को स्थानांतरित करने के वर्णन के सरल परिदृश्य में भी गिरना शुरू होता है। यह अंततः बिटमैप स्टैक दृष्टिकोण के समान मुद्दों से ग्रस्त है - आपके पास जितना अधिक संचालन होता है, उतना ही लंबे समय तक राज्य को फिर से बनाने के लिए होता है, इसलिए आप अनिवार्य रूप से बिटमैप स्नैपशॉट्स को समय-समय पर समाप्त कर देते हैं।

ऑब्जेक्ट के लिए आपके द्वारा वर्णित कैनवास परिदृश्य ('आकृति आकार' ऑपरेशन), कई दृष्टिकोण भी हैं। एक क्लासिक दृष्टिकोण आपके दस्तावेज़ मॉडल को छोटे, अधिक विशिष्ट डेटा संरचनाओं का सेट होना होगा जो कैनवास की वर्तमान स्थिति का वर्णन करते हैं। Shape कक्षा आदि के बारे में सोचें। सबसे सरल मामले में, जब कोई उपयोगकर्ता कैनवास में आयताकार जोड़ता है, तो Shape उदाहरण आकार के जेड-ऑर्डर किए गए सरणी में जोड़ा जाता है। किसी भी समय आकृतियों की सूची में परिवर्तन होता है, संदर्भ जेड क्रम में प्रत्येक आकार को चित्रित करके पुन: उत्पन्न होता है। पूर्ववत कार्यक्षमता को प्राप्त करने के लिए, हर बार जब आप आकृतियों की सरणी को बदलते हैं, तो आप एक आमंत्रण रिकॉर्ड करने के लिए NSUndoManager का भी उपयोग करते हैं, जब वापस खेले जाते हैं, तो विपरीत ऑपरेशन होने का कारण बनता है।

यदि आपका आकार-ऐड आपरेशन इस तरह देखा:

[shapeArray insertObject: newShape atIndex: 5]; 

तो फिर तुम, एक ही समय में, इस के साथ क्या करना होगा NSUndoManager:

[[undoManager prepareInvocationWithTarget: shapeArray] removeObjectAtIndex: 5]; 

जब उपयोगकर्ता क्लिक पूर्ववत, NSUndoManager उस आमंत्रण को वापस चलाता है, और shapeArray को इसकी पूर्व स्थिति वापस कर दी जाती है। यह क्लासिक NSUndoManager पैटर्न है। यह अच्छी तरह से काम करता है, लेकिन कुछ नुकसान भी हैं। उदाहरण के लिए, एप टर्मिनेशन में पूर्ववत स्टैक को जारी रखने के लिए यह जरूरी नहीं है। चूंकि ऐप टर्मिनेशन आईओएस पर आम हैं, और उपयोगकर्ता आमतौर पर एक ऐप को टर्मिनेशन में पूरी तरह से राज्य को पुनर्स्थापित करने की अपेक्षा करते हैं, एक दृष्टिकोण जिसमें आपका पूर्ववत स्टैक नहीं टिकेगा ऐप टर्मिनेशन आपकी आवश्यकताओं के आधार पर एक गैर-स्टार्टर हो सकता है। अन्य, अधिक जटिल दृष्टिकोण हैं, लेकिन वे इन विषयों में से एक पर अधिकतर भिन्नताएं हैं। Gang of Four book, Design Patterns से Command Pattern के बारे में पढ़ने के लिए एक क्लासिक लायक है।

कोई फर्क नहीं पड़ता कि आप किस दृष्टिकोण को चुनते हैं, इस तरह के आवेदन को विकसित करने के लिए एक चुनौती होगी। यह ग्राफ़िक पूर्ववत कार्यक्षमता केवल कुछ नहीं है जो "मुक्त" के लिए UIGraphicsContext में बनाई गई है। आपने उदाहरण के लिए टिप्पणियों में कई बार पूछा है। मुझे यह कहने में खेद है, लेकिन यह एक जटिल पर्याप्त अवधारणा है कि किसी के लिए स्टैक ओवरफ्लो उत्तर की सीमाओं के भीतर एक कार्य उदाहरण प्रदान करने के लिए संभव नहीं है। उम्मीद है कि ये विचार और पॉइंटर्स सहायक हैं। निश्चित रूप से कुछ ओपन सोर्स ड्राइंग अनुप्रयोग भी हैं जिन्हें आप प्रेरणा के लिए देख सकते हैं (हालांकि मुझे आईओएस के लिए किसी भी ओपन सोर्स ड्राइंग एप्लिकेशन के बारे में व्यक्तिगत रूप से पता नहीं है।)

2

UIGraphicsContext में इसका अपना पूर्ववत ढेर नहीं है। आपको स्टैक पर जो भी चित्रित हो रहा है, उसके प्रत्येक तत्व को स्टोर करने की आवश्यकता है, और उस स्टैक से आइटम को पूर्ववत करें और फिर से करें। NSUndoManager कक्षा पूर्ववत और फिर से संचालन के लिए तर्क को प्रबंधित करने में आपकी सहायता कर सकती है, लेकिन यह कोड लिखने की आपकी ज़िम्मेदारी है जो ड्रॉइंग एक्शन को स्टैक पर सहेजती है और फिर -drawRect: में ड्राइंग को फिर से बनाने के लिए इसे पढ़ती है।

+0

क्या आप मुझे एक नमूना उदाहरण प्रदान कर सकते हैं कृपया! –

1

सबसे पहले अनावश्यक वस्तु सेट करें और इसे उपयोग के लिए प्रारंभ करें।

NSUndoManager *undoObject; 
undoObject =[[NSUndoManager alloc] init]; 

uigraphics संदर्भ, हर बार जब संदर्भ बदल गया है को बचाने के लिए लक्ष्य समारोह के साथ पूर्ववत वस्तु रजिस्टर।

[[undoObject prepareWithInvocationTarget:self] performUndoWithObject:currentContext withLastpoint:lastPoint andFirstPoint:firstPoint]; 

लिखें UserDefined समारोह परिभाषा

-(void)performUndoWithObject:(CGContextRef)context withLastpoint:(CGPoint)previousLastPoint andFirstPoint:(CGPoint)previousFirstPoint 
{ 
    // necessary steps for undoing operation 
} 

कार्यवाही निर्धारित की है जब एक पूर्ववत करें बटन पर क्लिक किया जाता है।

-(void)undoButtonClicked 
{ 
    if([undoObject canUndo]) 
    { 
     [undoObject undo]; 
    } 
} 
1

उद्देश्य सी में पूर्ववत और फिर से संचालन कैसे करें आईओएस में मूल्य सरणी स्टोर करने के लिए। और मैंने स्ट्रिंग वैल्यू में अंडो और रेडो बटन काम में छोटा डेमो बनाया है। ViewController.h फ़ाइलें में दो NSMutableArray बनाएं

@interface ViewController : UIViewController<UITextFieldDelegate> 
{ 
    NSMutableArray *arrUndo, *arrRedo; 
} 
@property (weak, nonatomic) IBOutlet UIButton *btnUndo; 
@property (weak, nonatomic) IBOutlet UIButton *btnRedo; 
@property (weak, nonatomic) IBOutlet UITextField *txtEnterValue; 
@property (weak, nonatomic) IBOutlet UILabel *lblShowUndoOrRedoValue; 
@property (weak, nonatomic) IBOutlet UIButton *btnOK; 
- (IBAction)btnUndo:(id)sender; 
- (IBAction)btnRedo:(id)sender; 
- (IBAction)btnOK:(id)sender; 
@end 

ViewController.m फ़ाइलें लागू पूर्ववत में दो बटन कार्रवाई विधि जोड़ें या फिर से करना।

- (void)viewDidLoad { 
    [super viewDidLoad]; 
    self.txtEnterValue.delegate = self; 
    arrUndo = [[NSMutableArray alloc] init]; 
    arrRedo = [[NSMutableArray alloc] init]; 
} 
-(BOOL)canBecomeFirstResponder { 
    return YES; 
} 
- (IBAction)btnOK:(id)sender { 

    NSString *str = [NSString stringWithFormat:@"%@", [self.txtEnterValue.text description]]; 
    self.txtEnterValue.text = nil; 
    self.lblShowUndoOrRedoValue.text = str; 
    [arrUndo addObject:str]; 
    NSLog(@"Text Value : %@", [arrUndo description]); 
} 
- (IBAction)btnUndo:(id)sender { 

    if ([arrUndo lastObject] == nil) { 
     NSLog(@"EMPTY"); 
    } 
    else 
    { 
    [arrRedo addObject:[arrUndo lastObject]]; 
    NSLog(@"ArrAdd %@", [arrUndo description]); 

    [arrUndo removeLastObject]; 
    for (NSObject *obj in arrUndo) { 
     if ([arrUndo lastObject] == obj) { 

      self.lblShowUndoOrRedoValue.text = obj; 
     } 
    } 
    NSLog(@"ArrText %@", [arrUndo description]); 
    } 
} 
- (IBAction)btnRedo:(id)sender { 

    if ([arrRedo lastObject] == nil) { 
     NSLog(@"EMPTY"); 
    } 
    else 
    { 
    [arrUndo addObject:[arrRedo lastObject]]; 
    for (NSObject *obj in arrRedo) { 
     if ([arrRedo lastObject] == obj) { 

      self.lblShowUndoOrRedoValue.text = obj; 

     } 
    } 
    } 
    [arrRedo removeLastObject]; 
} 
संबंधित मुद्दे