Hi I am developing one iphone application in which I am using few keyboard events but those are not working properly in IOS8 as working in previous IOS versions. So here is my problem. I have two text fields. I am listening for two events (void)keyboardWillBeHidden:(NSNotification *)notification and (void)keyboardWasShown:(NSNotification *)notification. Inside these methods I am scrolling my content according to keyboard height. In previous IOS version it is working properly but in IOS8 it is causing problem. Whenever I select any text field it is triggering keyboardWasShown but whenever I select another text field then again it is triggering same event even though keyboard already shown. In previous versions it is triggering only once but for IOS 8 it is triggering twice. Here is my code
- (void)registerForKeyboardNotifications {
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(keyboardWasShown:)
name:UIKeyboardDidShowNotification
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(keyboardWillBeHidden:)
name:UIKeyboardWillHideNotification
object:nil];
}
- (void)deregisterFromKeyboardNotifications {
[[NSNotificationCenter defaultCenter] removeObserver:self
name:UIKeyboardDidShowNotification
object:nil];
[[NSNotificationCenter defaultCenter] removeObserver:self
name:UIKeyboardWillHideNotification
object:nil];
}
- (void)keyboardWasShown:(NSNotification *)notification {
[LogRecords showLog:#"keyboard shown ... "];
if(UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone || (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad && UIDeviceOrientationIsLandscape([[UIApplication sharedApplication] statusBarOrientation])))
{
//scroll content here according to height of keyboard ;
}
}
- (void)keyboardWillBeHidden:(NSNotification *)notification
{
[LogRecords showLog:#"keyboard hide "];
if(UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone || (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad && UIDeviceOrientationIsLandscape([[UIApplication sharedApplication] statusBarOrientation])))
{
//scroll content here according to height of keyboard ;
}
}
Am I doing anything wrong or it is problem with new version? Need Help. Thank you.
I have been experiencing the same thing, only in iOS8.
I worked around the issue by adding a semaphore for the handling of the notification:
#implementation MyViewController
//workaround to iOS 8 bug where the keyboard notification is fired up twice
static BOOL flag;
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardWillHide:) name:UIKeyboardWillHideNotification object:nil];
}
- (void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillShowNotification object:nil];
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillHideNotification object:nil];
}
- (void)keyboardWillShow:(NSNotification *)note {
if (flag) {
return;
}
flag = YES;
//your code for handling keyboard display
}
- (void)ga_keyboardWillHide:(NSNotification *)note {
if (!flag) {
return;
}
flag = NO;
// your code for handling keyboard hiding
}
#end
Related
For some reason, UIKeyboardWillHideNotification is being executed twice in my below code - I haven't a clue as to why. I know this because my NSLog ("Closed!") appears twice in my console. Am I missing something obvious (and no, I don't have UIKeyboardWillHideNotification pasted somewhere in my code a second time).
-(void)viewDidLoad {
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardWillChange:) name:UIKeyboardWillShowNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(handleKeyboard:) name:UIKeyboardWillHideNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(handleKeyboard:) name:UIKeyboardWillShowNotification object:nil];
}
- (void)handleKeyboard:(NSNotification*)aNotification{
NSDictionary* info = [aNotification userInfo];
NSValue* value = [info objectForKey:UIKeyboardAnimationDurationUserInfoKey];
NSTimeInterval duration = 3;
[value getValue:&duration];
if (aNotification.name == UIKeyboardWillShowNotification) {
self.upView.frame = CGRectOffset(self.upView.frame, 0, -self.keyboardHeight); self.tableView.frame = CGRectOffset(self.tableView.frame, 0, -self.keyboardHeight);
[self moveCustomView:YES duration:duration];
}
if (aNotification.name == UIKeyboardWillHideNotification) {
/** KEYBOARD HIDE **/
self.upView.frame = CGRectOffset(self.upView.frame, 0, self.keyboardHeight); self.tableView.frame = CGRectOffset(self.tableView.frame, 0, self.keyboardHeight);
[self moveCustomView:NO duration:duration];
NSLog(#"CLOSED!");
}
}
Make sure to remove observers in viewDidDisappear as , view controller may be not reallocated from some reason and code in viewDidLoad is executed twice as observer is added twice
// Objective c
- (void)viewWillDisappear:(BOOL)paramAnimated{
[super viewWillDisappear:paramAnimated];
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillShowNotification object:nil];
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillHideNotification object:nil];
}
// Swift
override func viewDidDisappear(_ animated: Bool)
{
NotificationCenter.default.removeObserver(self, name: NSNotification.Name.UIKeyboardDidShow, object: nil)
NotificationCenter.default.removeObserver(self, name: NSNotification.Name.UIKeyboardWillHide, object: nil)
}
Be sure to remove the observer from the dealloc method. If you do not remove it and its memory is not released, it will listen for keyboard behavior on other pages. In addition, you should not add the same notification twice to the same observer.
Instead of Using same method for Hide and show notification. You can use two different Methods.
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(keyboardWasShown:)
name:UIKeyboardDidShowNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(keyboardWillBeHidden:)
name:UIKeyboardWillHideNotification object:nil];
Now, for Change your frame You can use following code
NSDictionary* info = [aNotification userInfo];
CGSize *kbSize = [[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;
self.tableView.frame = CGRectOffset(self.tableView.frame, 0, -kbSize.height);
Please, try it like this:
What I did:
• moved subscription to viewWillAppear
• added "unsubscribe" in viewWillDisappear
• added "unsubscribe" in dealloc (shouldn't be related to your issue, but that's the right way to do it still)
• replaced == with isEqual in your handler (also not related to your issue, most likely).
There may be some typos there. Sorry, if that's the case.
-(void)viewWillAppear {
[super viewWillAppear];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardWillChange:) name:UIKeyboardWillShowNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(handleKeyboard:) name:UIKeyboardWillHideNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(handleKeyboard:) name:UIKeyboardWillShowNotification object:nil];
}
-(void)viewDidLoad {
[super viewDidLoad];
//Leaving this method here just to point out that everything was moved to viewWillAppear
}
- (void)handleKeyboard:(NSNotification*)aNotification{
NSDictionary* info = [aNotification userInfo];
NSValue* value = [info objectForKey:UIKeyboardAnimationDurationUserInfoKey];
NSTimeInterval duration = 3;
[value getValue:&duration];
if ([aNotification.name isEqual: UIKeyboardWillShowNotification]) {
self.upView.frame = CGRectOffset(self.upView.frame, 0, -self.keyboardHeight);
self.tableView.frame = CGRectOffset(self.tableView.frame, 0, -self.keyboardHeight);
[self moveCustomView:YES duration:duration];
}
if ([aNotification.name isEqual: UIKeyboardWillHideNotification]) {
/** KEYBOARD HIDE **/
self.upView.frame = CGRectOffset(self.upView.frame, 0, self.keyboardHeight);
self.tableView.frame = CGRectOffset(self.tableView.frame, 0, self.keyboardHeight);
[self moveCustomView:NO duration:duration];
NSLog(#"CLOSED!");
}
}
-(void)unsubscribe {
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
-(void)viewWillDisappear {
[super viewWillDisappear];
[self unsubscribe];
}
-(void)dealloc {
[self unsubscribe];
}
I want to raise my keyboard when i press on a determinate UITextField, so I create a touch down action, but at the first call it doesn't work, by second call it work fine.
here's the code (naturally keyboardSize is a global variable with CGSize type):
- (void)viewWillAppear:(BOOL)animated {
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardWillHide:) name:UIKeyboardWillHideNotification object:nil];
}
- (void)viewWillDisappear:(BOOL)animated {
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillShowNotification object:nil];
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillHideNotification object:nil];
}
- (void)viewWillDisappear:(BOOL)animated {
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillShowNotification object:nil];
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillHideNotification object:nil];
}
- (void)keyboardWillShow:(NSNotification *)notification {
keyboardSize = [[[notification userInfo] objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;
}
- (void)keyboardWillHide:(NSNotification *)notification {
[self moveFrameToVerticalPosition:0.0f forDuration:0.3f];
}
- (void)moveFrameToVerticalPosition:(float)position forDuration:(float)duration {
CGRect frame = self.view.frame;
frame.origin.y = position;
[UIView animateWithDuration:duration animations:^{
self.view.frame = frame;
}];
}
- (IBAction)insert:(id)sender {
float newVerticalPosition = - keyboardSize.height;
[self moveFrameToVerticalPosition:newVerticalPosition forDuration:0.0f];
}
In keyboardWillShow: add:
[self moveFrameToVerticalPosition:-keyboardSize.height forDuration:0.0f];
You don't really need insert:.
I've began to learn iOS development for a few weeks,but this bug confused me a lot....
I just post 4 different observers in a ViewController:(They have different notificationames)
[[NSNotificationCenter defaultCenter]postNotificationName:#"notificationame" object:self userInfo:userinfo];
Then I want to add & remove 4 different observers in another ViewController,like this:
-(void)viewwillappear{
self.localChangeObserver=[[NSNotificationCenter defaultCenter]addObserverForName:#"notificationame" object:nil queue:nil usingBlock:^(NSNotification *note) { }];
}
-(void)viewwilldisappear{
[[NSNotificationCenter defaultCenter]removeObserver:self.localChangeObserver];
}
But this"removeObserver" turns out to be not working.Each time I show this ViewController ,it add one more observer,(and then I hide this VC,nothing removed).So I got a lot of observers at last.
And, putting them in ViewDidLoad/dealloc also do not work.
But,another 2 Observers just work fine.like this:
-(void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardWillHide:) name:UIKeyboardWillHideNotification object:nil];
}
- (void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
I really don't know what's wrong with my code.Thanks a lot.
Use following code :
-(void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
[[NSNotificationCenter defaultCenter] addObserverForName:#"OBSERVER NAME" object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *aNotification)
{
//Write your Notification handler Code
}];
}
- (void)viewWillDisappear:(BOOL)animated
{
[super viewWillDisappear:animated];
[[NSNotificationCenter defaultCenter] removeObserver:self name:#"OBSERVER NAME" object:nil];
}
This code is working fine...!!!
Try following code
[[NSNotificationCenter defaultCenter] removeObserver:self name:#"notificationame" object:nil];
Can you see the button in the bottom right of the iPad keyboard?
Well I want access to the event handler for that button, Because, I have some logic that I need to administer when specifically THAT button is pressed.
My attempted solution included using the UIKeyboardWillHideNotification notification like so:
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(hideKeyboardTapped:)
name:UIKeyboardWillHideNotification
object:nil];
However this is called everytime the keyboard is dismissed, including when search cancel button is pressed, with a gesture tap on the background, etc; all of which have slightly different logic.
So I just need to have one set of logic for when that specific "hide keyboard" button is pressed.
The UIKeyboard is activated by a UISearchBar (for those of you who need extra info).
Any help would be greatly appreciated; and I'll answer any questions you may have.
There is not an official, Apple-sanctioned way to do this.
If you don't mind mucking around with private classes, which could get you rejected from the App Store, there is an unsupported method. Basically, you listen for changes to the keyboard's activeKey property, and if the new active key has a name of "Dismiss-Key", then the dismiss key was tapped:
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self)
{
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardDidShow:) name:UIKeyboardDidShowNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardWillHide:) name:UIKeyboardWillHideNotification object:nil];
}
return self;
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
if ([keyPath isEqualToString:#"activeKey"])
{
id activeKey = [object valueForKey:keyPath];
NSString *keyName = [activeKey valueForKey:#"name"];
if ([keyName isEqualToString:#"Dismiss-Key"])
{
[self didTapDismissKey];
}
}
else
{
[super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
}
}
- (void)dealloc
{
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
- (void)keyboardDidShow:(NSNotification *)notification
{
// Search for the UIKeyboardLayoutStar class, which seems to manage layout for the keyboard, and observe its activeKey property
UIWindow *topWindow = [UIApplication sharedApplication].windows.lastObject;
[self traverseViewHierarchyWithView:topWindow block:^(UIView *view, BOOL *stop) {
if ([view isKindOfClass:NSClassFromString(#"UIKeyboardLayoutStar")])
{
[view addObserver:self forKeyPath:#"activeKey" options:0 context:NULL];
}
}];
}
- (void)keyboardWillHide:(NSNotification *)notification
{
// Don't forget to remove the controller as an observer!
UIWindow *topWindow = [UIApplication sharedApplication].windows.lastObject;
[self traverseViewHierarchyWithView:topWindow block:^(UIView *view, BOOL *stop) {
if ([view isKindOfClass:NSClassFromString(#"UIKeyboardLayoutStar")])
{
[view removeObserver:self forKeyPath:#"activeKey"];
}
}];
}
- (BOOL)traverseViewHierarchyWithView:(UIView *)view block:(void (^)(UIView *, BOOL *))block
{
BOOL stop = NO;
block(view, &stop);
if (stop)
{
return YES;
}
for (UIView *subview in view.subviews)
{
if ([self traverseViewHierarchyWithView:subview block:block])
{
return YES;
}
}
return NO;
}
- (void)didTapDismissKey
{
NSLog(#"Dismiss key tapped");
}
Tested on the iOS 7 iPad simulator and it works.
I don't know if you can put a listener to a single button of the keyboard, but you can try to set some Booleans on the views, that can turn on/off the events that you want or don't want to handle (I would approach it like that), for example:
Add a custom notification observer/listener at the class where you
want to execute the method of the event.
Add the Apple default Keyboard Hide listener on the controller where the notification will be triggered.
Then, on the views that can trigger the event... Set the booleans to activate/deactivate the event action
#Some Other Class
-(void)viewWillAppear:(BOOL)animated{
[[NSNotificationCenter defaultCenter]addObserver:self
selector:#selector(doSomething)
name:#"doSomethingNotification"
object:nil];
}
-(void)viewWillDisappear:(BOOL)animated{
[[NSNotificationCenter defaultCenter] removeObserver:self name:#"doSomethingNotification" object:nil];
}
#Trigger Class
-(void)viewWillAppear:(BOOL)animated{
self.isNotificationNeeded = NO;
[[NSNotificationCenter defaultCenter]addObserver:self
selector:#selector(onKeyboardHide:)
name:UIKeyboardWillHideNotification
object:nil];
}
-(void)viewWillDisappear:(BOOL)animated{
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillHideNotification object:nil];
}
-(void)onKeyboardHide:(id)sender{
//When your event is Happening
if (self.isNotificationNeeded == YES) {
NSNotification *n = [NSNotification notificationWithName:#"doSomethingNotification" object:nil];
[[NSNotificationCenter defaultCenter] postNotification:n];
self.isNotificationNeeded = NO;
}
}
-(void)userClickedCancelButton{
//If this is a keyboard hide event that you don't want to trigger
self.isNotificationNeeded = NO;
}
//SearchBarDelegate
-(BOOL)searchBarShouldBeginEditing:(UISearchBar *)searchBar{
self.isNotificationNeeded = YES; //If your event can happen from here
return YES;
}
I have an issue with my app..
It's crashing when i'm using home button for multitasking to move to another app and when i want to go back again to my app it's crashing and i get the message:
*** -[UIView convertRect:toView:]: message sent to deallocated instance 0x81e4020
It started since i've implemented "inner-view" ad's.
do i need to do something in my code to make it disspapear?
I tried to solve it but no success.
This is my code of the ad's:
CGRect frame = CGRectMake(0, 480, 320, 50);
self.adBanner = [[UIView alloc] initWithFrame:frame];
[self.view convertRect:adBanner.frame toView:nil]; --->This is a line i tried to put...
[self.view addSubview:self.adBanner];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(iaAdReceived:) name:#"iaAdReceived" object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(iaDefaultAdReceived:) name:#"iaDefaultAdReceived" object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(iaAdFailed:) name:#"IaAdFailed" object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(iaAdClicked:) name:#"IaAdClicked" object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(iaAdWillShow:) name:#"IaAdWillShow" object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(iaAdDidShow:) name:#"IaAdDidShow" object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(iaAdWillHide:) name:#"IaAdWillHide" object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(iaAdDidHide:) name:#"IaAdDidHide" object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(iaAdWillClose:) name:#"IaAdWillClose" object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(iaAdDidClose:) name:#"IaAdDidClose" object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(iaAdWillResize:) name:#"IaAdWillResize" object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(iaAdDidResize:) name:#"IaAdDidResize" object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(iaAdWillExpand:) name:#"IaAdWillExpand" object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(iaAdDidExpand:) name:#"IaAdDidExpand" object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(iaAppShouldSuspend:) name:#"IaAppShouldSuspend" object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(iaAppShouldResume:) name:#"IaAppShouldResume" object:nil];
// Display ad
if (![InneractiveAd DisplayAd:#"iOS_Test" withType:IaAdType_Banner withRoot:self.adBanner withReload:60 withParams:optionalParams])
{
[adBanner removeFromSuperview];
}
}
-(void) viewWillDisappear:(BOOL)animated
{
[super viewWillDisappear:animated];
[adBanner removeFromSuperview];
}
- (IBAction)iaAdReceived:(id)sender
{
// The ad view has finished loading a paid ad
}
- (IBAction)iaDefaultAdReceived:(id)sender
{
// The ad view has finished loading a default ad
}
- (IBAction)iaAdFailed:(id)sender
{
// The ad view has failed to load an ad
}
- (IBAction)iaAdClicked:(id)sender
{
// The ad has been clicked
}
- (IBAction)iaAdWillShow:(id)sender
{
// The ad is about to show
}
- (IBAction)iaAdDidShow:(id)sender
{
// The ad did show
}
- (IBAction)iaAdWillHide:(id)sender
{
// The ad is about to hide
}
- (IBAction)iaAdDidHide:(id)sender
{
// The ad did hide
}
- (IBAction)iaAdWillClose:(id)sender
{
// The ad is about to close
}
- (IBAction)iaAdDidClose:(id)sender
{
// The ad did close
}
- (IBAction)iaAdWillResize:(id)sender
{
// The ad is about to resize
}
- (IBAction)iaAdDidResize:(id)sender
{
// The ad did resize
}
- (IBAction)iaAdWillExpand:(id)sender
{
// The ad is about to expand
}
- (IBAction)iaAdDidExpand:(id)sender
{
// The ad did expand
}
- (IBAction)iaAppShouldSuspend:(id)sender
{
// The app should suspend (for example, when the ad expands)
}
- (IBAction)iaAppShouldResume:(id)sender
{
// The app should resume (for example, when the ad collapses)
}
I attached a screenshot...
What could it be?
Thanks...
Your problem is that when running :
[self.view convertRect:adBanner.frame toView:nil];
your view doesn't exists anymore.
in your appDelegate you should work on this method :
- (void)applicationDidBecomeActive:(UIApplication *)application
{
/*
Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
*/
}
anyway, what did you try to achieve with this line ? because it's returning a CGRect which you're not using.