cordova-plugin-keyboard icon indicating copy to clipboard operation
cordova-plugin-keyboard copied to clipboard

shrinkView not work on iOS12

Open ActNotSign opened this issue 6 years ago • 28 comments

have solution ? it's bug ?

ActNotSign avatar Sep 20 '18 09:09 ActNotSign

please put screenshots and more detailled issue

Aarbel avatar Sep 20 '18 11:09 Aarbel

Hello,

I have the same issue after upgrading to iOS 12. When I click on a textarea, and keyboard shows up, it takes the HTML contents of the page "too high". There is also a new vertical scrollbar, which I can use to bring the contents back to its normal place - right above the keyboard. I can also pull it back atop again if I swipe up on non-scrollable area of my application.

Here are the screenshots how it looks like: https://www.screencast.com/t/DpbAwwOmhBO - initially after opening the keyboard https://www.screencast.com/t/7D9Fapjel8 - scrolled down a bit And from native perspective: https://www.screencast.com/t/mHI6ZIyRZ

UPD. If I set Keyboard.disableScrollingInShrinkView(true), the vertical scrolling is not longer available, so that the visible HTML is always stuck at the top.

Please, take a look at this. In the meanwhile, I will try to find my way around on my own and find a fix.

Thanks, Andrey.

EternallLight avatar Sep 21 '18 14:09 EternallLight

@cjpearson

Aarbel avatar Sep 21 '18 14:09 Aarbel

I was poking around -shrinkViewKeyboardWillChangeFrame: to see what the before and after sizes were when I noticed self.webView.scrollView.contentSize was still incorrect at the end on iOS 12 only -- it was fine on iOS 11.

I'm sure there's a better way, but this is how I'm hacking my way around the problem until the maintainers have a chance to take a look for a real solution. The new bits are the two checks for iOS 12.

Full file: https://gist.github.com/mattio/ba5d77474e725463bc75cfbf1dba0cca

- (void)shrinkViewKeyboardWillChangeFrame:(NSNotification*)notif
{
    // No-op on iOS 7.0.  It already resizes webview by default, and this plugin is causing layout issues
    // with fixed position elements.  We possibly should attempt to implement shrinkview = false on iOS7.0.
    // iOS 7.1+ behave the same way as iOS 6
    if (NSFoundationVersionNumber < NSFoundationVersionNumber_iOS_7_1 && NSFoundationVersionNumber > NSFoundationVersionNumber_iOS_6_1) {
        return;
    }
    
    // If the view is not visible, we should do nothing. E.g. if the inappbrowser is open.
    if (!(self.viewController.isViewLoaded && self.viewController.view.window)) {
        return;
    }
    
    self.webView.scrollView.scrollEnabled = YES;
    
    CGRect screen = [[UIScreen mainScreen] bounds];
    CGRect statusBar = [[UIApplication sharedApplication] statusBarFrame];
    CGRect keyboard = ((NSValue*)notif.userInfo[@"UIKeyboardFrameEndUserInfoKey"]).CGRectValue;
    
    // Work within the webview's coordinate system
    keyboard = [self.webView convertRect:keyboard fromView:nil];
    statusBar = [self.webView convertRect:statusBar fromView:nil];
    screen = [self.webView convertRect:screen fromView:nil];
    
    // if the webview is below the status bar, offset and shrink its frame
    if ([self settingForKey:@"StatusBarOverlaysWebView"] != nil && ![[self settingForKey:@"StatusBarOverlaysWebView"] boolValue]) {
        CGRect full, remainder;
        CGRectDivide(screen, &remainder, &full, statusBar.size.height, CGRectMinYEdge);
        screen = full;
    }
    
    // Get the intersection of the keyboard and screen and move the webview above it
    // Note: we check for _shrinkView at this point instead of the beginning of the method to handle
    // the case where the user disabled shrinkView while the keyboard is showing.
    // The webview should always be able to return to full size
    CGRect keyboardIntersection = CGRectIntersection(screen, keyboard);
    if (CGRectContainsRect(screen, keyboardIntersection) && !CGRectIsEmpty(keyboardIntersection) && _shrinkView && self.keyboardIsVisible) {
        // I'm sure there's a better way...
        if (@available(iOS 12, *)) {
            self.webView.scrollView.scrollEnabled = !self.disableScrollingInShrinkView; // Order intentionally swapped.
            screen.size.height -= keyboardIntersection.size.height;
            
            CGSize revisedSize = CGSizeMake(self.webView.scrollView.frame.size.width, self.webView.scrollView.frame.size.height - keyboard.size.height);
            self.webView.scrollView.contentSize = revisedSize;
        }
        else {
            screen.size.height -= keyboardIntersection.size.height;
            self.webView.scrollView.scrollEnabled = !self.disableScrollingInShrinkView;
        }
    }
    
    // A view's frame is in its superview's coordinate system so we need to convert again
    self.webView.frame = [self.webView.superview convertRect:screen fromView:self.webView];
  
    // I'm sure there's a better way...
    if (@available(iOS 12, *)) {
        CGSize revisedSize = CGSizeMake(self.webView.frame.size.width, self.webView.frame.size.height - keyboard.size.height);
        self.webView.scrollView.contentSize = revisedSize;
    }
}

