iOS8: How to clear a UIView from a UIViewController - objective-c

I'm trying to update my app to use a storyboard with auto-layout. Using a XIB, I have this working fine. My app has a view controller with a subView defined in Interface Builder. I draw in the subView.
That works.
But I cannot clear (or undo/redo). I can see that the UIView methods are invoked, but I must not be doing something I'm supposed to do.
Here are some code snips, and I'd appreciate some help:
VC simply calls the view:
- (IBAction)eraseButtonTapped:(id)sender {
NSLog(#"%s", __FUNCTION__);
savedImage.image = drawImage.image;
[drawingView eraseButtonClicked];
}
UIView:
- (void)eraseButtonClicked {
NSLog(#"%s", __FUNCTION__);
self.bufferArray = [self.currentArray mutableCopy];
[self.currentArray removeAllObjects];
[self setNeedsDisplay];
}
Both functions log..
These are the touch methods:
#pragma mark - Touch Methods
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
NSLog(#"%s", __FUNCTION__);
self.currentColorPath = [[DrawingPath alloc] init];
[self.currentColorPath setColor:self.currentColor];
UITouch *touch= [touches anyObject];
[self.currentColorPath.path moveToPoint:[touch locationInView:self]];
[self.currentArray addObject:self.currentColorPath];
[self.redoStack removeAllObjects];
lastPoint = [touch locationInView:self];
lastPoint.y -= 20;
if ([touch tapCount] == 2) {
[self alertOKCancelAction];
return;
}
}
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
NSLog(#"%s", __FUNCTION__);
UITouch *touch = [touches anyObject];
[self.currentColorPath.path addLineToPoint:[touch locationInView:self]];
[self setNeedsDisplay];
CGPoint currentPoint = [touch locationInView:self];
currentPoint.y -= 20;
lastPoint = currentPoint;
}
-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
NSLog(#"%s", __FUNCTION__);
self.currentColorPath = nil;
}
The view calls a separate object to handle the drawing.. This is a code snippet (removing non-relevant bits).
- (id)init {
//NSLog(#"%s", __FUNCTION__);
if (!(self = [super init] ))
return nil;
path = [[UIBezierPath alloc] init];
_path.lineCapStyle=kCGLineCapRound;
_path.lineJoinStyle=kCGLineJoinRound;
[_path setLineWidth:brush];
return self;
}
- (void)draw {
NSLog(#"%s", __FUNCTION__);
[self.color setStroke];
[self.path stroke];
}

Related

crashed when touch two sprites at the same time(cocos2d-iphone)

The app will crash when two sprites are touched at the same time.
-(void)addEnemy
{
enemy = [CCSprite spriteWithFile:#"enemy.png"];
enemy.position = ccp(winsize.width / 2, winsize.height / 2);
[spriteSheet addChild:enemy];
[spritetiles addObject:enemy]; //spritetiles is NSMutableArray
}
touch code
-(void)ccTouchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
CGPoint location = [self convertTouchToNodeSpace: touch];
for (CCSprite *target in [spriteSheet children]) {
if (CGRectContainsPoint(target.boundingBox, location)) {
[target stopAllActions];
[spriteSheet removeChild:target cleanup:YES];
[spritetiles removeObject:target];
}
}
}
if I touch any one of the sprite, there's no error, but if i touch two sprites(sometime some sprites' position is nearby), the app will crash, at the code line "if (CGRectContainsPoint(target.boundingBox, location)) {", so how can I fix it? thanks
Updated
Use reverseEnumerator in order to iterate through an array when you may need to remove elements as part of the for loop:
-(void)ccTouchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
CGPoint location = [self convertTouchToNodeSpace: touch];
for (CCSprite *target in [spriteSheet.children reverseObjectEnumerator]) {
if (CGRectContainsPoint(target.boundingBox, location)) {
[target stopAllActions];
[spriteSheet removeChild:target cleanup:YES];
[spritetiles removeObject:target];
}
}
}

Change UISlider value using minimumImageValue / maximumImageValue

I'd like to have a UISlider respond to tapping on the minimumValueImage and/or maximumValueImage, setting the value to either minimum or maximum. I can't seem to find a 'normal' approach for this scenario, so I came up with this solution. I'm subclassing a UISlider and keep register of where the user started a touch. By comparing the location I can figure out if it was on one of the images. Works okay, but is there a less custom way to achieve the same goal?
#interface FGSlider ()
#property (nonatomic) CGRect minimumValueImageRect;
#property (nonatomic) CGRect maximumValueImageRect;
#property (nonatomic) BOOL touchesBeganInMinimumValueImageRect;
#property (nonatomic) BOOL touchesBeganInMaximumValueImageRect;
#end
#implementation FGSlider
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
[super touchesBegan:touches withEvent:event];
UITouch *touch = [touches anyObject];
CGPoint location = [touch locationInView:self];
if(CGRectContainsPoint(self.minimumValueImageRect, location)) {
self.touchesBeganInMinimumValueImageRect = YES;
}
else if(CGRectContainsPoint(self.maximumValueImageRect, location)) {
self.touchesBeganInMaximumValueImageRect = YES;
}
}
-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
[super touchesEnded:touches withEvent:event];
UITouch *touch = [touches anyObject];
CGPoint location = [touch locationInView:self];
if(self.touchesBeganInMinimumValueImageRect && CGRectContainsPoint(self.minimumValueImageRect, location)) {
[self setValue:self.minimumValue animated:YES];
[self sendActionsForControlEvents:UIControlEventValueChanged];
}
else if(self.touchesBeganInMaximumValueImageRect && CGRectContainsPoint(self.maximumValueImageRect, location)) {
[self setValue:self.maximumValue animated:YES];
[self sendActionsForControlEvents:UIControlEventValueChanged];
}
// reset state
self.touchesBeganInMinimumValueImageRect = NO;
self.touchesBeganInMinimumValueImageRect = NO;
}
-(CGRect)minimumValueImageRectForBounds:(CGRect)bounds {
self.minimumValueImageRect = [super minimumValueImageRectForBounds:bounds];
return self.minimumValueImageRect;
}
-(CGRect)maximumValueImageRectForBounds:(CGRect)bounds {
self.maximumValueImageRect = [super maximumValueImageRectForBounds:bounds];
return self.maximumValueImageRect;
}
#end
I made a simple category that seems to work and doesn't rely on calculating bounds and is MUCH simpler than your implementation. Try it and let me know what you think.
- (void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
for (UIView *view in self.subviews) {
CGPoint locationPoint = [touch locationInView:view];
if ([view pointInside:locationPoint withEvent:event]) {
UIImageView *imageView = (UIImageView*)view;
if (imageView.image == self.maximumValueImage) {
[self setValue:self.maximumValue animated:YES];
[self sendActionsForControlEvents:UIControlEventValueChanged];
} else if (imageView.image == self.minimumValueImage) {
[self setValue:self.minimumValue animated:YES];
[self sendActionsForControlEvents:UIControlEventValueChanged];
}
}
}
[super touchesBegan:touches withEvent:event];
}

