I am using MHRotaryKnob to make Rotary dial like animation. I am using it for making old telephone dial pad.. At present it is just showing animation when i dial the pad it just come back with animation. even the first circle from lower not even getting touch detected and touch is working there also where there is no circle to dial. Below i am posting the code i am using.
- (BOOL)beginTrackingWithTouch:(UITouch *)touch withEvent:(UIEvent *)event
{
CGPoint point = [touch locationInView:self];
if (self.interactionStyle == MHRotaryKnobInteractionStyleRotating)
{
// If the touch is too close to the center, we can't calculate a decent
// angle and the knob becomes too jumpy.
if ([self squaredDistanceToCenter:point] < MinDistanceSquared)
return NO;
// Calculate starting angle between touch and center of control.
_angle = [self angleBetweenCenterAndPoint:point];
}
else
{
_touchOrigin = point;
_angle = [self angleForValue:self.value];
}
self.highlighted = YES;
[self showHighlighedKnobImage];
_canReset = NO;
return YES;
}
- (BOOL)handleTouch:(UITouch *)touch
{
if (touch.tapCount > 1 && self.resetsToDefault && _canReset)
{
[self setValue:self.defaultValue animated:YES];
return NO;
}
CGPoint point = [touch locationInView:self];
if (self.interactionStyle == MHRotaryKnobInteractionStyleRotating)
{
if ([self squaredDistanceToCenter:point] < MinDistanceSquared)
return NO;
// Calculate how much the angle has changed since the last event.
float newAngle = [self angleBetweenCenterAndPoint:point];
float delta = newAngle - _angle;
_angle = newAngle;
// We don't want the knob to jump from minimum to maximum or vice versa
// so disallow huge changes.
if (fabsf(delta) > 45.0f)
return NO;
self.value += (self.maximumValue - self.minimumValue) * delta / (MaxAngle*2.0f);
// Note that the above is equivalent to:
//self.value += [self valueForAngle:newAngle] - [self valueForAngle:angle];
}
else
{
self.value = [self valueForPosition:point];
}
return YES;
}
- (BOOL)continueTrackingWithTouch:(UITouch *)touch withEvent:(UIEvent *)event
{
if ([self handleTouch:touch] && self.continuous)
[self sendActionsForControlEvents:UIControlEventValueChanged];
return YES;
}
- (void)endTrackingWithTouch:(UITouch *)touch withEvent:(UIEvent *)event
{
self.highlighted = NO;
[self showNormalKnobImage];
// You can only reset the knob's position if you immediately stop dragging
// the knob after double-tapping it, i.e. when tracking ends.
_canReset = YES;
[self handleTouch:touch];
[self sendActionsForControlEvents:UIControlEventValueChanged];
[self setValue:self.defaultValue animated:YES];
}
I am trying to achieve that which circle is selected to dial that can be detected and only circles can be used to dial not outside the circles. Thanks in advance, any sort of help is appreciated.
Related
I've been stuck on this problem for days. What I have is multiple SKSpriteNode's, one for a left arrow, right arrow and up arrow. When I hold down the right arrow I want my character to continue moving right while its being held down, on the other hand if you press the up Arrow then you will only jump once regardless of if you hold it down.
So my problem for example is when i hold the right arrow and then i press the up arrow, touchesEnded is called and it stops my character from moving right even though I still have my finger on the right arrow
-(void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
[super touchesBegan:touches withEvent:event];
for (UITouch *touch in touches){
CGPoint location = [touch locationInNode:self];
if (CGRectContainsPoint(rightArrow.frame, location)){
[wizard setTexture:[SKTexture textureWithImageNamed:#"wizardRight"]];
didTouchRightArrow = YES;
isLookingRight = YES;
isLookingLeft = NO;
rightArrow.alpha = 0.5;
NSLog(#"Touching right");
}
if (CGRectContainsPoint(leftArrow.frame, location)){
[wizard setTexture:[SKTexture textureWithImageNamed:#"wizardLeft"]];
isLookingRight = NO;
isLookingLeft = YES;
didTouchLeftArrow = YES;
leftArrow.alpha = 0.5;
NSLog(#"Touching left");
}
if (CGRectContainsPoint(upArrow.frame, location)){
didTouchUpArrow = YES;
upArrow.alpha = 0.5;
NSLog(#"Touching up");
}
-(void) touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
[super touchesBegan:touches withEvent:event];
if (rightArrow.alpha != 1.0){
rightArrow.alpha = 1.0;
}
if (leftArrow.alpha != 1.0){
leftArrow.alpha = 1.0;
}
if (upArrow.alpha != 1.0){
upArrow.alpha = 1.0;
for (UITouch *touch in touches){
CGPoint location = [touch locationInNode:self];
if (CGRectContainsPoint(rightArrow.frame, location)){
NSLog(#"Touching right");
didTouchRightArrow = YES;
} {
NSLog(#"Not touching right");
didTouchRightArrow = NO;
}
if (CGRectContainsPoint(leftArrow.frame, location)){
NSLog(#"Touching Left");
didTouchLeftArrow = YES;
} else {
NSLog(#"not touching left");
didTouchLeftArrow = NO;
}
didTouchUpArrow = NO;
}
This may not be the right way to approach the problem, but in touchesEnded I am trying to see if the touch is still in the desired Rect.
You need a way to identify the different nodes which are registering a touch. There is more than one way to do this but I have always found using the name property of a node to be the simplest and easiest to work with.
You already have the right idea by using the BOOLs to register the touch states.
I wrote some code to handle what you are trying to accomplish:
#import "GameScene.h"
#implementation GameScene {
SKSpriteNode *node0;
SKSpriteNode *node1;
BOOL node0touch;
BOOL node1touch;
}
-(void)didMoveToView:(SKView *)view {
self.backgroundColor = [SKColor blackColor];
node0 = [SKSpriteNode spriteNodeWithColor:[SKColor redColor] size:CGSizeMake(100, 100)];
node0.name = #"node0";
node0.position = CGPointMake(100, 300);
[self addChild:node0];
node1 = [SKSpriteNode spriteNodeWithColor:[SKColor blueColor] size:CGSizeMake(100, 100)];
node1.name = #"node1";
node1.position = CGPointMake(400, 300);
[self addChild:node1];
node0touch = false;
node1touch = false;
}
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
for (UITouch *touch in touches) {
CGPoint touchLocation = [touch locationInNode:self];
SKNode *node = [self nodeAtPoint:touchLocation];
if([node.name isEqualToString:#"node0"])
node0touch = true;
if([node.name isEqualToString:#"node1"])
node1touch = true;
}
}
-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
for (UITouch *touch in touches) {
CGPoint touchLocation = [touch locationInNode:self];
SKNode *node = [self nodeAtPoint:touchLocation];
if([node.name isEqualToString:#"node0"])
node0touch = false;
if([node.name isEqualToString:#"node1"])
node1touch = false;
}
}
-(void)update:(CFTimeInterval)currentTime {
if(node0touch)
NSLog(#"node0 touch");
if(node1touch)
NSLog(#"node1 touch");
}
I am trying to slide the view in both directions,and following code is working fine for entire view, but i need this pan gesture works only for left and right corners only say 50 pixels on each side, and neglect the gesture if its not on the corners.
please help
-(void)setupGestures {
UIPanGestureRecognizer *panRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:#selector(movePanel:)];
[panRecognizer setMinimumNumberOfTouches:1];
[panRecognizer setMaximumNumberOfTouches:1];
[panRecognizer setDelegate:self];
[_centerViewController.view addGestureRecognizer:panRecognizer];
}
-(void)movePanel:(id)sender {
[[[(UITapGestureRecognizer*)sender view] layer] removeAllAnimations];
CGPoint translatedPoint = [(UIPanGestureRecognizer*)sender translationInView:self.view];
CGPoint velocity = [(UIPanGestureRecognizer*)sender velocityInView:[sender view]];
if([(UIPanGestureRecognizer*)sender state] == UIGestureRecognizerStateBegan) {
UIView *childView = nil;
if(velocity.x > 0) {
if (!_showingRightPanel) {
childView = [self getLeftView];
}
} else {
if (!_showingLeftPanel) {
childView = [self getRightView];
}
}
// make sure the view we're working with is front and center
[self.view sendSubviewToBack:childView];
[[sender view] bringSubviewToFront:[(UIPanGestureRecognizer*)sender view]];
}
if([(UIPanGestureRecognizer*)sender state] == UIGestureRecognizerStateEnded) {
if(velocity.x > 0) {
// NSLog(#"gesture went right");
} else {
// NSLog(#"gesture went left");
}
if (!_showPanel) {
[self movePanelToOriginalPosition];
} else {
if (_showingLeftPanel) {
[self movePanelRight];
} else if (_showingRightPanel) {
[self movePanelLeft];
}
}
}
if([(UIPanGestureRecognizer*)sender state] == UIGestureRecognizerStateChanged) {
if(velocity.x > 0) {
// NSLog(#"gesture went right");
} else {
// NSLog(#"gesture went left");
}
// are we more than halfway, if so, show the panel when done dragging by setting this value to YES (1)
_showPanel = abs([sender view].center.x - _centerViewController.view.frame.size.width/2) > _centerViewController.view.frame.size.width/2;
// allow dragging only in x coordinates by only updating the x coordinate with translation position
[sender view].center = CGPointMake([sender view].center.x + translatedPoint.x, [sender view].center.y);
[(UIPanGestureRecognizer*)sender setTranslation:CGPointMake(0,0) inView:self.view];
// if you needed to check for a change in direction, you could use this code to do so
if(velocity.x*_preVelocity.x + velocity.y*_preVelocity.y > 0) {
// NSLog(#"same direction");
} else {
// NSLog(#"opposite direction");
}
_preVelocity = velocity;
}
}
Get the four corners of the UIView using yourView.frame
Then, get the point of touch inside the UIView.
See the difference between the point of touch and each of the four corners.
If any one of the four values is < 50 (say), do what you want in the method which is called through the UIPanGestureRecognizer.
You can the point of touch through
CGPoint currentlocation = [recognizer locationInView:self.view];
You can get the four corners through,
CGPoint topLeft = view.bounds.origin;
topLeft = [[view superview] convertPoint:topLeft fromView:view];
CGPoint topRight = CGPointMake(view.bounds.origin.x + view.bounds.width, view.bounds.origin.y);
topRight = [[view superview] convertPoint:topRight fromView:view];
// and so on.
You can find the distance between two points through this method,
- (double) getDistance:(CGPoint)one :(CGPoint)two
{
return sqrt((two.x - one.x)*(two.x - one.x) + (two.y - one.y)*(two.y - one.y));
}
Hope this helps (-:
Override the method - (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event in the UIView to look like the following
- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event
{
BOOL pointInside = NO;
if(CGRectContainsPoint(self.bounds, point) && ((point.x < 50) || (point.x > self.bounds.size.width-50)))
{
pointInside = YES;
}
return pointInside;
}
Hope it helps.
I am trying to drag an image view. I have got little bit of success in doing so, but it is not behaving as i want. I wish that it should move only if touch inside the image and drag it.
But it is moving even if I am touching and dragging from anywhere on the screen.
I have written code like this:
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
//retrieve touch point
CGPoint pt= [[ touches anyObject] locationInView:[self.view.subviews objectAtIndex:0]];
startLocation = pt;
}
- (void) touchesMoved:(NSSet*)touches withEvent:(UIEvent*)event
{
CGPoint pt = [[touches anyObject] locationInView: [self.view.subviews objectAtIndex:0]];
CGRect frame = [[self.view.subviews objectAtIndex:0]frame];
frame.origin.x += pt.x - startLocation.x;
frame.origin.y += pt.y - startLocation.y;
[[self.view.subviews objectAtIndex:0] setFrame: frame];
}
The return value of locationInView method is point relative to the view frame. check it is or not in the view frame first.
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
CGRect targetFrame = [self.view.subviews objectAtIndex:0].frame;
//retrieve touch point
CGPoint pt= [[ touches anyObject] locationInView:[self.view.subviews objectAtIndex:0]];
//check if the point in the view frame
if (pt.x < 0 || pt.x > targetFrame.size.width || pt.y < 0 || pt.y > targetFrame.size.height)
{
isInTargetFrame = NO;
}
else
{
isInTargetFrame = YES;
startLocation = pt;
}
}
- (void) touchesMoved:(NSSet*)touches withEvent:(UIEvent*)event
{
if(!isInTargetFrame)
{
return;
}
//move your view here...
}
Try something like this:
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
//retrieve touch point
startLocation = [[ touches anyObject] locationInView:self.view];
// Now here check to make sure that start location is within the frame of
// your subview [self.view.subviews objectAtIndex:0]
// if it is you need to have a property like dragging = YES
// Then in touches ended you set dragging = NO
}
- (void) touchesMoved:(NSSet*)touches withEvent:(UIEvent*)event
{
CGPoint pt = [[touches anyObject] locationInView: [self.view.subviews objectAtIndex:0]];
CGRect frame = [[self.view.subviews objectAtIndex:0]frame];
frame.origin.x += pt.x - startLocation.x;
frame.origin.y += pt.y - startLocation.y;
[[self.view.subviews objectAtIndex:0] setFrame: frame];
I have code in place which lets you tap buttons and play a sound for each button, as well as sliding your fingers across the buttons and having each button play it's corresponding sound as you enter the button's area. It's working pretty good, except for a strange bug:
If you press your fingers on two buttons at the same time it will play both sounds initially. However, if you continue leaving your fingers on the button, and then release your fingers off the screen while moving one of them ever so slightly (still within the confines of each button), it will play one of the sounds of the two buttons. How can I prevent this from happening? I only want the sounds to play if you're sliding a finger across the buttons or hitting them initially, not if you're just moving them slightly while hitting two buttons at the same time and then releasing your finger.
Below is my code:
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
NSSet *allTouches = [event allTouches];
touchesCount = [allTouches count];
for(UITouch *t in touches) {
CGPoint location = [t locationInView:t.view];
if(CGRectContainsPoint(soundButton1.frame, location))
{
if (!soundButton1.isHighlighted && touchesCount < 2){
soundID = #"0";
[self playSound];
[soundButton1 setHighlighted:YES];
}
}
else {
[soundButton1 setHighlighted:NO];
}
if(CGRectContainsPoint(soundButton2.frame, location))
{
if (!soundButton2.isHighlighted && touchesCount < 2){
soundID = #"1";
[self playSound];
[soundButton2 setHighlighted:YES];
}
}
else {
[soundButton2 setHighlighted:NO];
}
}
}
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
for(UITouch *t in touches) {
CGPoint location = [t locationInView:t.view];
if(CGRectContainsPoint(soundButton1.frame, location))
{
[soundButton1 setHighlighted:YES];
soundID = #"0";
[self playSound];
}
if(CGRectContainsPoint(soundButton2.frame, location))
{
[soundButton2 setHighlighted:YES];
soundID = #"1";
[self playSound];
}
}
}
-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
for(UITouch *t in touches) {
CGPoint location = [t locationInView:t.view];
if(CGRectContainsPoint(soundButton1.frame, location))
{
[soundButton1 setHighlighted:NO];
}
if(CGRectContainsPoint(soundButton2.frame, location))
{
[soundButton2 setHighlighted:NO];
}
}
}
Try disabling the sounds for a short (very) period. In touchesEnded:withEvent:, check whether it has two touches, then do something like this,
soundDisabled = YES;
You can either request a selector to run after delay
[self performSelector:#selector(enableSound) withObject:nil afterDelay:0.2];
and then
- (void)enableSound {
soundDisabled = NO;
}
Or you could wait for the second finger to go up and then
soundDisabled = NO;
im trying to send a parameter from my touchesEnded handler like so...
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
CGPoint currentPosition = [touch locationInView:self.view];
CGFloat deltaX = fabsf(gestureStartPoint.x - currentPosition.x);
CGFloat deltaY = fabsf(gestureStartPoint.y - currentPosition.y);
if (deltaX >= 0.3 && deltaY <= 100) { //horizontal swipe detected
[self performSelector:#selector(refreshCover:)
withObject:nil afterDelay:0];
if (gestureStartPoint.x < currentPosition.x) { //swipe right
[self refreshCover:#"backward"];
NSLog(#"swipe backward");
} else { //swipe left
[self refreshCover:#"forward"];
NSLog(#"swipe forward");
}
}
}
then in refreshCover, i just have :
- (void)refreshCover:(NSString*)direction {
NSLog(#"direction: %#", direction);
}
when a user swipes, refreshCover is called, but the direction parameter is not getting passed. if i call [self refreshCover:#"forward"] from anywhere else, the parameter is passed without problems.
any ideas? thanks in advance.
The problem is with this code
[self performSelector:#selector(refreshCover:)
withObject:nil afterDelay:0];
The performSelector will call the function. I think this code is not needed since you are calling the function individually