In my view I want to add a target which should be fired when I click the view. I can do the same through IB or I have done it for buttons even in code. However I have no idea how to do it for UIView programatically.
Anyone has done that before.
Help me.
For clicking a UIView you have to use UIGestureRecognizer or UITouch. This would only help in prompting an action. The UIButton has a selector method whereas the UIView does not have any such method. Also , this is same for UIImageViews etc also.
You can acheive this using UIGestureRecognizer.
Step 1:
Add your UIView as a property in your viewcontroller
#property (strong, nonatomic) IBOutlet UIView *yourView;
Step 2:
Set UIGestureRecognizer for your UIView.
- (void)viewDidLoad {
[super viewDidLoad];
UIGestureRecognizer *gesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(handleGesture:)];
[self.yourView addGestureRecognizer:gesture];
}
Step 3:
Handle the click on UIView.
- (void)handleGesture:(UIGestureRecognizer *)gestureRecognizer {
//to get the clicked location inside the view do this.
CGPoint point = [gestureRecognizer locationInView:self.yourView];
}
Remember that A UIGestureRecognizer is to be be used with a single view.
Related
I have a simple question, how to connect a textfield to another Control view, if I click on the textfield, instead of show the keyboard it jump to another view
Thanks for answers
In the delegate method of the TextField, wich is textFieldShouldBeginEditing, add code that go from current View to another View.
Or you can use tap gasture recognizer on TextField to get the touch.
Here is the code:
create a TextFied in your IB and connect it to .h file
#interface ViewController : UIViewController<UITextFieldDelegate>
#property (strong, nonatomic) IBOutlet UITextField *firstTF;
And in .m file add this
#synthesize firstTF;
- (void)viewDidLoad
{
[super viewDidLoad];
firstTF.delegate= self;
}
-(BOOL)textFieldShouldBeginEditing:(UITextField *)textField{
secondViewController *ainfoController = [[secondViewController alloc] initWithNibName:#"secondViewController" bundle:nil];
[self presentModalViewController:ainfoController animated:YES];
return YES;
}
If you are adding the Textfield by code then,
UITextField *textField = [[UITextField alloc] initWithFrame:CGRectMake(x, y, width, height)];
textField.delegate = self;
[self.view addSubview:textField];
and add this method
- (BOOL) textFieldShouldBeginEditing:(UITextField *)textField{
// you can add the code for present a new viewController here
return NO;
}
make sure you have added UITextFieldDelegate in your .h file
I really don't get in why you need this but as a developer we do firmly believe to implement all scenarios, so in your case, you can achieve the same by following the any one beneath mentioned tacts:
1) In this approach, you need to override the textfieldshouldbegin delegate and use the navigate code for moving from one screen to another and don't forget to call resignFirstResponder here.
2) While in this second approach what you can do, just overlap a custom button(with neither image nor any text) and just on his click event method write your navigation code to move another screen.
Do that stuff, you'll get what you want and in case still you find any difficulty just shout over me.
I have 11 UIView on each has been set a Gesture Recognizer. This UIView are within mutable array and each have got a tag. How do to pass tag of UIView pressed to method selector?
viewIcone.userInteractionEnabled = YES;
viewIcone.tag = index;
UITapGestureRecognizer * tap = [[UITapGestureRecognizer alloc]initWithTarget:self action:#selector(touchUp:)];
tap.delegate = self;
[viewIcone addGestureRecognizer:tap];
[self.arrayMutabile insertObject:viewIcone atIndex:index];
[self addSubview:viewIcone];
The implementation of method selector is:
-(void) touchUp: (UITapGestureRecognizer *) gestureRecognizer{
NSInteger tag = [self.arrayMutabile indexOfObject:self.viewIcone];
NSLog(#"the tag is %d", tag);
}
I always leave 10. Where is the wrong?
Thanks in advance
The UITapGestureRecognizer has a view property which it inherits from it's parent:
http://developer.apple.com/library/ios/#documentation/uikit/reference/UIGestureRecognizer_Class/Reference/Reference.html#//apple_ref/occ/cl/UIGestureRecognizer
The view the gesture recognizer is attached to. (read-only)
#property(nonatomic, readonly) UIView *view
Discussion
You attach (or add) a gesture recognizer to a UIView object using the addGestureRecognizer: method.
Availability
Available in iOS 3.2 and later.
Declared In
UIGestureRecognizer.h
This will be the view that was tapped and you can retrieve the tag from there.
I'm trying to hide the number pad, but I do not want to implement a button.
Is there a way to dismiss the number pad when the user taps outside the textfield?
This is one of those questions where you read it and say "That's easy you just..". And then you go to do it and make it super complicated. And then realize it doesn't have to be that complicated.
The answer I've come up with, and I'm sure it will help someone else, Is to use an invisible UIView that never interacts but acts on other views and maybe not in the way you'd think.
The typical answer to a question about dismissing the UIKeyboardTypeNumberPad keyboard is to add a bar that has a button as the inputAccessoryView to dismiss the keyboard. If a bar and button are undesirable generally you just listen for touch events on the background and your good to go but this question is about a tableview and that makes this much harder.
But this inputAccessoryView feature is still awesome. It allows you to define a UIView or UIView subclass to be displayed when the keyboard is shown. More importantly when the keyboard is shown due to a textfield for which it is the inputAccessoryView becoming first responder.
I could yammer on but first here is some code for a lightweight class that actually performs very well in testing.
The contents of NJ_KeyboardDismisser.h are:
#import <UIKit/UIKit.h>
// For some reason neither inputView or inputAccessoryView are IBOutlets, so we cheat.
#interface UITextField (WhyDoIHaveToDoThisApple)
#property (readwrite, retain) IBOutlet UIView *inputAccessoryView;
#end
#interface NJ_KeyboardDismisser : UIView
#property (nonatomic, weak) IBOutlet UIView *mainView;
-(id)initWithMainView:(UIView *)view; // convienience method for code
#end
And the contents of NJ_KeyboardDismisser.m are:
#import "NJ_KeyboardDismisser.h"
#implementation NJ_KeyboardDismisser {
UITapGestureRecognizer *_tapGR;
}
#synthesize mainView = _mainView;
-(void)setMainView:(UIView *)view{
if (_tapGR) [_tapGR.view removeGestureRecognizer:_tapGR];
_mainView = view;
_tapGR = [[UITapGestureRecognizer alloc] initWithTarget:_mainView action:#selector(endEditing:)];
}
-(id)initWithMainView:(UIView *)view{
if ((self = [super initWithFrame:CGRectMake(0, 0, 0, 0)])){
self.mainView = view;
}
return self;
}
-(void)didMoveToWindow{ // When the accessory view presents this delegate method will be called
[super didMoveToWindow];
if (self.window){ // If there is a window one of the textfields, for which this view is inputAccessoryView, is first responder.
[self.mainView addGestureRecognizer:_tapGR];
}
else { // If there is no window the textfield is no longer first responder
[self.mainView removeGestureRecognizer:_tapGR];
}
}
#end
You may recognize the endEditing: method, as mentioned by Cosique, it is a UIView extension method that asks a views nested textfield to resign. Sound handy? It is. By calling it on the tableview the textfield it contains resigns first responder. Since this technique works on all UIViews there is no need to artificially limit this outlet to only UITableViews so the outlet is just UIView *mainView.
The final moving part here is the UITapGestureRecognizer. We don't want to add this recognizer full time for fear of screwing up the tableview's workings. So we take advantage of UIView's delegate method didMoveToWindow. We don't really do anything with the window we just check to see if we are in one; If we are then one of our textfields is first responder, if not then it's not. We add and remove our gesture recognizer accordingly.
Okay straightforward enough, but how do you use it? Well if instantiating in code you could do it like this, in tableView:cellForRowAtIndexPath::
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"Cell"];
UITextField *field = [[UITextField alloc] initWithFrame:CGRectMake(20, 6, 100, 31)];
[cell.contentView addSubview:field];
field.keyboardType = UIKeyboardTypeNumberPad;
field.inputAccessoryView = [[NJ_KeyboardDismisser alloc] initWithMainView:self.view];
}
If you are using static cells in a storyboard then the technique is different (obviously). First drag out a generic NSObject and place it in the dark grey strip below the view (where the other objects such as the view controller are). Then change this new object's class to be NJ_KeyboardDismisser. Then connect the "Keyboard Dismisser"'s mainView property to that view (generally a tableview). Then connect the inputAccessoryView property from any each text field in that scene you wish to the "Keyboard Dismisser".
Give it a try! The tableview acts normally. Apple's tap recognizer is smart enough to ignore the swipes on the table, so you can scroll. It also ignores touches in the textfields so you can edit and select other textfields. But tap outside a textfield and the keyboard is gone.
Note: This class's use is not limited to tableviews. If you want to use it on a regular view, just set the mainView property to be the same as the view controller's view.
The easiest way is to do this in your view controller:
[self.view endEditing: YES];
You can resign the responder inside the below function for your view:
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
Make sure your view is enabled for user interaction.
when creating the text field add a tag to it.
like this Yourtextfield.tag = 1;
and in you touchesEnded method
do this :
UITextField *resignTextField = (UITextField *)[self.view viewWithTag:1];
[resignTextField resignFirstResponder];
Actually, I want to push data from one view to other. I have a UIScrollView which has images on top of it. Now I want to push the data from that view to other view since whenever I do touch on that image view I want to select the position and push the location to other view.
UIScrollView does not have navigationController and cannot be able to push it.
UIScrollView is on top of UIViewController class. Is there a way to send the UITouch from UIScrollView to UIViewController Class and let that class push the view or do I have to work around some thing.
I have the following code for UIScrollView class,
ImageScrollView.m
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *t = [touches anyObject];
CGPoint touchInScrollView = [t locationInView:imageView];
NSLog(#"x: %f", floor(touchInScrollView.x));
NSLog(#"Y : %f", floor(touchInScrollView.y));
/****Cant be done since pushViewController is not allowed in UIScrollView.****/
DetailViewController *newView = [[DetailViewController alloc] initWithNibName:#"DetailViewController" bundle:nil];
[self.navigationController pushViewController:newView animated:YES];
}
Add this property to ImageScrollView.h
#property (nonatomic, retain) IBOutlet UIViewController* parentVC;
Add this line after #implementation in ImageScrollView.m
#synthesize parentVC;
Add this line to your - (void)dealloc method in ImageScrollView.m
[parentVC release];
If you create your ImageScrollView programmatically, after creation in your view controller:
imageScrollViewYouJustMade.parentVC = self;
If you create your ImageScrollView in Interface Builder, connect the parentVC outlet to File's Owner.
To push a new view controller, in ImageScrollView.m
[self.parentVC.navigationController pushViewController:newView animated:YES];
Here's an alternative,
I can't say for sure without knowing more about your application, but in general if I had a scroll view containing images that I wanted to tap, I would use a UIButton instead of UIImageView, and do something like
btnImage = [UIImage imageNamed:#"image.png"];
[btn setImage:btnImage forState:UIControlStateNormal];
If you aren't creating buttons programmatically, you can also set an image as it's background by changing the Type in the Attributes inspector to Custom, and change the Background attribute to the desired image.
Using a button instead of an image view will allow you to connect the touchDown outlet of the button to an IBAction method in your primary view controller that might look like:
- (IBAction)smileyFaceButtonTapped:(UIButton*)sender;
I want to call an action in two classes (a superview and a full screen subview) when the user single taps the screen. But, when I add a UITapGestureRecognizer to the subview, the one added to the superview is overridden. Is it possible to add a UITapGestureRecognizer to a subview without overriding the UITapGestureRecognizer added to the superview?
If so, how can I do this?
Thanks!
Edit:
From my main viewController "MyToolBerController", I'm adding the subview from another viewController as follows:
PhotoViewController *photoViewController = [[PhotoViewController alloc] initWithNibName:#"PhotoViewController" bundle:nil];
myPhotoView = photoViewController.view;
[self.view addSubview:myPhotoView];
I add the GestureRecognizer in the MyToolBerController like this:
UITapGestureRecognizer *singleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(handleSingleTapFrom:)];
[singleTap setNumberOfTapsRequired:1];
singleTap.delegate = self;
[myPhotoView addGestureRecognizer:singleTap];
[singleTap release];
This all works fine, but I need to call a method in the PhotoViewController class when the view is tapped as well as in the MyToolBerController class.
When I add another UITapGestureRecognizer in the photoViewController, it overrides the UITapGestureRecognizer added in the superView.
Gesture recognizers can dispatch multiple actions when the gesture occurs. You can add the subview as another target of the gesture recognizer and only use a single UITapGestureRecognizer instance:
[tapRecognizer addTarget:theSubview action:#selector(whatever:)];
In your gesture recognizer selector method, pass the information along to the subview. There's no need to have multiple gesture recognizers for the same gesture. Something like:
- (IBAction)handleSingleDoubleTap:(UIGestureRecognizer *)sender
{
CGPoint tapPoint = [sender locationInView:sender.view.superview];
UIView *subview = [parentView viewWithTag:100];
[subview doSomethingWithPoint:tapPoint];
}
This of course means that your subview that needs to be notified should be given the tag 100 either in Interface Builder or in code when the view controller gets loaded.
Update based on Jonah's code:
So instead of retaining the view, retain the view controller:
PhotoViewController *photoViewController = [[PhotoViewController alloc] initWithNibName:#"PhotoViewController" bundle:nil];
self.myPhotoViewController = photoViewController;
Which means you need to declare it this way in the MyToolbarController header:
#property (nonatomic, retain) PhotoViewController *myPhotoViewController;
Then, when your gesture selector gets called, pass the message along to the view controller you retained. Something like:
- (IBAction)handleSingleTapFrom:(UIGestureRecognizer *)sender
{
CGPoint tapPoint = [sender locationInView:sender.view.superview];
[myPhotoViewController doSomethingWithPoint:tapPoint];
}
Of course the -doSomethingWithPoint: method is only for example. You can name and create any method you want that takes any parameter you want to pass in your PhotoViewController.
Let me know if you need further clarification.