cocoa touch hitTest withEvent can recognize UIView subclass

I have a view with subViews, these subViews are a subClass of UIView, in the example the subClass is called ESDcelda
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
UIImage *img = [UIImage imageNamed:#"lgrey091.gif"];
[self setBackgroundColor:[UIColor colorWithPatternImage:img]];
ESDcelda *cel1 = [[ESDcelda alloc] initWithTipo:1];
[cel1 setFrame:CGRectMake(100, 100, cel1.frame.size.width, cel1.frame.size.height)];
[self addSubview:cel1];
cel1 = [[ESDcelda alloc] initWithTipo:2];
[cel1 setFrame:CGRectMake(300, 100, cel1.frame.size.width, cel1.frame.size.height)];
[self addSubview:cel1];
}
return self;
}
now I'm triyng to know what kind of UIView I am pointing with the touchEvents with the following methods but in the log the pointer "vista" only recognizes the self class or the UIView class, there is any way to recognize the subClass "celdaSel" ?
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [[touches allObjects] objectAtIndex:0];
[self perfTouch:touch];
}
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [[touches allObjects] objectAtIndex:0];
[self perfTouch:touch];
}
-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [[touches allObjects] objectAtIndex:0];
[self perfTouch:touch];
}
-(void)perfTouch:(UITouch *)touch
{
CGPoint punto = [touch locationInView:self];
UIView *vista = (ESDcelda *)[self hitTest:punto withEvent:nil];
if (![vista isKindOfClass:[self class]])
{
celdaSel = (ESDcelda *)vista;
[celdaSel seleccion:YES];
}
else
{
if (celdaSel != nil)
{
[celdaSel seleccion:NO];
}
}
}
Solved, there are the steps
In the main view only left the code that interpects the touch and where is it.
v
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [[touches allObjects] objectAtIndex:0];
[self perfTouch:touch];
}
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [[touches allObjects] objectAtIndex:0];
[self perfTouch:touch];
}
-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [[touches allObjects] objectAtIndex:0];
[self perfTouch:touch];
if (self.celdaSel != nil)
{
NSLog(#"%d",self.celdaSel.elemento);
}
}
-(void)perfTouch:(UITouch *)touch
{
CGPoint punto = [touch locationInView:self];
[self hitTest:punto withEvent:nil];
}
In the UIView subClass called ESDCelda I override pointInside:withEvent method to know if the current single touch is on the view, "inter" is the variable that lets me know if the touch is on the view, "seleccionada" indicates if the view is highlighted, "conten" is a pointer to the superview, and "seleccion:" is the method that highlights the view it self.
v
-(BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event
{
BOOL inter = [super pointInside:point withEvent:event];
if (inter)
{
//NSLog(#"%i, %#", inter, self);
if (!self.selecionada)
{
[self seleccion:YES];
if (self.conten.celdaSel != nil)
[self.conten.celdaSel seleccion:NO];
[self.conten setCeldaSel:self];
}
}
else
{
if (self.selecionada)
{
[self seleccion:NO];
[self.conten setCeldaSel:nil];
}
}
return inter;
}

Detect Swipe faster than UISwipeGestureRecognizer?

i was wondering how to detect a "swipe" faster than this? I'd like to call a method as soons as the user moves his finger to the left. Let's call it a "small" swipe gesture.
This would be the normal/long swipe…
UISwipeGestureRecognizer *recognizer = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:#selector(handleSwipeFrom:)];
recognizer.direction = UISwipeGestureRecognizerDirectionLeft;
[scrollView addGestureRecognizer:recognizer];
[recognizer release];
[scrollView delaysContentTouches];
Now I build this:
#import "UICustomScrollView.h"
#implementation UICustomScrollView
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// do stuff
}
return self;
}
// Listen for "fast" swipe
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
CGPoint location = [touch locationInView:self];
CGPoint prevLocation = [touch previousLocationInView:self];
if (location.y - prevLocation.y > 0) {
[[NSNotificationCenter defaultCenter] postNotificationName:#"fastSwipe" object:self];
}
[super touchesMoved:touches withEvent:event];
}
#end

