Change UISlider value using minimumImageValue / maximumImageValue - objective-c

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];
}

Related

iOS8: How to clear a UIView from a UIViewController

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];
}

CCSprite disappears for unknown reason

-(void)touchBegan:(UITouch*)touch withEvent:(UIEvent*)event {
CGPoint touchPoint = [touch locationInNode:self];
[_gameBall setPosition:CGPointMake(touchPoint.x,self.gameBall.position.y)];
}
After a touch the _gameball sprite is not visible anymore, any reason why this happens?I logged it and isvisible for gameball is true and the touchpoint is always within the content size of my CCNode.
#import "GameScene.h"
#interface GameScene()
#property (nonatomic,strong) CCSprite* gameBall;
#end
#implementation GameScene
#synthesize gameBall = _gameBall;
+(GameScene*)gameInstance
{
return [[self alloc]init];
}
-(id)init
{
self = [super init];
if (self) {
//Implement
//user interaction
self.userInteractionEnabled = YES;
//Create the ball
_gameBall = [CCSprite spriteWithImageNamed:#"small_blue_ball.png"];
_gameBall.position = ccp(0.5f,0.1f);
_gameBall.positionType = CCPositionTypeNormalized;
[self addChild:_gameBall];
}
return self;
}
-(void)onEnter
{
[super onEnter];
}
-(void)onExit
{
[super onExit];
}
-(void)touchBegan:(UITouch *)touch withEvent:(UIEvent *)event
{
CGPoint touchPoint = [touch locationInNode:self];
touchPoint = [self convertToNodeSpace:touchPoint];
[_gameBall setPosition:CGPointMake(touchPoint.x, self.gameBall.position.y)];
NSLog(#"%f , %f",_gameBall.position.x,_gameBall.position.y);
}
-(void)touchMoved:(UITouch *)touch withEvent:(UIEvent *)event
{
}
#end
that was the .m file
now the .h file
#import "cocos2d-ui.h"
#import "cocos2d.h"
#interface IntroScene : CCScene
+(CCScene*)scene;
#end
CGPoint touchPoint = [touch locationInNode:self];
touchPoint = [self convertToNodeSpace:touchPoint];
might be your problem.. try changing it to:
CGPoint touchPoint = [touch locationInView:[touch view]];
touchPoint = [self convertToNodeSpace:touchPoint];
-edit-
ok, try:
CGPoint touchPoint = [touch locationInView:[touch view]];
touchPoint = [[self parent] convertToNodeSpace:touchPoint];
-edit2-
just noticed the cgpointmake:
[_gameBall setPosition:CGPointMake(touchPoint.x, self.gameBall.position.y)];
might not do anything special, but you should keep your code monotone, as in if you used _gameball.position then also use _gameball.position.y
So might want to change it to:
_gameBall setPosition:CGPointMake(touchPoint.x, _gameBall.position.y)];
-edit3-
this seems to work for me:
CGPoint touchPoint = [touch locationInView:[touch view]];
touchPoint = [[_gameBall parent] convertToNodeSpace:touchPoint];
[_gameBall setPosition:ccp(touchPoint.x, _gameBall.position.y)];
-Final edit-
Since you are using cocos2d, also use their ccTouchesBegan function.. Change it to:
-(void)ccTouchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
NSArray* touchArray = [touches allObjects];
for (UITouch* touch in touchArray)
{
CGPoint touchPoint = [touch locationInView:[touch view]];
touchPoint = [_gameBall convertToNodeSpace:touchPoint];
[_gameBall setPosition:ccp(touchPoint.x, _gameBall.position.y)];
break;
}
}
if it doesn't register touches, then add: [self setTouchEnabled:YES]; to your scene.

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

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

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".