Im developing a word finding app.Here i want some words to fall from the top of screen of iphone.
There will be a red line at the bottom of screen.
User have to select the correct word before reaching a red line.
So how can i implement the falling effect in iphone.(i.e words falling effect).
Can anyone please help me with this.
Thanks in advance.
You can implement this using UIView animations. This sample code is all within a view controller, with a single label, fallingLabel added to the view. You can expand it to include multiple labels.
The key point is to import the QuartzCore framework. This gives you access to the presentationLayer of a view, which holds the current state of an animating view. You add the framework to your project in the project summary part of Xcode, then put the following in the top of your view controller's implementation file:
#import <QuartzCore/QuartzCore.h>
The following code animates the dropping of the label. It will increase in speed as it falls due to the UIViewAnimationOptionCurveEaseIn setting, giving you a convincing gravity effect.
self.fallingLabel.center = CGPointMake(160,50);
[UIView animateWithDuration:3
delay:0
options:UIViewAnimationOptionCurveEaseIn
animations:^{self.fallingLabel.center = CGPointMake(160,400);}
completion:nil];
Now, you need to implement touch handling. This is not done on the label, as internally it will think it is already at the bottom of the screen. You handle the touches in your view controller:
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
CGPoint touchLocation = [touch locationInView:self.view];
if ([self.fallingLabel.layer.presentationLayer hitTest:touchLocation])
{
NSLog(#"Label was touched");
CALayer *presLayer = self.fallingLabel.layer.presentationLayer;
[UIView animateWithDuration:0
delay:0
options:UIViewAnimationOptionBeginFromCurrentState
animations:^{self.fallingLabel.frame = presLayer.frame;}
completion:nil];
}
}
Here, what is happening is that the presentation layer is being queried to see if the touch falls within it's current bounds. If so, we then start a new animation, which starts from the current state - in this case all I have done is stop the falling of the label, but you could implement anything you like here.
If you have multiple falling labels you can try the hitTest on the presentation layer of each one until you find the one that has been touched.
try to use usual animations blocks, but run than in separate theard:
NSOperationQueue *_queue;
_queue = [[NSOperationQueue alloc] init];
SEL selector = #selector(fallWord);
NSMethodSignature *signature = [self methodSignatureForSelector:selector];
NSInvocation *inv = [NSInvocation invocationWithMethodSignature:signature];
[inv setTarget:self];
[inv setSelector:selector];
NSInvocationOperation *fall= [[[NSInvocationOperation alloc] initWithInvocation:inv] autorelease];
[_queue addOperation:fall];
then, implement fallWord method, where you will set an animatin of falling:
UILabel *lb = [[UILabel alloc] initWithFrame:CGRectMake(<#CGFloat x#>, <#CGFloat y#>, <#CGFloat width#>, <#CGFloat height#>)];
[UIView animateWithDuration:1
delay:0
options:UIViewAnimationOptionCurveLinear
animations:^{
[lb setCenter:CGPointMake(<#CGFloat x#>, <#CGFloat y#>)];
} completion:nil];
then, you will need to implement touches and in method
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
NSUInteger touchCount = 0;
for (UITouch *touch in touches) {
[self dispatchFirstTouchAtPoint:[touch locationInView:self] forEvent:nil];
touchCount++;
}
}
check if touch coodinates inside your UILabel's frame
Cocos2d combined with box2d or chipmunk will help you achieve a falling affect (simulating gravity towards the bottom of the screen).
I will give a general plan with Cocos2d / chipmunk
Learn both.
Cocos2d - CCLabelTTF, CCLayer, CCSprite, CCTouch recognition, how to schedule a timer with cocos2d
Chipmunk - bodies, gravity, using the timer set up with cocos2d to step through the physics, calling a C static void function to update the CCLabelTTF's that are still on screen, removing those objects that aren't on screen (past the red line), and how to use the Cocos2d touch methods to verify if you hit a word or not.
ie method
-(void)ccTouchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
There are great starter documents on Cocos2d's site and not so great documentation for chipmunk, but you can find tutorials on hooking that in.
I am not sure if UIKit animations can be interrupted how they will need to be in your app.
In any implementation, you will also need to ensure your view displaying the text isn't bigger than the text.
If you take the cocos2d + physics engine route to achieve your goal, you will be in good shape to learn how to make an even more complex game.
You are actually looking for AutoComplete textbox. Basically there is no such thing exist in iPhone. but with the help of UIPicker view you can provide such effect
Related
I want to disable touches on all areas of the screen apart from a specific few points (e.g buttons). I.e. I don't want 'touchesBegan' to trigger at all when I tap anything other than a button. Calling
self.view.userInteractionEnabled = NO;
has the desired effect for not registering touches, but then of course I can't tap any buttons. I basically want the button to still work, even if there are 5 points touching the screen, i.e. all touch inputs have been used up, and the button represents the 6th.
Is this possible?
I've tried inserting a view with userInteraction disabled below my buttons, but it still registers touches when the user taps the screen. It seems the only way to disable touch registering is to do so on the entire screen (on the parent UIView).
UPDATE:
I've tried using gesture recognizers to handle all touch events, and ignore those that don't qualify. Here is my code:
#interface ViewController : UIViewController <UIGestureRecognizerDelegate>
...
- (void)viewDidLoad
{
[super viewDidLoad];
UIGestureRecognizer *allRecognizer = [[UIGestureRecognizer alloc] initWithTarget:self action:nil];
allRecognizer.delegate = self;
[self.view addGestureRecognizer:allRecognizer];
}
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch {
CGPoint coords = [touch locationInView:self.view];
NSLog(#"Coords: %g, %g", coords.x, coords.y);
if (coords.y < 200) {
[self ignoreTouch:touch forEvent:nil];
return TRUE;
}
return FALSE;
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
NSLog(#"%i touch(es)", [touches count]);
}
However the screen still 'reads' the touches, so if I place 5 fingers down, the 6th one won't trigger a button press...
You need to set up an invisible UIButton and lay it between the view that should not register touches and the UIButtons that should still be active.
Now you need to set the invisible button's 'userInteractionEnabled':
//userInteractionEnabled == NO => self.view registeres touches
//userInteractionEnabled == YES => self.view doesn't register touches
[_invisibleButton setUserInteractionEnabled:NO];
What really matters in this solution is that both - the invisible and the visible buttons are direct subviews of the VC's view.
You can download an example project from my dropbox:
https://dl.dropboxusercontent.com/u/99449487/DontTapThat.zip
However this example just prevents the handling of certain touches. Completly ignoring input isn't technically possible: Third party apps are not responsible for for detecting input. They are just responsible for handling input. The detection of touch input is done iOS.
The only way to build up a case like you describe it in the comments is to hope that iOS won't interpret the input of your case as a "finger" because it's most likely going to cover an area that's way bigger than a finger.
So in conclusion the best way would be to change the material of the case you're about to build or at least give it a non conductive coating. From a third party developers point of view there is no way to achieve your goals with software if there is a need for 5 fingers as described in the comments.
There is couple of methods in UIView that you can override:
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event; // recursively calls -pointInside:withEvent:. point is in the receiver's coordinate system
- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event; // default returns YES if point is in bounds
This should prevent to call touchBegin and other methods.
Regards.
I have a nice solution for this. What ever the area you want to hide the interaction place a transparent button on top of the area.
touchesBegan is a default method so it must call all the time when touch happens on view so there is no way-out, But you can still do one thing set
self.buttonPlayMusic.userInteractionEnabled = FALSE;
for the object you don't need touch may be this could be help you with your desired output.
Have you tried using a UIScrollView as the background ? i.e the area where you do not want touch events to be fired.
UIScrollView does not call the touch methods.
You can add UIImageView Control on that area where you want to disable touch event.you can add UIImageView object as top of self.view subViews.
Example
//area -- is that area where you want to disable touch on self.view
UIImageView *imageView=[[UIImageView alloc]initWithFrame:area];
[self.view addSubView:imageView];
You touchDelegate will always call in this way, but if you are doing some task on touch then you can do your task like this way.
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
UIButton *touchObject=(UIButton*)[touch view];
if ([touchObject isKindOfClass:[UIButton class]])
{
//Do what ever you want on button touch
}
else{
return;
}
}
I'm using CAKeyframeAnimation.
-(IBAction)start:(id)sender {
UIBezierPath *path = [UIBezierPath bezierPath];
[path moveToPoint:CGPointMake(600, 150)];
[path addLineToPoint:CGPointMake(600, 300)];
[path addLineToPoint:CGPointMake(450, 300)];
[path addLineToPoint:CGPointMake(450, 150)];
[path addLineToPoint:CGPointMake(600, 150)];
CAKeyframeAnimation *move = [CAKeyframeAnimation animationWithKeyPath:#"position"];
move.path = path.CGPath;
move.duration = 6.0f;
move.repeatCount = 100;
[testButton.layer addAnimation:move forKey:#"move"];
I need to make possible to use button while it moving.
Also I tried use touches detection but its only working with button while it stop.
Is it possible?
Thanks.
Really! you want the user to press the button while it is animating? People prefer to turn off interaction during animation. But anyway it this is your interaction then so be it. Have you tried - [yourButton setUserInteractionEnabled:TRUE];
Normally during any UIView animations we need to simply put UIViewAnimationOptionAllowUserInteraction as the animation option and thats it. Since you have gone more deeper in using CoreAnimation and layers, not sure what options make it work there. Please let us know how it works out for you...
UPDATE: This problem looked interesting to me. So I was just trying this out in Xcode. Here is what I found. To hit a moving button, you need to do hit testing on the button's .layer.presentationLayer property (need QuartzCore for this) in your view controller.
Internally, The animation is just eye candy. The animation lags behind the actual movement of the view. The button is already at the destination point when the animation starts. You just see a movie of the view/button moving. If you want a button to be clickable during the animation, you'll have to make the animation yourself.
So the coe would be like this-
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *t = [touches anyObject];
CGPoint location = [t locationInView:self.view];
for (UIButton *button in self.buttonsOutletCollection)
{
if ([button.layer.presentationLayer hitTest:location])
{
// This button was hit whilst moving - do something with it here
break;
}
}
}
So, right now I have a rocket which bounces side to side across the bottom of the iphone 5 screen. I want the rocket however to stop moving side to side but to go upwards once the user touches the screen (so touching the screen makes the rocket take off).
First, in viewDidAppear I told the compiler to run the spawnRocket method after 2 seconds.
In the spawnRocket method I established the rockets image and frame, and then I added it to the view and performed a uiview animation sending the rocket to the right side of the screen. In the finished parameter in the uiview animation method I told the compiler to run the moveRocketLeft method.
In the moveRocketLeft method I did an animation which would send the rocket to the left of the screen, and in the finished parameter I ran the moveRocketRight method.
The moveRocketMethod is basically the spawnRocket method except I don't establish the rockets image and frame and add it to the view.
So after all this, I tried to implemented the -touchesBegan:withEvent: method. I tried simply running a uiview animation which changed the rockets y to off the screen upwards, and the x to whatever the x was currently at when the user touched the screen.
However, I realize that the calling the rockets frame does not return the location that the rocket looks like while animating. It really just returns what the rockets frame will be when its done animating. So, to get the frame I want should I call layer? I remember reading somewhere that layer will return the actual location of a uiimageview during an animation.
But, layer only has the property bounds and not frame, so I'm a little confused.
I also tried calling [self.view.layer removeAllAnimations]; and then running a new animation which would shoot the awkward up, but the removeAllAnimations method never worked (and anyway i don't really like the idea of using that because i heard it lags).
So anyone have any idea how i can implement touchesBegan:withEvent: method so that the rocket can take off correctly? (or if you think I have to change my whole program please feel free to help)
#import "ViewController.h"
#import <QuartzCore/QuartzCore.h>
#interface ViewController ()
#property UIImageView *rocket;
#end
#implementation ViewController
#synthesize rocket=_rocket;
- (void)viewDidLoad
{
[super viewDidLoad];
}
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
[self.view.layer removeAllAnimations];
// [UIView animateWithDuration:3 delay:0 options:UIViewAnimationOptionCurveEaseIn animations:^(){self.rocket.frame=CGRectMake(self.rocket.frame.origin.x, -40, 25, 40);} completion:^(BOOL finished){}];
// this didn't work :(
}
-(void)viewDidAppear:(BOOL)animated{
[self performSelector:#selector(spawnRocket) withObject:self afterDelay:2];
}
-(void)spawnRocket{
self.rocket=[[UIImageView alloc]initWithImage:[UIImage imageNamed:#"default.png"]]; //places imageview right off screen
self.rocket.frame=CGRectMake(-25, 420, 25, 40);
[self.view addSubview:self.rocket];
[UIView animateWithDuration:1.5 delay:0 options:UIViewAnimationOptionCurveLinear animations:^(){self.rocket.frame=CGRectMake(295, 420, 25, 40);} completion:^(BOOL finished){if (finished)[self moveRocketLeft]; }];
}
-(void) moveRocketLeft{
[UIView animateWithDuration:1.5 delay:0 options:UIViewAnimationOptionCurveLinear animations:^(){self.rocket.frame=CGRectMake(0, 420, 25, 40);} completion:^(BOOL finished){if (finished)[self moveRocketRight];}];
}
-(void)moveRocketRight{
[UIView animateWithDuration:1.5 delay:0 options:UIViewAnimationOptionCurveLinear animations:^(){self.rocket.frame=CGRectMake(295, 420, 25, 40);} completion:^(BOOL finished){if (finished)[self moveRocketLeft];}];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#end
This should do the trick
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
CALayer *rocketPresentationLayer = [self.rocket.layer presentationLayer];
self.rocket.layer.position = rocketPresentationLayer.position;
[UIView animateWithDuration:3 delay:0 options:UIViewAnimationOptionCurveEaseIn|UIViewAnimationOptionBeginFromCurrentState animations:^(){self.rocket.frame=CGRectMake(self.rocket.frame.origin.x, -40, 25, 40);} completion:^(BOOL finished){}];
}
Note 1: I didn't put logic in here to check whether the user tapped the rocket again, when it is taking off vertically. You might want to add a BOOL or something to see if the user successfully hit the rocket or not, and if so, don't perform the vertical animation again.
Note 2: If in future you only want this to occur when the rocket is hit, you can use hitTest checking to call the animation conditionally.
// Get the touch
UITouch *touch = [touches anyObject];
CGPoint touchPoint = [touch locationInView:self.view];
// See if we hit the rocket
CALayer *rocketPresentationLayer = [self.rocket.layer presentationLayer];
CALayer* hitTest = [rocketPresentationLayer hitTest:touchPoint];
// If we did, then stop animation and move upwards
if (hitTest) {
....
}
P.S: Also as a slight mention, #property UIImageView *rocket; should be changed to #property (nonatomic) UIImageView *rocket;. This is primarily for performance reasons, as I don't expect your rocket to be accessed by multiple threads (it shouldn't, it's the UI!).
My problem is quite strange but simple.
I subclassed a my customer UIScrollView: MyScrollView, where i disabled the scroll:
self.scrollEnabled = NO;
that means apart from
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
all other UIScrollViewDelegate method won't be called
and in MyScrollView i do the content scroll by detecting the user touch movement on screen, that is to say no flipping, no bounces, my implementation is in the touchesMoved:withEvent: method
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
// NSLog(#"touch.phase:%d",touch.phase);
CGPoint currentPosition = [touch locationInView:self];
CGPoint lastTouchPosition = [touch previousLocationInView:self];
CGFloat deltaY = lastTouchPosition.y - currentPosition.y;
CGFloat contentYOffset = self.contentOffset.y + deltaY;
[self setContentOffset:CGPointMake(0,contentYOffset) animated:NO];
}
after the user drag movement have been finished, i do my own method according to the content offset of MyScrollView in touchesEnded:withEvent:
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
//some implementation according to current content offset
}
user moves finger on screen, whenever the finger left the screen surface, the touchesEnded:withEvent: get called and i can implement my own method correctly.
BUT, when user move finger on screen surface from inside the screen to outside either on top or bottom, then lift the finger up, the touchesEnded:withEvent: method never got called, it seems like the ios doesn't treat the move out bounds(top or bottom) event as a touches end event, also ios wouldn't know the what is going on when touch is outside it screen bounds
someone may suggest me to detect the current position in touchesMoved:withEvent: to check out whether it is inbounds or not. this MAY WORK WHEN THE MOVEMENT IS VERY SLOW, but when you move very fast, the system can not detect every point position, it seems like the movement is detected in a certain time interval.
can any one help me out how could i detect if the user finger has moved out of bounds or not
I think the touchesCancelled:withEvent: method will be called !
I have resolved this problem
bcs UIScrollView does too much work that we can not handle some event ourselves, fortunately the UIView can detect the touche move out of bounds and will invoke the touchesEnd:withEvent: method.
considering that replacing MyScrollView's superclass with UIView has too much work to do, so i figured out a simple way to resolve:
i added an TouchActionDetectView subclassed from UIView, whose work is to detect all user touches event and deliver those event to MyScrollView. of course i have to clear the background color of TouchActionDetectView to avoid blocking other view content.
I am facing below problem:-
Please have a look in the below image the thing what i want is:-
I want to drag default images from view 1 to view 2 and images have to be always thr in view1 so its not like touch moved to draging images .
i tried a lot things in that but i succeed in draging image from one view to another but in view2 i am not able to get touch points so its just adding thr as frame
But i cnt able to touch tht image across view2 and even in view2
i want to do other functionality like zooming and others but first want to get touch points in view2.
I am giving description image about this problem.
The edited question is:-
i have done this simple demo in this i am transferring one view to another view and after getting view2 points its been in its limit boundaries.
but how can i get the default things remain in their.
i will modify this code i will add images in this view. but its just shows my thinking here so guide me here.
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event{
UITouch *touch = [touches anyObject];
if ([touch view] == view3) {
CGPoint location = [touch locationInView:self.view];
view3.center = location;
return;
}
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
int tmpValue = 0;
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.5];
{
onceDone = TRUE;
if(onceDone == TRUE)
{
UITouch *touch = [touches anyObject];
CGPoint pt = [touch locationInView:self.view];
NSLog(#"X = %f y=%f",pt.x,pt.y);
view3.center = pt;
if(view3.frame.origin.x < view2.frame.origin.x )
//view3.frame.origin.x < view2.frame.origin.x)
[view3 setFrame:CGRectMake(159,view3.frame.origin.y, view3.frame.size.width, view3.frame.size.height)];
}
}
[UIView commitAnimations];
}
Please help me.
it is urgent.
Thanks in advance
If you are using pan gestures are touchesMoved method to drag and drop the images.Make super view of view1 and view2 to same UIView and calculate your gesture location or touched point with respect to that common super view.That means your view1 and view2 will be on the same view and each subView(image)is also added to main view only.So you can move images on main view where ever you want and can perform any operation on them.
We have been working in a similar issue, and we have made up with this solution:
We have an UIPanGestureRecognizer added to each button.
When we detect the pan gesture begin, we create the object we want to drag (in this case, it could be a copy of your image). You should have to set a rect equals to the button, or if you create the object in a different view, you should have to convert the object coordinates so the object seems in the same position as the button, but inside his view.
After that we move the last created object, instead of move the button.
And that is, the trick here is the UIPanGestureRecognizer works until you untouch the screen, but it is triggered while you move your finger for all the screen, not only inside the button!
I hope this works for you.