2012-12-06 65 views
4

多年來一直困擾着問題。希望我能在這裏得到答案。我用this鏈接來平滑我的自由手繪。在這段代碼中,我可以設置線條寬度和顏色,但是當我嘗試使用this鏈接包含撤銷/重做特技時,我發現它非常困難,該鏈接在恢復重做時工作正常,但其自由伸展不平滑。不能包含撤消/重做與光滑的自由手繪

經過一番研究和編碼後,我才知道它的繪圖導航是我認爲防止撤銷/重做。

在第一鏈路有一個文件「CachedLIView.h /米」當我用這一點,並嘗試包括撤消/恢復在此,我發現,在下面的方法:

- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event // (2) 
{ 
    UITouch *touch = [touches anyObject]; 
    CGPoint p = [touch locationInView:self]; 
    [path addLineToPoint:p]; 

    [self drawBitmap]; // (3) 
    [self setNeedsDisplay]; 

    [path removeAllPoints]; //(4) 
} 

此方法正在調用drawBitMap:方法,每次用戶擡起手指並同時從「路徑」移除點時,該方法實際上會生成臨時圖像。

- (void)drawBitmap // (3) 
{ 
    UIGraphicsBeginImageContextWithOptions(self.bounds.size, YES, 0.0); 
    [[UIColor blackColor] setStroke]; 
    if (!incrementalImage) // first draw; paint background white by ... 
    { 
     UIBezierPath *rectpath = [UIBezierPath bezierPathWithRect:self.bounds]; // enclosing bitmap by a rectangle defined by another UIBezierPath object 
     [[UIColor greenColor] setFill]; 
     [rectpath fill]; // filling it with white 
    } 
    [incrementalImage drawAtPoint:CGPointZero]; 
    //[path stroke]; 
    for (UIBezierPath *_path in pathArray) 
     [_path strokeWithBlendMode:kCGBlendModeNormal alpha:1.0]; 
    incrementalImage = UIGraphicsGetImageFromCurrentImageContext(); 
    UIGraphicsEndImageContext(); 
} 

我保存數組中的每條路徑,以便我可以撤銷/重做。 (從第二個鏈接中獲得了這個想法)。下面

是這個文件,我已經修改,包括撤銷/重做的完整代碼:

#import "CachedLIView.h" 

@implementation CachedLIView 
{ 
    UIBezierPath *path; 
    UIImage *incrementalImage; // (1) 
} 

- (id)initWithFrame:(CGRect)frame // (1) 
{ 
    if (self = [super initWithFrame:frame]) 
    { 
     [self setMultipleTouchEnabled:NO]; // (2) 
     //  [self setBackgroundColor:[UIColor whiteColor]]; 
//    path = [[UIBezierPath alloc] init]; 
//    [path setLineWidth:3]; 

     pathArray=[[NSMutableArray alloc]init]; 
     bufferArray=[[NSMutableArray alloc]init]; 
     [self drawBitmap]; 
    } 
    return self; 
} 

- (void)drawRect:(CGRect)rect 
{ 
    NSLog(@"in drawrect pathArray[count]: %d", pathArray.count); 

    [incrementalImage drawInRect:rect]; // (3) 

    //[[UIColor blackColor] setStroke]; 
    //[path stroke]; 
    for (UIBezierPath *_path in pathArray) 
     [_path strokeWithBlendMode:kCGBlendModeNormal alpha:1.0]; 
} 


- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event 
{ 
    path = [[UIBezierPath alloc] init]; 
    path.lineWidth = 3; 

    UITouch *touch = [touches anyObject]; 
    CGPoint p = [touch locationInView:self]; 
    [path moveToPoint:p]; 

    [pathArray addObject:path]; 

} 

- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event 
{ 
    UITouch *touch = [touches anyObject]; 
    CGPoint p = [touch locationInView:self]; 
    [path addLineToPoint:p]; 


    [self setNeedsDisplay]; 
} 

- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event // (2) 
{ 
    UITouch *touch = [touches anyObject]; 
    CGPoint p = [touch locationInView:self]; 
    [path addLineToPoint:p]; 

    [self drawBitmap]; // (3) 
    [self setNeedsDisplay]; 

    [path removeAllPoints]; //(4) 
} 

- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event 
{ 
    [self touchesEnded:touches withEvent:event]; 
} 

