UIBezierPath never being rendered - objective-c

so I have a little experience with objective-c, but not a ton. I'm trying to render UIBezierPath via TouchEvents (in other words draw a line with your finger). In addition, I would like to save all the bezierPaths into a NSMutableArray (paths) so that I can move or modify them later. This is the very simplest of applications. My header looks like this:
#interface ViewController : UIViewController{
UIBezierPath* path;
NSMutableArray* paths;
int curThickness;
}
#property (strong, nonatomic) IBOutlet UIView *scene;
#end
Scene is the view which takes up the entire screen and is where I am trying to draw my paths.
Relavent implementation looks like this:
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
UITouch *touch = [touches anyObject];
NSLog(#"Starting Path");
path = [UIBezierPath bezierPath];
path.lineWidth = 15.0f;
path.lineCapStyle = kCGLineCapRound;
path.lineJoinStyle = kCGLineJoinRound;
path.flatness = 2.0;
path.miterLimit = 4.0;
[path moveToPoint:[touch locationInView:scene]];
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event{
UITouch *touch = [touches anyObject];
[path addLineToPoint:[touch locationInView:scene]];
[scene setNeedsDisplay];
}
- (void)drawRect:(CGRect)rect {
NSLog(#"I'm supposed to be drawing something...");
[[UIColor redColor] set];
[path stroke];
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event{
NSLog(#"No more touchy feelies");
UITouch *touch = [touches anyObject];
[path addLineToPoint:[touch locationInView:scene]];
[paths addObject:path];
[scene setNeedsDisplay];
NSLog(#"number of paths: %i.", paths.count);
}
When I run it on the emulator, all the events are registered, DrawRect is never called, nothing is drawn on the screen (even if I add a [path trace] at the end of touchesEnded), path is nonEmpty, and paths.count remains zero no matter how many paths I trace.
What am I missing? As always your help is always greatly appreciated.

Couple things that should help you:
UIViewController does not implement - (void)drawRect .. you need to be doing this code in a UIView subclass instead!
If your paths collection is always zero count, a common mistake causing this is when paths itself is nil. (Obj-c doesn't care if you try to send messages to a nil object, it will just return a default value instead of crashing.) Double-check that you instantiated an NSMutableArray object and pointed paths to it.

Related

how to add 3dtouchforce to UIButton?

I want to measure the touch force when tapping or dragging a button. i have created a UITapGestureRecognizer (for tapping) and added it to myButton like this:
UITapGestureRecognizer *tapRecognizer2 = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(buttonPressed:)];
[tapRecognizer2 setNumberOfTapsRequired:1];
[tapRecognizer2 setDelegate:self];
[myButton addGestureRecognizer:tapRecognizer2];
i have created a method called buttonPrssed like this:
-(void)buttonPressed:(id)sender
{
[myButton touchesMoved:touches withEvent:event];
myButton = (UIButton *) sender;
UITouch *touch=[[event touchesForView:myButton] anyObject];
CGFloat force = touch.force;
forceString= [[NSString alloc] initWithFormat:#"%f", force];
NSLog(#"forceString in imagePressed is : %#", forceString);
}
I keep getting zero values (0.0000) for touch. any help or advice would be appreciated. i did a search and found DFContinuousForceTouchGestureRecongnizer sample project but found it too complicated. I use iPhone 6 Plus s that has touch. i can also measure touch when tapping on any other area in the screen but not on buttons using this code:
- (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
[super touchesMoved:touches withEvent:event];
UITouch *touch = [touches anyObject];
//CGFloat maximumPossibleForce = touch.maximumPossibleForce;
CGFloat force = touch.force;
forceString= [[NSString alloc] initWithFormat:#"%f", force];
NSLog(#"forceString is : %#", forceString);
}
You are getting 0.0000 in buttonPressed because the user already lifted his finger when this is called.
You are right, that you need to get the force in the touchesMoved method, but you need to get it in the UIButton's touchesMoved method. Because of that you need to subclass UIButton and override its touchesMoved method:
Header file:
#import <UIKit/UIKit.h>
#interface ForceButton : UIButton
#end
Implementation:
#import "ForceButton.h"
#implementation ForceButton
- (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
[super touchesMoved:touches withEvent:event];
UITouch *touch = [touches anyObject];
CGFloat force = touch.force;
CGFloat relativeForce = touch.force / touch.maximumPossibleForce;
NSLog(#"force: %f, relative force: %f", force, relativeForce);
}
#end
Also, there is no need to use a UITapGestureRecognizer to detect a single tap on a UIButton. Just use addTarget instead.

Changing SKSpriteNode property via touchesBegan

I was wondering if there was a more efficient way to changing the property of a SKSpriteNode in touchesBegan than my current method. The following is my method:
- (void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
CGPoint location = [touch locationInNode:self];
SKNode *node = [self nodeAtPoint:location];
if ([node.name isEqualToString:#"Start"]){
for (SKSpriteNode *node2 in [self children]){
if ([node2.name isEqualToString:#"Start"]){
node2.texture = [SKTexture textureWithImageNamed:#"button_beige_pressed"];
}
}
}
...
}
Your current logic suggest that you have multiple nodes with the name 'start'. If this is actually the case I suggest creating an array and storing all 'start' nodes in said array.
If however you only have a single node with the name 'start', then no loop is needed as you already have a reference to the node with the touch function.
I found a solution:
- (void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
CGPoint location = [touch locationInNode:self];
SKSpriteNode *node = (SKSpriteNode *)[self nodeAtPoint:location];
if ([node.name isEqualToString:#"Start"]){
node.texture = startPressed;
}
}
I was using a Node when I should have been using a spritenode.

UIView detecting touches in only one half of the screen

I am currently working on a 3D OpenGLES-based iPhone Game project and I want to have a view that detect touches so I can then rotate my camera according to the touch gestures.
So here I created a TouchPad class that derives from UIView to record the touch gestures.
Once done I have figured out that only half of the screen is effective. The whole left side.
Whenever i touch the right part of the screen it does not call the -[touchesBegan] method
Here is my class definition
#interface TouchPad : UIView
{
CGPoint fingerMove, originalPosition;
}
#property (nonatomic, assign) CGPoint fingerMove;
#end
And here is my class implementation
#import "TouchPad.h"
#implementation TouchPad
#synthesize fingerMove;
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self)
fingerMove = CGPointMake(0, 0);
return self;
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
std::cout << "called";
UITouch *touch = [touches anyObject];
originalPosition = [touch locationInView:self];
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
CGPoint currentPosition = [touch locationInView:self];
fingerMove = CGPointMake(currentPosition.x - originalPosition.x,
currentPosition.y - originalPosition.y);
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event;
{
UITouch *touch = [touches anyObject];
originalPosition = [touch locationInView:self];
fingerMove = CGPointMake(0, 0);
}
- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
{
fingerMove = CGPointMake(0, 0);
}
#end
And here is how i use it inside my ViewController
- (void)prepareGame
{
game = [[MainGame alloc] init];
[self.view addSubview:game.IrrView];
[game.IrrView release];
rotationPad = [[TouchPad alloc] initWithFrame:CGRectMake(0.0, 0.0,
[[UIScreen mainScreen] bounds].size.width,
[[UIScreen mainScreen] bounds].size.height)];
[self.view addSubview:rotationPad];
[rotationPad release];
}
- (void)runGame
{
[game updateMapPattern];
[game updateCamera :rotationPad.fingerMove];
[game draw];
}
I really want to know how to make the touchPad work in the whole screen and not only the left part of the screen. Maybe there is a conflict with my game view

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.

objective-c touch-events

I've got a set of Images and would like to know which I have touched. How could I implement that...?
To be more precise:
A "Home-Class" will instantiate a couple of Image-Classes:
Image *myImageView = [[Image alloc] initWithImage:myImage];
The image-class looks something like this:
- (id) initWithImage: (UIImage *) anImage
{
if ((self = [super initWithImage:anImage]))
{
self.userInteractionEnabled = YES;
}
return self;
}
later on, I use these touches-event-methods also in the Image-class:
- (void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{}
- (void) touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event{}
My problem at the moment: the touchesBegan/Ended methods will be fired no matter where I touched the screen, but I would like to find out which of the Images has been touched.....
Whenever you get the touch, you check if that touch happen in between your image area. Here is the example code, lets suppose you have UIImage object called img.
- (void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [[event allTouches] anyObject];
CGPoint location = [touch locationInView:self.view];
if (location.x >= img.x && location.x <= img.x && location.y >= img.y && location.y <= img.y) {
// your code here...
}
}
Inside your *.h (interface) file:
#interface MyViewController : UIViewController{
IBOutlet UIImageView *imageViewOne;
IBOutlet UIImageView *imageViewTwo;
UIImageView * alphaImage;
}
-(BOOL)isTouch:(UITouch *)touch WithinBoundsOf:(UIImageView *)imageView;
Place UIImageView components on your *.xib and bind them with 'imageViewOne' and 'imageViewTwo' using the "File's owner".
Go to the *.m (implementation) file and:
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
if ([self isTouch:touch WithinBoundsOf:imageViewOne])
{
NSLog(#"Fires first action...");
}
else if([self isTouch:touch WithinBoundsOf:imageViewTwo]){
NSLog(#"Fires second action...");
}
}
//(Optional 01) This is used to reset the transparency of the touched UIImageView
-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event{
[alphaImage setAlpha:1.0];
}
-(BOOL)isTouch:(UITouch *)touch WithinBoundsOf:(UIImageView *)imageView{
CGRect _frameRectangle=[imageView frame];
CGFloat _imageTop=_frameRectangle.origin.y;
CGFloat _imageLeft=_frameRectangle.origin.x;
CGFloat _imageRight=_frameRectangle.size.width+_imageLeft;
CGFloat _imageBottom=_frameRectangle.size.height+_imageTop;
CGPoint _touchPoint = [touch locationInView:self.view];
/*NSLog(#"image top %f",_imageTop);
NSLog(#"image bottom %f",_imageBottom);
NSLog(#"image left %f",_imageLeft);
NSLog(#"image right %f",_imageRight);
NSLog(#"touch happens at %f-%f",_touchPoint.x,_touchPoint.y);*/
if(_touchPoint.x>=_imageLeft &&
_touchPoint.x<=_imageRight &&
_touchPoint.y>=_imageTop &&
_touchPoint.y<=_imageBottom){
[imageView setAlpha:0.5];//optional 01 -adds a transparency changing effect
alphaImage=imageView;//optional 01 -marks the UIImageView which deals with the transparency changing effect for the moment.
return YES;
}else{
return NO;
}
}
That's how I handled that. I got the idea having read the post of "itsaboutcode".