mattio avatar Sep 28 '18 20:09 mattio

I was poking around -shrinkViewKeyboardWillChangeFrame: to see what the before and after sizes were when I noticed self.webView.scrollView.contentSize was still incorrect at the end on iOS 12 only -- it was fine on iOS 11.

I'm sure there's a better way, but this is how I'm hacking my way around the problem until the maintainers have a chance to take a look for a real solution. The new bits are the two checks for iOS 12.

Full file: https://gist.github.com/mattio/ba5d77474e725463bc75cfbf1dba0cca

- (void)shrinkViewKeyboardWillChangeFrame:(NSNotification*)notif
{
    // No-op on iOS 7.0.  It already resizes webview by default, and this plugin is causing layout issues
    // with fixed position elements.  We possibly should attempt to implement shrinkview = false on iOS7.0.
    // iOS 7.1+ behave the same way as iOS 6
    if (NSFoundationVersionNumber < NSFoundationVersionNumber_iOS_7_1 && NSFoundationVersionNumber > NSFoundationVersionNumber_iOS_6_1) {
        return;
    }
    
    // If the view is not visible, we should do nothing. E.g. if the inappbrowser is open.
    if (!(self.viewController.isViewLoaded && self.viewController.view.window)) {
        return;
    }
    
    self.webView.scrollView.scrollEnabled = YES;
    
    CGRect screen = [[UIScreen mainScreen] bounds];
    CGRect statusBar = [[UIApplication sharedApplication] statusBarFrame];
    CGRect keyboard = ((NSValue*)notif.userInfo[@"UIKeyboardFrameEndUserInfoKey"]).CGRectValue;
    
    // Work within the webview's coordinate system
    keyboard = [self.webView convertRect:keyboard fromView:nil];
    statusBar = [self.webView convertRect:statusBar fromView:nil];
    screen = [self.webView convertRect:screen fromView:nil];
    
    // if the webview is below the status bar, offset and shrink its frame
    if ([self settingForKey:@"StatusBarOverlaysWebView"] != nil && ![[self settingForKey:@"StatusBarOverlaysWebView"] boolValue]) {
        CGRect full, remainder;
        CGRectDivide(screen, &remainder, &full, statusBar.size.height, CGRectMinYEdge);
        screen = full;
    }
    
    // Get the intersection of the keyboard and screen and move the webview above it
    // Note: we check for _shrinkView at this point instead of the beginning of the method to handle
    // the case where the user disabled shrinkView while the keyboard is showing.
    // The webview should always be able to return to full size
    CGRect keyboardIntersection = CGRectIntersection(screen, keyboard);
    if (CGRectContainsRect(screen, keyboardIntersection) && !CGRectIsEmpty(keyboardIntersection) && _shrinkView && self.keyboardIsVisible) {
        // I'm sure there's a better way...
        if (@available(iOS 12, *)) {
            self.webView.scrollView.scrollEnabled = !self.disableScrollingInShrinkView; // Order intentionally swapped.
            screen.size.height -= keyboardIntersection.size.height;
            
            CGSize revisedSize = CGSizeMake(self.webView.scrollView.frame.size.width, self.webView.scrollView.frame.size.height - keyboard.size.height);
            self.webView.scrollView.contentSize = revisedSize;
        }
        else {
            screen.size.height -= keyboardIntersection.size.height;
            self.webView.scrollView.scrollEnabled = !self.disableScrollingInShrinkView;
        }
    }
    
    // A view's frame is in its superview's coordinate system so we need to convert again
    self.webView.frame = [self.webView.superview convertRect:screen fromView:self.webView];
  
    // I'm sure there's a better way...
    if (@available(iOS 12, *)) {
        CGSize revisedSize = CGSizeMake(self.webView.frame.size.width, self.webView.frame.size.height - keyboard.size.height);
        self.webView.scrollView.contentSize = revisedSize;
    }
}

like this ?

CGRect keyboardIntersection = CGRectIntersection(screen, keyboard); if (CGRectContainsRect(screen, keyboardIntersection) && !CGRectIsEmpty(keyboardIntersection) && _shrinkView && self.keyboardIsVisible) { if (@available(iOS 12, *)) { CGSize revisedSize = CGSizeMake(self.webView.frame.size.width, screen.size.height); self.webView.scrollView.contentSize = revisedSize; } screen.size.height -= keyboardIntersection.size.height; self.webView.scrollView.scrollEnabled = !self.disableScrollingInShrinkView; } // A view's frame is in its superview's coordinate system so we need to convert again self.webView.frame = [self.webView.superview convertRect:screen fromView:self.webView];

