无法使用平滑的自由手绘图来包含撤消/重做

时间:2012-12-06 13:01:24

标签: iphone drawrect quartz-core

多日来一直在努力解决问题。希望我能在这里得到答案。我使用this链接来平滑我的自由手绘图。在这段代码中,我能够设置线宽和颜色,但是当我尝试使用this链接在其中包含undo / redo feauture时,我发现它非常困难,这在undo redo上正常工作但是它的自由手dreawing是不光滑。

经过一些研究和编码,我知道它的绘图的阴影,我认为防止撤消/重做。

在第一个链接中有一个文件“CachedLIView.h / m”当我使用它并尝试在其中包含undo / redo时,我发现在以下方法中:

- (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();
}

我正在保存数组中的每个路径,以便我可以执行撤消/重做。 (从第二个链接中获取此想法)。

下面是我已修改为包含undo / redo:

的此文件的完整代码
    #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计数工作正常。但无法在屏幕上显示撤消/重做效果。

2 个答案:

答案 0 :(得分:2)

嘿,我不能得到你的整个代码,但我可以建议你我们怎样才能实现这些东西,

对于徒手画图像中的重做和撤消,您可以在触摸开始时触摸 capture image render 或触摸结束并 manage stack of that renders 。然后根据您的要求(重做/撤消)从缓存内存中使用该渲染。所以步骤就像,

1)当您触摸电路板时捕获渲染并保存。并在缓存中管理该序列。

  • 因此,对于每次触摸开始,您必须捕获图像并按顺序保存。

2)当你按下撤销时,获取最后一次渲染并用你的电路板替换它。

3)对于重做,您可以检查是否有更高的渲染可用,然后您当前替换渲染。表示您可以通过最后更新的渲染启用和禁用该按钮。

4)完成保存图像后不要忘记清空缓存,这样就可以管理堆栈以进行下一次绘图。


  • 如果你没有得到这个想法,请告诉我。

答案 1 :(得分:1)

最后我得到它并且能够平滑地使用撤消/重做功能。 这是导致问题的 drawBitMap 方法。

我删除(评论过)对此[self 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,它的工作非常好。