I have a textfield on UIScrollview.
When the user taps outside of UITextfield, I use UIScrollViewKeyboardDismissModeInteractive to dismiss the keyboard. But it is not dismissing the keyboard.
What is wrong with my code?
m_scrollProfile = [[UIScrollView alloc]initWithFrame:CGRectMake(0, 0, 300, 300)];
m_scrollProfile.backgroundColor = kBGWhiteColor;
m_scrollProfile.userInteractionEnabled = YES;
[self.m_bgImageView addSubview:m_scrollProfile];
m_scrollProfile.keyboardDismissMode = UIScrollViewKeyboardDismissModeInteractive;
I encountered the same issue recently. In my header, I added <UITextFieldDelegate> as follows:
#interface YourClass : UIViewController <UITextFieldDelegate>
I added this in my viewDidLoad:
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc]initWithTarget:self action:#selector(dismissKeyboard:)];
[self.view addGestureRecognizer:tap];
and
self.myTextField.delegate = self;
and this method down below:
- (void)dismissKeyboard:(UITapGestureRecognizer *)recognizer {
NSLog(#"Dismiss keyboard");
[self.view endEditing:YES];
}
Not sure what else is going on w/ your implementation, but it works in the app I'm currently working on when the user clicks outside the UITextField.
Related
I created a UIView in a separate class, and I am trying to animate it in my ViewController. It is supposed to work like the notification screen on the iPhone that appears when you swipe down, and then you can swipe it back up.
I can get my custom view to swipe down, but when I try to swipe it back up, the swipe up gesture is not being initiated.
I am a novice, so any help is greatly appreciated!
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
NotificationView *notificationView = [[NotificationView alloc]init];
[self.view addSubview:notificationView];
UISwipeGestureRecognizer *swipeDownGestureRecognizer = [[UISwipeGestureRecognizer alloc]initWithTarget:self action:#selector(swipeDown:)];
swipeDownGestureRecognizer.direction = UISwipeGestureRecognizerDirectionDown;
UISwipeGestureRecognizer *swipeUpGestureRecognizer = [[UISwipeGestureRecognizer alloc]initWithTarget:self action:#selector(swipeUp:)];
swipeUpGestureRecognizer.direction = UISwipeGestureRecognizerDirectionUp;
[self.view addGestureRecognizer:swipeDownGestureRecognizer];
[notificationView addGestureRecognizer:swipeUpGestureRecognizer];
}
-(void) swipeUp: (UISwipeGestureRecognizer *) recognizer{
UIView *notificationView = [[NotificationView alloc]init];
notificationView = recognizer.view;
[UIView animateWithDuration:2.0 animations:^{
notificationView.frame = CGRectMake(0, 0, 414, 723);
}];
}
-(void) swipeDown: (UISwipeGestureRecognizer *) recognizer{
UIView *notificationView = [[NotificationView alloc]init];
notificationView = recognizer.view;
[UIView animateWithDuration:2.0 animations:^{
notificationView.frame = CGRectMake(0, 723, 414, 723);
}];
}
notificationView in ViewDidLoad should be assigned to the viewControllers property, and you should not alloc init views in the gesture recognizer actions.
You should create a property with your notificationView and keep a reference to it, and not create a new one over and over.
#property (strong, nonatomic) NotificationView *notificationView;
And in your viewDidLoad:
_notificationView = [[NotificationView alloc] init];
// Important line to solve your problems on gestures not fired off on your notification view
_notificationView.userInteractionEnabled = YES;
[self.view addSubview:_notificationView];
and simply change:
-(void)swipeDown:(UISwipeGestureRecognizer *)recognizer {
[UIView animateWithDuration:2.0 animations:^{
_notificationView.frame = CGRectMake(0, 723, 414, 723);
}];
}
You should look into a tutorial on how properties work.
And you should look into This Thread to avoid animations getting called multiple times etc by handling gesture states.
I tried to use initWithFrame but I am not able to display the UIView, This kind of code solved many questions as I saw here but not in my case:
- (id)initWithFrame:(CGRect)frame myParams:(NSArray*)params;
.m file
- (id)initWithFrame:(CGRect)frame myParams:(NSArray*)params{
self = [super initWithFrame:frame];
if(self){
UIView *view = [UIView alloc] initWithFrame:CGRectMake(0,0,100,100)];
//Trying to send an uiview with gesture include
view.userInteractionEnabled = YES;
UITapGestureRecognizer *tap = [UITapGestureRecognizer alloc]
initWithTarget:self action:#selector(test)];
[view addGestureRecognizer:tap];
[self addSubview:view];
}
return self;
}
Here is how I am trying to add the view in UIViewController:
Maybe here I am doing it wrong, right?
Custom *view = [Custom alloc] initWithFrame:self.view.bounds myParams:array];
[self.view addSubview:view];
So, my question is it possible to add UITapGesture in the UIView generated in this class, cause it is not firing:
.h file
+ (UIView *)viewParams:(NSArray*)params;
.m file
+ (UIView *)viewWithParams:(NSArray*)params{
UIView *view = [UIView alloc] initWithFrame:CGRectMake(0,0,100,100)];
NSLog(#"read params %#", params);
//Trying to send an uiview with gesture include
view.userInteractionEnabled = YES;
UITapGestureRecognizer *tap = [UITapGestureRecognizer alloc]
initWithTarget:self action:#selector(test)];
[view addGestureRecognizer:tap];
return view;
}
- (void)test{
NSLog('it works...');
}
UPDATE : As instance method is working. But as class method I can not make it work. somebody know if possible?
1st Part
If you are using XIB for your customView then you need to use awakeFromNib method. But if you are trying to create through code only then just use initWithFrame: method and add your gesture recognizer in the initializer.
2nd Part
For firing tap gesture recognizer you are adding recognizer target self i.e your customView. So event will fire in your customViewClass class only then to get these events in your controller you need to use protocol and delegate. And set the delegate of customView to whatever controller you want to use in the controller.
View will add after firing the initwithcoder just use this code in init with coder ...
dispatch_after(0.1, dispatch_get_main_queue(), ^(void)
{
UIView *view = [UIView alloc] initWithFrame:CGRectMake(0,0,100,100)];
//Trying to send an uiview with gesture include
view.userInteractionEnabled = YES;
UITapGestureRecognizer *tap = [UITapGestureRecognizer alloc]
initWithTarget:self action:#selector(test)];
[view addGestureRecognizer:tap];
[self addSubview:view];
});
}
return self;
}
Minimum Time interval 0.1 max time interaval set as per your data load requirement
I've made a custom view class. I'm initializing it in my view controller class. I've enabled user interaction then also it's not working. I've searched it in similar questions but most of them say to enable user interaction.
Here's the code I've written.
#interface ProfileCreatorViewController (){
SectionTitleView *ProfileTitle;
CGRect mainFrame;
}
#end
#implementation ProfileCreatorViewController
- (void)viewDidLoad {
[super viewDidLoad];
mainFrame = CGRectMake(self.view.frame.origin.x, self.view.frame.origin.y + NAVBAR_HEIGHT, self.view.frame.size.width, self.view.frame.size.height);
CGRect profileFrame = CGRectMake(mainFrame.origin.x + 5, mainFrame.origin.y, mainFrame.size.width - 20, 50);
ProfileTitle = [[SectionTitleView alloc]initWithFrame:profileFrame withTitle:#"Profile" withUnderLineColor:[UIColor blackColor] withDownButton:[UIImage imageNamed:#"rightArrow"]];
[self.view addSubview:ProfileTitle];
UITapGestureRecognizer *recog = [[UITapGestureRecognizer alloc]initWithTarget:self action:#selector(downButtonClicked)];
[ProfileTitle addGestureRecognizer:recog];
ProfileTitle.userInteractionEnabled = YES;
}
-(void) downButtonClicked{
NSLog(#"clicked");
}
You can check couple of things here
profileFrame's height and width are not very small (print profileFrame)
ProfileTitle is not complete transparent (Gesture will also not work when view's alpha is very close to 0)
ProfileTitle is not obscured by any other view (use visual debugger for that)
#interface ProfileCreatorViewController ()<UIGestureRecognizerDelegate>{
SectionTitleView *ProfileTitle;
CGRect mainFrame;
}
#end
#implementation ProfileCreatorViewController
- (void)viewDidLoad {
[super viewDidLoad];
mainFrame = CGRectMake(self.view.frame.origin.x, self.view.frame.origin.y + NAVBAR_HEIGHT, self.view.frame.size.width, self.view.frame.size.height);
CGRect profileFrame = CGRectMake(mainFrame.origin.x + 5, mainFrame.origin.y, mainFrame.size.width - 20, 0);
ProfileTitle = [[SectionTitleView alloc]initWithFrame:profileFrame withTitle:#"Profile" withUnderLineColor:[UIColor blackColor] withDownButton:[UIImage imageNamed:#"rightArrow"]];
[self.view addSubview:ProfileTitle];
UITapGestureRecognizer *recog = [[UITapGestureRecognizer alloc]initWithTarget:self action:#selector(downButtonClicked:)];
recog.delegate=self;
[ProfileTitle addGestureRecognizer:recog];
ProfileTitle.userInteractionEnabled = YES;
}
-(void) downButtonClicked:(UITapGestureRecognizer *)sender{
NSLog(#"clicked");
}
Add a delegate and change your method signature
Try these..
create property of your custom view like these..and also import it in your ProfileCreatorViewController.h file like these..
#import "SectionTitleView.h"
#property (nonatomic , strong) SectionTitleView *previewView;
Add UIGestureRecognizerDelegate
#interface ProfileCreatorViewController ()<UIGestureRecognizerDelegate>
{
SectionTitleView *ProfileTitle;
CGRect mainFrame;
}
set NumberOfTapsRequired if you want
UITapGestureRecognizer *recog =
[[UITapGestureRecognizer alloc]initWithTarget:self
action:#selector(downButtonClicked:)];
ProfileTitle.userInteractionEnabled = YES;
[recog setNumberOfTapsRequired:1]; //No. of taps..
[ProfileTitle addGestureRecognizer:recog];
and also its method
-(void) downButtonClicked:(UITapGestureRecognizer*)gesture
{
NSLog(#"Taped");
}
i hope it helps..
You need the UIGestureRecognizerDelegate inside the header file.
Also create a property to hold the UITapGestureRecognizer inside:
#property (strong, nonatomic) UITapGestureRecognizer tapGesture;
You also shouldn't create the UITapGestureRecognizer inside the parent class. The ProfileTitle should generate this by itself. So you'd better insert the code inside viewDidLoad inside SectionTitleView.
FYI: And don't use capitalized variable names
I want to implement , when swipe bottom to top of screen the keyboard is shown on screen and when swipe from top to bottom on screen the keyboard hides.
Its like iOS 7 effect when we swipe on screen the search textfield and keyboard is shown and when swipe down its hide.
Try this:
//declare a property to store your current responder
#property (nonatomic, assign) id currentResponder;
//in viewDidLoad:
UISwipeGestureRecognizer *swipe = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:#selector(resignOnSwipe:)];
[self.collectionView addGestureRecognizer:swipe];
//Implement the below delegate method:
- (void)textFieldDidBeginEditing:(UITextField *)textField {
self.currentResponder = textField;
}
//Implement resignOnSwipe:
- (void)resignOnSwipe:(id)sender {
[self.currentResponder resignFirstResponder]
}
Try Something like this,.. It works fine
In xib,
Add a textfield and hide it. Connect that to your .h file and name it as tf.
In .h file,
Add
#import <UIKit/UIKit.h>
#interface KeyboardDisplay : UIViewController <UIGestureRecognizerDelegate>
{
__weak IBOutlet UITextField *tf;
}
In .m file,
- (void)viewDidLoad
{
[super viewDidLoad];
UISwipeGestureRecognizer *swipeGesture = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:#selector(handleSwipeGesture:)];
swipeGesture.direction = UISwipeGestureRecognizerDirectionUp;
[self.view addGestureRecognizer:swipeGesture];
UISwipeGestureRecognizer *swipeGesture2 = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:#selector(handleSwipeGesture:)];
swipeGesture2.direction = UISwipeGestureRecognizerDirectionDown;
[self.view addGestureRecognizer:swipeGesture2];
}
-(void)handleSwipeGesture:(UISwipeGestureRecognizer *) sender
{
//Gesture detect - swipe up/down , can be recognized direction
if(sender.direction == UISwipeGestureRecognizerDirectionUp)
{
[tf becomeFirstResponder];
NSLog(#"Up");
}
else if(sender.direction == UISwipeGestureRecognizerDirectionDown)
{
[tf resignFirstResponder];
NSLog(#"down");
}
}
NOTE : Don't forget to hide the textfield in xib.
I have created a UIViewController, which contains a UIView object.
I want the UIView object response to a single tap by 1 finger, and also pinch by 2 fingers.
I have clicked the "User Interaction Enabled" and the "Multiple touch" options in the xib.
I create both UITapGestureRecognizer, and UIPinchGestureRecognizer inside the UIView function initWithFrame:, as it is the only entry point for the UIView object. But the object doesn't response to the UIGestureRecognizer objects. Why? Or, where is the best place to put the UIGestureRecognizer objects?
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code
// single tap
UITapGestureRecognizer* singleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(handleSingleTap:)];
singleTap.numberOfTapsRequired = 1;
singleTap.numberOfTouchesRequired = 1;
[self addGestureRecognizer: singleTap];
// 2 fingers pinch
UIPinchGestureRecognizer* doubleMove = [[UIPinchGestureRecognizer alloc] initWithTarget:self action:#selector(handleDoubleMove:)];
[self addGestureRecognizer: doubleMove];
}
return self;
}
Your problem is that when you instantiate your custom view subclass in IB, initWithCoder: is called. If you had done it programmatically using initWithFrame: it would have worked properly.
Two ways you can fix this,
Move the gestures setup to a different method and call them in both initWithFrame: and initWithCoder:. I would recommend doing this if you intend to reuse this component and expose some kind of callbacks on gestures.
If you want to implement this once and have a lot of interacting with the controller element, add them in viewDidLoad.
I tried your code and it works for me.
Where are you setting the view? Maybe it has any other view in front, or its superview has userInteractionEnabled disabled.
I created a UIView subclass and added this code:
-(void) handleSingleTap:(UITapGestureRecognizer *)gr {
NSLog(#"handleSingleTap");
}
-(void) handleDoubleMove:(UIPinchGestureRecognizer *)gr {
NSLog(#"handleDoubleMove");
}
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code
// single tap
UITapGestureRecognizer* singleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(handleSingleTap:)];
singleTap.numberOfTapsRequired = 1;
singleTap.numberOfTouchesRequired = 1;
[self addGestureRecognizer: singleTap];
// 2 fingers pinch
UIPinchGestureRecognizer* doubleMove = [[UIPinchGestureRecognizer alloc] initWithTarget:self action:#selector(handleDoubleMove:)];
[self addGestureRecognizer: doubleMove];
}
return self;
}
Then, in my controller:
-(void) viewDidLoad {
[super viewDidLoad];
MyView * myView = [[MyView alloc] initWithFrame:CGRectMake(0, 0, 100, 100)];
myView.backgroundColor = [UIColor greenColor];
[self.view addSubview:myView];
[myView release];
}
And it works.
i think if you are working with .xib, initialization can also be done in
-(void)awakeFormNib;
Adding the GestureRecognizers is typically done in the viewDidLoad method of the UIViewController.