ActNotSign avatar Sep 29 '18 11:09 ActNotSign

I would replace the entire shrinkViewKeyboardWillChangeFrame: method with what I have above and see if it solves your problem. It worked for me, but your situation might be different. Keep in mind that, depending on your build process, your manual edits might get overwritten and you may need to make them each time.

mattio avatar Oct 02 '18 13:10 mattio

Just as another reference, right after tapping the input:

screen shot 2018-10-02 at 21 59 45

@EternallLight did you figure out a workaround by any chance?

Birowsky avatar Oct 02 '18 20:10 Birowsky

@Birowsky oh, it seems like you're having the same problem... I've been fighting with this for a few days and ended up using WkWebView instead of UIWebView - cordova-plugin-wkwebview-engine or cordova-plugin-ionic-webview. However, it broke all http requests (the CORS issue) and displaying images from cdvfile:// URL (hello, imagecache.js). To fix HTTP requests, I used cordova-plugin-wkwebview-file-xhr - had to manually remove cordova-plugin-wkwebview-engine from its dependencies in config.xml; for cdvfile - ended up with hacking imagecache.js. But, cordova-plugin-wkwebview-file-xhr caused another issues with angular-file-upload that keeps the native FormData under the closure before it is replaced with a the cordova-plugin-wkwebview-file-xhr FormData polyfill. The good part - there are no issues with keyboard at all :) You know what else is strange? Today, I installed our production app from the AppStore, which is supposed to be broken - and it works perfectly! No idea what important I could have changed since then. It seems like WkWebView has some performance benefits, so hope it all was not in vein.

EternallLight avatar Oct 02 '18 20:10 EternallLight

Hello Friends!

I've taken @mattio's lovely patch, and applied it into a branch. I am not planning to release the branch to npm, so here is a quick start for how to use the patch without needign to fork on your own:

  1. Clone https://github.com/wecohere/cordova-plugin-keyboard
  2. Checkout the zs-fix-keyboard branch
  3. cordova plugin add relative/path/to/the/cloned/cordova-plugin-keyboard
  4. cordova build

It's not perfect, but it will get things by until the maintainer choose to merge or implements a better version.

If you need it in CI, I don't know how to help with that since I do my builds locally :/. Sorry! Maybe someone with more wisdom than I can help with that.

zspencer avatar Oct 22 '18 23:10 zspencer

@zspencer thank you for this fix. It resolved the problem for me. Hopefully they soon get that patch into the public npm. I had the tires spinning and going nowhere. This patch got the car out of the sludge. Appreciation x 1000

jremi avatar Oct 26 '18 16:10 jremi

@jremi - Unfortunately, the patched version seems to be hit-or-miss across devices and iOS versions. The alternative I wound up finally going with is adding both cordova-plugin-ionic-webview and cordova-plugin-ionic-keyboard to the project.

This, so far, has provided the smoothest user experience for keyboards appearing and disappearing in my cordova app, but did have a minor bump in the road: The README for cordova-plugin-ionic-webview tells you to set the WKPort value. However that resulted in the app launching safari every time the app started. I set it back to the default and everything worked and I have something close to keyboard bliss.

For future reference, here are the relevant snippets of my config.xml, which are not that exciting and probably not that useful:

    <plugin name="cordova-plugin-ionic-webview" spec="^2.2.0">
        <variable name="ANDROID_SUPPORT_ANNOTATIONS_VERSION" value="27.+" />
    </plugin>
    <preference name="WKPort" value="8080" />
    <plugin name="cordova-plugin-ionic-keyboard" spec="2.1.3" />

My understanding is that the bug lies in iOS 12 UIWebViews, which are deprecated by Apple; so moving off of UIWebView to WKWebViews, either via the Cordova maintained wkwebview-engine or cordova-plugin-ionic-webview is likely to provide most consistent maintenance experience moving forward.

zspencer avatar Oct 26 '18 16:10 zspencer

@zspencer i am actually not using ionic with my cordova app. I am using cordova + framework7. Good to know. Thanks for info

jremi avatar Oct 26 '18 16:10 jremi

To clarify, I am also not using ionic, the cordova-plugin-ionic-webview provides a solid WKWebView implementation for non-ionic apps.

zspencer avatar Oct 26 '18 16:10 zspencer

ah good you said that. Maybe i will drop these in then.

jremi avatar Oct 26 '18 16:10 jremi

  1. https://github.com/wecohere/cordova-plugin-keyboard