- (void)drawBitmap // (3) 
{ 
    UIGraphicsBeginImageContextWithOptions(self.bounds.size, YES, 0.0); 
    [[UIColor blackColor] setStroke]; 
    if (!incrementalImage) // first draw; paint background white by ... 
    { 
     UIBezierPath *rectpath = [UIBezierPath bezierPathWithRect:self.bounds]; // enclosing bitmap by a rectangle defined by another UIBezierPath object 
     [[UIColor greenColor] setFill]; 
     [rectpath fill]; // filling it with white 
    } 
    [incrementalImage drawAtPoint:CGPointZero]; 
    //[path stroke]; 
    for (UIBezierPath *_path in pathArray) 
     [_path strokeWithBlendMode:kCGBlendModeNormal alpha:1.0]; 
    incrementalImage = UIGraphicsGetImageFromCurrentImageContext(); 
    UIGraphicsEndImageContext(); 
} 

#pragma mark - undo/redo 
-(void)undoButtonClicked 
{ 
    if([pathArray count]>0){ 
     UIBezierPath *_path=[pathArray lastObject]; 
     [bufferArray addObject:_path]; 
     [pathArray removeLastObject]; 

     [self drawBitmap]; 
     [self setNeedsDisplay]; 
    } 
} 

-(void)redoButtonClicked 
{ 
    if([bufferArray count]>0){ 
     UIBezierPath *_path=[bufferArray lastObject]; 
     [pathArray addObject:_path]; 
     [bufferArray removeLastObject]; 

     [self drawBitmap]; 
     [self setNeedsDisplay]; 
    } 
} 
@end 

h文件是:

#import <UIKit/UIKit.h> 

@interface CachedLIView : UIView 
{ 
    NSMutableArray *pathArray; 
    NSMutableArray *bufferArray; 
    UIBezierPath *myPath; 

} 
-(void)undoButtonClicked; 
-(void)redoButtonClicked; 
@end 

請幫助我。我做錯了什麼。 pathArray計數工作正確。但無法在屏幕上顯示撤銷/重做效果。

回答

1

最後,我明白了,並且能夠順利drawiwith撤消/重做功能。 這是drawBitMap方法將其導致問題..

我刪除(註釋)在調用此[自drawBitmap]方法無處不在。

我在touchesEnded和undo/redo方法中調用了這個方法。我覺得不需要使用這種方法,因爲當用戶從屏幕上擡起他的指尖時,它會進行緩存(加速繪圖),創建新的圖像並將其放置在屏幕上,舊的圖像被刪除,並且用戶有幻想他是不斷繪圖。但是這種緩存只在極端情況下需要,當你真的想提高性能時(如果你的內存不足並且繪圖開始變得難看)。

所以我決定在稍後階段保存這個緩存機制並將其刪除。雖然我無法找出爲什麼我的撤銷/重做功能不能使用它,但我認爲當我有一個新的圖像緩存,當它被放置在屏幕上(當用戶提起fingere時),然後它創造了問題,因爲我必須保留上次緩存的圖像(用於撤消/重做)。

我將在稍後的階段使用緩存,並嘗試優化我的代碼。

還記得要刪除[myPath removeAllPoints];這條線來自touchesEnded:方法,除此之外,一旦你擡起你的指尖,你的繪圖就會消失。

希望這會幫助別人。 這裏是touchesEnded:修改的方法。

- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event // (2) 
{ 
     UITouch *touch = [touches anyObject]; 
CGPoint p = [touch locationInView:self]; 
[path addLineToPoint:p]; 

    //[self drawBitmap]; // CAUSES PROBLEM IF UNCOMMENTED AND UNDO/REDO WILL STOP WORKING.. 
    [self setNeedsDisplay]; 


    //[myPath removeAllPoints];// LINE GETS DRAWN BUT VANISHED WHEN TOUCH LIFTED OFF FROM SCREEN.. 
    ctr = 0; 
} 

後來我將這個功能添加到了SmoothedBIView中,它的工作非常好。

+1

令人難以置信的有用!非常感謝你!!另外,什麼是ctr?我認爲這是你個人項目中的一些東西,因爲它與我的一切無關。 –

+0

你可以暫時忽略ctr ..是的,它是我的項目的一部分.. – Rakesh

2

嘿,我不能老是讓你的整個代碼,但我可以建議你如何才能實現這樣的事情,

重做和撤消寫意描繪你可以capture image render在觸摸的時候就開始或觸摸結束並且manage stack of that renders。然後根據您的要求(重做/撤消)使用您的緩存中的渲染。所以步驟如下:

1)當你觸摸你的主板時捕獲渲染並保存。並在緩存中管理該序列。

  • 因此,對於每次觸摸開始,您必須捕捉圖像並按順序保存。

2)當您按下撤消在那個時候得到您最後渲染和替換您的董事會。 3)對於重做,你可以檢查是否有更高的渲染可用,然後你當前的替換渲染。意味着您可以通過最後更新的渲染來啓用和禁用該按鈕。

4)完成保存圖像後,不要忘記清空緩存,因此您可以管理下一張圖紙的堆疊。


  • 讓我知道,如果你沒有得到這個想法。