Avoid UIView touch delay

I am using a subclass of UIView in my app. When the user touches on view I need to get the coordinates of the point; for this I am using:
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event{
currentPoint=[[touches anyObject]locationInView:self];
}
It has some delay. Can any one give me the solution to get the points immediately? Thank you all.
- (id)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
// Initialization code.
self.frame=frame;
rect=[[NSMutableArray alloc] initWithCapacity:1];
currentPointsList=[[NSMutableArray alloc]initWithCapacity:1];
}
return self;
}
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
UITouch *touch = [touches anyObject];
firstTouchedPoint = [touch locationInView:self];
NSLog(#"the firstTouched point is %");
for (int i=0; i<[rect count]; i++) {
if(CGRectContainsPoint([[rect objectAtIndex:i]CGRectValue], firstTouchedPoint)){
CGRect firstLineRect = CGRectMake(firstTouchedPoint.x,
[[rect objectAtIndex:i]CGRectValue].origin.y,
[[rect objectAtIndex:i]CGRectValue].size.width-firstTouchedPoint.x+[[rect objectAtIndex:i]CGRectValue].origin.x,
[[rect objectAtIndex:i]CGRectValue].size.height);
UIImageView *firstLine=[[UIImageView alloc]initWithFrame:firstLineRect];
firstLine.backgroundColor=[[UIColor blueColor]colorWithAlphaComponent:0.3f];
[self addSubview:firstLine];
break;
}
}
If you are using a UIScrollView there is a delay touches property (delaysContentTouches). You may want to make sure that is NO.