@zspencer THANK YOU! Your fork was a massive help for me. There are still some rough edges that the ionic team needs to address with a proper fix but this got my app into a usable state. Much appreciated!

startupfoundry avatar Nov 06 '18 03:11 startupfoundry

@zspencer i am actually not using ionic with my cordova app. I am using cordova + framework7. Good to know. Thanks for info

we are also facing the same issue. can you please let me know how to fix the issue .

edvenkat avatar Nov 21 '18 10:11 edvenkat

Hi, How did you solved the issue? @cjpearson The patch of @mattio didn't solved the issues for me and also if I install the cordova-plugin-wkwebview-engine the app don't run.. I have the same problem the @Birowsky 's screenshot

mallociFrancesca avatar Dec 07 '18 16:12 mallociFrancesca

Hey @edvenkat and @mallociFrancesca - I don't know that I can help shed much more light on this, other than to say that using cordova-plugin-ionic-webview is not a drop-in replacement; and may require you to adjust your config.xml and/or software design in order for it to work correctly.

I'm more than happy to set up a paid remote pairing session where we step through your code and get it working. Feel free to reach out via any of the means I've listed on my website.

zspencer avatar Dec 08 '18 20:12 zspencer

@mattio and @zspencer currently i am using ur branch but i am facing the below issue (refer below link) above 12.0 can you please tell the solution for this?

for your reference https://camo.githubusercontent.com/e19923ed896d8232238d4714c04243f27f386437/687474703a2f2f692e696d6775722e636f6d2f514458307457512e676966

edvenkat avatar Jan 10 '19 10:01 edvenkat

The solution remains to switch off the built in browser an onto the ionic maintained webview and keyboard plugins, per this comment - https://github.com/cjpearson/cordova-plugin-keyboard/issues/77#issuecomment-43346755

zspencer avatar Jan 10 '19 19:01 zspencer

@zspencer i not good in objective-c how can i switch the plugin on or off with paramter ??

dizzlr avatar Jan 27 '19 01:01 dizzlr

Sadly, the README for cordova-plugin-ionic-webview does not include installation instructions, but I believe it is because they expect users to know how to use [cordova plugin add](https://cordova.apache.org/docs/en/latest/reference/cordova-cli/#cordova-plugin-command)

I would recommend also running cordova plugin rm cordova-plugin-keyboard and cordova clean (or do a cordova platform rm ios and cordova platform rm android to ensure you don't have leftover copies of this particular plugin anymore.

zspencer avatar Jan 27 '19 02:01 zspencer

thanks @zspencer but i looking for way or function on your branch that stop the cordova keyboard plugin and make it work with parameter because the plugin working fine in some views and some views make trouble so i want way to fire and stop it 😊 thanks in advance

dizzlr avatar Jan 27 '19 08:01 dizzlr

That is the reason why I abandoned trying to make this plugin work and just used the ionic one. The ionic webview works in every single case, whereas this plugin works in most but not all cases; and trying to manage those cases was going to be a nightmare.

It took me about 2 hours to get ionic-webview set up; I strongly encourage you to take the time to investigate it for yourself. You can keep going down the rabbit hole of trying to make this plugin work for your situation, but it's unlikely to be fruitful.

But maybe it will be and I'll learn something!

zspencer avatar Jan 27 '19 19:01 zspencer

This same issue is also present on iOS 13. :/

The Ionic flavor of this plugin is also broken for this same feature despite having more activity than this plugin.

brianespinosa avatar Oct 21 '19 19:10 brianespinosa

Hello Friends!

I've taken @mattio's lovely patch, and applied it into a branch. I am not planning to release the branch to npm, so here is a quick start for how to use the patch without needign to fork on your own:

  1. Clone https://github.com/wecohere/cordova-plugin-keyboard
  2. Checkout the zs-fix-keyboard branch
  3. cordova plugin add relative/path/to/the/cloned/cordova-plugin-keyboard
  4. cordova build

It's not perfect, but it will get things by until the maintainer choose to merge or implements a better version.

If you need it in CI, I don't know how to help with that since I do my builds locally :/. Sorry! Maybe someone with more wisdom than I can help with that.

your solution is perfect .. can you make it public? because I use the phonegap build

AdrianoGeraldeli avatar May 22 '20 13:05 AdrianoGeraldeli

@AdrianoGeraldeli - it is public, but you'll have to do the gitwizardry yourself :). I am not really bought into the cordova ecosystem enough to take on maintenance of a public project within it.

I'm happy to do paid pairing sessions to help people solve this problem, just send me an email? [email protected]

zspencer avatar May 22 '20 18:05 zspencer

Using this command can add the plugin easily

cordova plugin add https://github.com/wecohere/cordova-plugin-keyboard#zs-fix-keyboard --nofetch 

Constaline avatar Jun 12 '20 06:06 Constaline