How do I get access to ToolBar or InputAccessoryView that appears on top of keyboard without using textfield instance

356 Views Asked by At

Whenever keyboard appears in the project , I can find that by adding observer to UIKeyboardWillShowNotification.

But I want to get access to the tool bar that appears on top of the keyboard globally from not from every viewcontroller

Background:

I am using IQKeyboardManager and I am setting buttons on top of the keyboard using it.

IQKeyboardManager doesn't make the tool bar available for external access.

So I'm wondering if there's any way to get access to the keyboard whenever it appears and iterate the items of toolbar that's on top of the keyboard.

Any tips are welcome

Update:

The problem comes from the source code in the POD.

IQUIView+IQKeyboardToolbar.m

  {
  //Flexible space
   [items addObject:[[self class] flexibleBarButtonItem]];
   
   //Title button
   toolbar.titleBarButton.title = titleText;
   if (@available(iOS 11.0, *)) {}
   else
   {
       toolbar.titleBarButton.customView.frame = CGRectZero;
   }

   [items addObject:toolbar.titleBarButton];
   
   //Flexible space
   [items addObject:[[self class] flexibleBarButtonItem]];
    }

Because of the above code in their pod

even though there's no title text in tool bar , it's still being added as an item on the toolbar and so when we turn on the accessibility the empty title button is read as Dimmed button.

I have the fix

   if(titleText){
   //Flexible space
   [items addObject:[[self class] flexibleBarButtonItem]];
   
   //Title button
   toolbar.titleBarButton.title = titleText;
   if (@available(iOS 11.0, *)) {}
   else
   {
       toolbar.titleBarButton.customView.frame = CGRectZero;
   }

   [items addObject:toolbar.titleBarButton];
   
   //Flexible space
   [items addObject:[[self class] flexibleBarButtonItem]];
   }else{
   [items addObject:[[self class] flexibleBarButtonItem]];
   [items addObject:[[self class] flexibleBarButtonItem]];
   [items addObject:[[self class] flexibleBarButtonItem]];

   }

But we can't fix their pod from our side.

So I'm wondering if I could get access of the the tool bar above keyboard , then I can effectively remove the empty item and add the items back into the tool bar again and this would fix my problem.

3

There are 3 best solutions below

0
HangarRash On BEST ANSWER

I strongly urge you to work the patched framework into your build environment since you already know the fix to the framework. Doing so avoids the need to change any of your app's code.

However, the following code could be used as a temporary workaround until the framework is fixed (if ever) by the framework author. The following makes it simple to get access to the inputAccessoryView of any text field or text view in your app each time the text field or text view becomes first responder.

Add these two lines to your app delegate's didFinishLaunchingWithOptions method:

Objective-C:

[NSNotificationCenter.defaultCenter addObserver:self selector:@selector(beginEditingHandler:) name:UITextFieldTextDidBeginEditingNotification object:nil];
[NSNotificationCenter.defaultCenter addObserver:self selector:@selector(beginEditingHandler:) name:UITextViewTextDidBeginEditingNotification object:nil];

Swift:

NotificationCenter.default.addObserver(self, selector: #selector(beginEditingHandler), name: UITextField.textDidBeginEditingNotification, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(beginEditingHandler), name: UITextView.textDidBeginEditingNotification, object: nil)

And add this method to your app delegate class:

Objective-C:

- (void)beginEditingHandler:(NSNotification *)notification {
    UIResponder *responder = notification.object;
    UIView *inputAccessoryView = responder.inputAccessoryView;
    if (inputAccessoryView) {
        // Process the inputAccessoryView as needed
    }
}

Swift:

@objc func beginEditingHandler(_ notification: NSNotification) {
    if let responder = notification.object as? UIResponder, let inputAccessoryView = responder.inputAccessoryView {
        // Process the inputAccessoryView as needed
    }
}

I'm not familiar with the framework you are using so I don't know how to get the toolbar from the input accessory view. It could be as simple as trying to cast inputAccessoryView as? UIToolbar or you might have to see if there is a subview of inputAccessoryView that is a UIToolbar.

0
Faisal Memon On

The way I see it, you have an external dependency which you cannot change (because it will take a while to upstream your fix into their official release) but you have a fix you want in their code right now.

So one way to workaround it, whilst staying within your working practices, is to have an Xcode build script phase in your project which 'patches' the files of the Pod before compilation. See the command /usr/bin/diff and /usr/bin/patch for creating and applying patches.

7
Afzal K. On

Since you dont want to do it via inputAccessoryView then you can do it via UIKeyboardWillShowNotification observer and get the UIKeyboardFrameEndUserInfoKey from the notification's userInfo dictionary to get the frame of the keyboard and From there you can get the frame of the input accessory view and do any modifications on it.

c'mon, it's not that hard

- (void)viewDidLoad {
    [super viewDidLoad];
    
    // to listen for notification when keyboard appears
    [[NSNotificationCenter defaultCenter] addObserver:self 
        selector: @selector(handleNotification:) 
        name:UIKeyboardWillShowNotification 
        object: nil];
}

// when keyboard appears to handle it
- (void)handleNotification:(NSNotification *)notification {
    // notification's userInfo dictionary to get frame of the keyboard
    CGRect keyboardFrame = [notification.userInfo[UIKeyboardFrameEndUserInfoKey] CGRectValue];
    
    // get input accessory view from current first responder
    UIView *inputAccessoryView = [[UIApplication sharedApplication] keyWindow].firstResponder.inputAccessoryView;
    
    // now its accessed, make changes
    inputAccessoryView.backgroundColor = [UIColor greenColor];
}
    // remove observer
- (void)dealloc {
    [[NSNotificationCenter defaultCenter] removeObserver:self];
}