2010-05-04 3 views
1

Je crée une application de dessin simple et je voudrais de l'aide pour dessiner des rectangles basés sur les événements tactiles de l'utilisateur. Je suis en mesure de dessiner un rectangle en utilisant Core Graphics à partir du point dans touchesBegan au point dans touchesEnded. Ce rectangle est ensuite affiché une fois que l'événement touchesEnded est déclenché. Cependant, je voudrais pouvoir le faire de manière «live». Ce qui signifie que le rectangle est mis à jour et affiché lorsque l'utilisateur fait glisser son doigt. Est-ce possible? Toute aide serait grandement appréciée, merci!Dessiner un rectangle en utilisant Core Graphics avec un aperçu en direct

MISE À JOUR:

j'ai pu obtenir que cela fonctionne en utilisant le code suivant. Il fonctionne parfaitement bien pour les petites images, mais il devient très lent pour les grandes images. Je réalise que ma solution est extrêmement inefficace et je me demandais si quelqu'un pouvait proposer une meilleure solution. Merci.

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event 
    { 
     UITouch *touch = [touches anyObject]; 
     _firstPoint = [touch locationInView:self.view]; 
     _firstPoint.y -= 40; 
     _lastPoint = _firstPoint; 
    } 

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

     [self drawSquareFrom:_firstPoint to:currentPoint]; 

     _lastPoint = currentPoint; 
    } 

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

     [self drawSquareFrom:_firstPoint to:currentPoint]; 

     [_modifiedImage release]; 
     _modifiedImage = [[UIImage alloc] initWithCGImage:_imageView.image.CGImage]; 
    } 

    - (void)drawSquareFrom:(CGPoint)firstPoint to:(CGPoint)lastPoint 
    { 
     _imageView.image = _modifiedImage; 

     CGFloat width = lastPoint.x - firstPoint.x; 
     CGFloat height = lastPoint.y - firstPoint.y; 

     _path = [UIBezierPath bezierPathWithRect:CGRectMake(firstPoint.x, firstPoint.y, width, height)]; 

     UIGraphicsBeginImageContext(_originalImage.size); 
     [_imageView.image drawInRect:CGRectMake(0, 0, _originalImage.size.width, _originalImage.size.height)]; 

     _path.lineWidth = 10; 
     [[UIColor redColor] setStroke]; 
     [[UIColor clearColor] setFill]; 
     [_path fill]; 
     [_path stroke]; 

     _imageView.image = UIGraphicsGetImageFromCurrentImageContext(); 
     UIGraphicsEndImageContext(); 
    } 
+0

(c'est-à-dire Illustrator ou Photoshop) Dans ce cas, vous pouvez facilement ajouter un CAShapeLayer avec un chemin rectangulaire à votre document temporairement ... le valider dans votre document lorsque l'utilisateur a fini de le faire glisser. – nielsbot

+0

Dans tous les cas, vous pouvez prévisualiser votre rectangle en utilisant un CAShapeLayer avec un chemin rectangulaire sur votre image actuelle dans votre document. – nielsbot

Répondre

0

Ce que vous faites en ce moment est la création d'un apparié CGImage et CGBitmapContext pour chaque appel à drawSquareFrom:to: et les disposer à chaque fois. Au lieu de cela, créez un seul apparié CGImage et CGBitmapContext que vous réutilisez pour chaque appel.

-(void) drawSquareFrom:(CGPoint)from to:(CGPoint)to { 
    CGContextRef context = [self offscreenContext]; 
    CGRect draw , full = [self offscreenContextBounds]; 

    draw.origin = from; 
    draw.size.width = to.x - from.x; 
    draw.size.height = to.y - from.y; 
    draw = CGRectStandardize(draw); 

    [[UIColor redColor] setStroke]; 
    [[UIColor clearColor] setFill]; 
    CGContextClearRect(context , full); 
    CGContextFillRect(context , draw); 
    CGContextStrokeRectWithWidth(context , draw , 10); 
    [_imageView setNeedsDisplay]; 
} 

Vous créez un CGImage et CGContext comme celui-ci, bien qu'il existe quelques ... à remplir. Apparié Toutes les variables de myX sont destinés à être des membres de la classe.

-(CGContextRef) offscreenContext { 
    if (nil == myContext) { 
     size_t width = 400; 
     size_t height = 300; 
     CFMutableDataRef data = CFDataCreateMutable(NULL , width * height * 4); // 4 is bytes per pixel 
     CGDataProviderRef provider = CGDataProviderCreateWithCFData(data); 
     CGImageRef image = CGImageCreate(width , height , ... , provider , ...); 
     CGBitmapContextRef context = CGBitmapContextCreate(CFDataGetMutableBytePtr(data) , width , height , ...); 
     CFRelease(data); // retained by provider I think 
     CGDataProviderRelease(provider); // retained by image 

     myImage = image; 
     myContext = context; 
     myContextFrame.origin = CGPointZero; 
     myContextFrame.size.width = width; 
     myContextFrame.size.height = height; 
     _imageView.image = [UIImage imageWithCGImage:image]; 
    } 

    return myContext; 
} 
-(CGRect) offscreenContextBounds { 
    return myContextFrame; 
} 

Cela définit l'image _imageView.image à l'image nouvellement créée. Dans drawSquareFrom:to: je suppose que setNeedsDisplay est suffisant pour dessiner les modifications apportées, mais il se peut que vous deviez assigner un nouveau UIImage chaque fois que wrapper la même CGImage.

0

Utilisez simplement deux contextes. Dans celui que vous venez de "prévisualiser" dessiner le Rectangle et vous pouvez l'effacer sur TouchesMoved. Sur Touches Enfin, vous dessinez sur votre contexte d'origine, puis sur l'image. Au lieu de dessiner dans une image bitmap, pourquoi ne pas créer des images qui sont des compositions d'objets CALayer?

Questions connexes