hackiftekhar / IQKeyboardManager

Codeless drop-in universal library allows to prevent issues of keyboard sliding up and cover UITextField/UITextView. Neither need to write any code nor any setup required and much more.
MIT License
16.45k stars 2.41k forks source link

Keyboard flashes down from the top of the screen upon removeFromSuperview/addSubview #1571

Closed BillBunting closed 5 years ago

BillBunting commented 5 years ago

Describe the bug When a TextView is displayed within a UISearchBar that is part of a UITableView UISearchController and the view is removed and added (to force the search bar bookmark or other icon to change to a custom icon), then the keyboard will flash down from the top of the screen and the keyboard manager will stop working properly in all text fields/ This is an obscure use case for sure, but I felt it worth mentioning just in case there are others with a similar problems related to adding and removing views that display keyboards or for others that modify and remove/add subviews views within the search bar

[view removeFromSuperview]; [window addSubview:view];

Expected behavior The keyboard should not flash down from the top of the screen, ever.

Versions

Xcode: 10.1 Simulator/Device: iOS 12 Simulator/Device Name: iPhone X (any) Library Version: 6.4.0

hackiftekhar commented 5 years ago

Hmm, can you please share demo project so I can take a look.

BillBunting commented 5 years ago

@hackiftekhar ,

Thank you for your quick response.

The easiest way to reproduce problem is to add the following method, refreshViews, to the Objective_C_Demo demo app and call it from the top of shareClicked as shown below.

In the demo app, select the share icon which will trigger the code causing the issue. Note that the keyboard manager does not render correctly following the call to refreshViews and seems to "disconnect" and no longer function properly in possibly several ways. It will no longer display navigation above the keyboard nor will it scroll the views up.

//
//  ViewController.m
//  KeyboardTextFieldDemo

#import "ViewController.h"
#import "IQKeyboardManager.h"

@interface ViewController ()<UIPopoverPresentationControllerDelegate>

@end

@implementation ViewController

- (void)refreshViews {
    for (UIWindow *window in [UIApplication sharedApplication].windows) {
        for (UIView *view in window.subviews) {
            [view removeFromSuperview];
            [window addSubview:view];
        }
    }
}

- (IBAction)shareClicked:(UIBarButtonItem *)sender
{
    [self refreshViews];

    NSString *shareString = @"IQKeyboardManager is really great control for iOS developer to manage keyboard-textField.";
    UIImage *shareImage = [UIImage imageNamed:@"IQKeyboardManagerScreenshot"];
    NSURL *youtubeUrl = [NSURL URLWithString:@"http://youtu.be/6nhLw6hju2A"];

    NSArray *activityItems = @[youtubeUrl,
                              shareString,
                              shareImage];

    UIActivityViewController *controller = [[UIActivityViewController alloc] initWithActivityItems:activityItems applicationActivities:nil];
    NSArray *excludedActivities = @[UIActivityTypePrint,
                                    UIActivityTypeCopyToPasteboard,
                                    UIActivityTypeAssignToContact,
                                    UIActivityTypeSaveToCameraRoll];
    controller.excludedActivityTypes = excludedActivities;
    [self presentViewController:controller animated:YES completion:nil];
}

The reason I am calling refreshViews is because it was the only way I could find to dynamically swap out the bookmark icon contained within a UITable's UISearchController and then change it again later after viewDidLoad or viewWillAppear. The following code is used after a user selected the replaced bookmark button which needs to change to indicate search filter state.

[UISearchBar.appearance setImage:[UIImage imageNamed:@"filterIconActive"] forSearchBarIcon:UISearchBarIconBookmark state:UIControlStateNormal];
BillBunting commented 5 years ago

I found a potential workaround that does not interfere with IQKeyboardManager. The code now does not remove the internal UITextEffectsWindows and then the IQKeyboardManager is not affected.

    for (UIWindow *window in [UIApplication sharedApplication].windows) {
        if ([NSStringFromClass([window class]) isEqualToString:@"UITextEffectsWindow"] == false) {
            for (UIView *view in window.subviews) {
                [view removeFromSuperview];
                [window addSubview:view];
            }
        }
    }
hackiftekhar commented 5 years ago

However what you are doing is looking a non-standard approach. We should not add/remove any subviews of UIWindow object. It may lead to undesired behavior.