2010-08-02 50 views
6

我有一個繪圖應用程序,我想創建一個撤消方法。繪圖發生在TouchesMoved:方法內部。保存CGContextRef

我想創建一個CGContextRef並將其推送到堆棧或將其保存在可以稍後恢復的上下文屬性中,但沒有任何運氣。任何建議都會很棒。以下是我有...

UIImageView  *drawingSurface; 
CGContextRef  undoContext; 


- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { 
UIGraphicsBeginImageContext(self.view.frame.size); 
CGContextRef context = UIGraphicsGetCurrentContext(); 
[drawingSurface.image drawInRect:CGRectMake(0, 0, drawingSurface.image.size.width, drawingSurface.image.size.height)]; 
UIGraphicsPushContext(context); 

     // also tried but cant figure how to restore it 
     undoContext = context; 

UIGraphicsEndImageContext(); 
} 

然後我就用我的復原按鈕,觸發一個方法...

- (IBAction)restoreUndoImage { 
UIGraphicsBeginImageContext(self.view.frame.size); 
UIGraphicsPopContext(); 
drawingSurface.image = UIGraphicsGetImageFromCurrentImageContext(); 
UIGraphicsEndImageContext(); 
} 

當我運行這一點,我相信我的drawingSurface被分配爲零,因爲它只是刪除圖像中的所有內容。

我的猜測是我不能用pop和push這種方式。但我似乎無法弄清楚如何保存上下文,然後將其推回到drawingSurface上。 Hmmmm。任何幫助將會......很好......有幫助。在此先感謝 -

而且,僅供參考,這是我正在做的畫在屏幕上,這是偉大的工作。這是我的TouchesMoved內:

UIGraphicsBeginImageContext(self.view.frame.size); 
CGContextRef context = UIGraphicsGetCurrentContext(); 
[drawingSurface.image drawInRect:CGRectMake(0, 0, drawingSurface.image.size.width, drawingSurface.image.size.height)]; 

CGContextSetLineCap(context, kCGLineCapRound); //kCGLineCapSquare, kCGLineCapButt, kCGLineCapRound 
CGContextSetLineWidth(context, self.brush.size); // for size 

CGContextSetStrokeColorWithColor (context,[currentColor CGColor]); 

CGContextBeginPath(context); 
CGContextMoveToPoint(context, lastPoint.x, lastPoint.y); 
CGContextAddLineToPoint(context, currentPoint.x, currentPoint.y); 
CGContextStrokePath(context); 
drawingSurface.image = UIGraphicsGetImageFromCurrentImageContext(); 
UIGraphicsEndImageContext(); 

回答

1

我想你接近這個問題的錯誤的方式和混亂的環境。

在即時模式API中,您可以使用push/pop保存對象的'狀態',而不是圖形表示。狀態由線寬,顏色和位置組成。圖形表示是繪製操作(位圖)的結果,通常是您不想保存的內容。

請嘗試保存用於創建圖形的「信息」。

我最初的建議是解耦你的形狀創建和繪畫。在OSX上,您可以使用NSBezierPath,但對於iOS,我們必須使用一組點。

例如,給定此協議:

// ViewController.h 
@protocol DrawSourceProtocol <NSObject> 
- (NSArray*)pathsToDraw; 
@end 

@interface ViewController : UIViewController<DrawSourceProtocol> 
@end 

您可以實現以下功能:

// ViewController.m 
@interface ViewController() { 
    NSMutableArray *currentPath; 
    NSMutableArray *allPaths; 
    MyView *view_; 
} 
@end 

... 

- (void)viewDidLoad { 
    [super viewDidLoad]; 
    currentPath = [[NSMutableArray alloc] init]; 
    allPaths = [[NSMutableArray alloc] init];  
    view_ = (MyView*)self.view; 
    view_.delegate = self; 
} 

- (NSArray*)pathsToDraw { 
    // Return the currently draw path too 
    if (currentPath && currentPath.count) { 
    NSMutableArray *allPathsPlusCurrent = [[NSMutableArray alloc] initWithArray:allPaths]; 
    [allPathsPlusCurrent addObject:currentPath]; 
    return allPathsPlusCurrent; 
    } 
    return allPaths; 
} 

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { 
    currentPath = [[NSMutableArray alloc] init]; 
} 

- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { 
    // When a touch ends, save the current path 
    [allPaths addObject:currentPath]; 
    currentPath = [[NSMutableArray alloc] init]; 
    [view_ setNeedsDisplay];  
} 

- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event { 
    UITouch *touch = [touches anyObject]; 
    CGPoint currentPoint = [touch locationInView:self.view]; 

    // We store the point with the help of NSValue 
    [currentPath addObject:[NSValue valueWithCGPoint:currentPoint]]; 

    // Update the view 
    [view_ setNeedsDisplay]; 
} 

現在繼承你的觀點(我稱之爲我的MyView的位置),並執行這樣的事情:

// MyView.h 
#import "ViewController.h" 

@protocol DrawSourceProtocol; 

@interface MyView : UIView { 
    __weak id<DrawSourceProtocol> delegate_; 
} 
@property (weak) id<DrawSourceProtocol> delegate; 
@end 

// MyView.m 

@synthesize delegate = delegate_; 

... 

- (void)drawRect:(CGRect)rect { 
    NSLog(@"Drawing!"); 

    // Setup a context 
    CGContextRef context = UIGraphicsGetCurrentContext(); 
    CGContextSetStrokeColorWithColor(context, [UIColor redColor].CGColor); 
    CGContextSetRGBFillColor(context, 0.0, 0.0, 1.0, 1.0); 
    CGContextSetLineWidth(context, 2.0); 

    // Get the paths 
    NSArray *paths = [delegate_ pathsToDraw]; 

    for (NSArray *aPath in paths) { 
    BOOL firstPoint = TRUE; 
    for (NSValue *pointValue in aPath) { 
     CGPoint point = [pointValue CGPointValue]; 

     // Always move to the first point 
     if (firstPoint) { 
     CGContextMoveToPoint(context, point.x, point.y); 
     firstPoint = FALSE; 
     continue; 
     } 

     // Draw a point 
     CGContextAddLineToPoint(context, point.x, point.y); 
    } 
    } 

    // Stroke! 
    CGContextStrokePath(context); 
} 

這裏唯一的缺點是setNeedsDisplay不是很高效。最好使用setNeedsDisplayInRect :,看看我的最後一篇關於an efficient way of determining the 'drawn' rect的帖子。

至於撤消?您的撤消操作僅僅是從allPaths數組中彈出最後一個對象。這個練習我會留給你:)

希望這會有所幫助!

+1

神奇的,深思熟慮的答案。不知道爲什麼OP不接受這一點。 – Tim 2012-05-31 21:35:44