13

When I tap a textfield at the bottom of the screen, the keyboard appears and hides the active element. On iOS, it works perfect.

I'm able to scroll the form, so the textfield is in the visible area, but that's not nice at all. Am I doing something wrong or is this a known bug as I have the same behaviour in this example from Sencha Touch itself: docs.sencha.com/touch/2-1/touch-build/examples/forms/

If on this form:

enter image description here

I tap in the textfield of "Bio", the keyboard hides the textfield, instead of scrolling the textfield up to have it visible while typing:

enter image description here

swalkner
  • 16,679
  • 31
  • 123
  • 210

5 Answers5

11

This is definitively a known-issue, I've seen this many times on Android. The only thing you can try to do is listen for a focus event on the input field and then scroll to the element. You might have to play around with the right Y-value, which suits your situation best.

{
    xtype: 'textareafield',
    name: 'bio',
    label: 'Bio',
    maxRows: 10,
    listeners: {
        focus: function(comp, e, eopts) {
            var ost = comp.element.dom.offsetTop;
            this.getParent().getParent().getScrollable().getScroller().scrollTo(0, ost);
        }
    }
},

This works for me. If you need any help implementing this, let me know!

enter image description here

Rob
  • 4,927
  • 12
  • 49
  • 54
  • I changed it to `comp.getParent().getScrollable().getScroller().scrollTo(0, e.target.clientHeight);`, but it still doesn't work, unfortunately... the code is called and in desktop-chrome it seems like it scrolls a little bit, on android it doesn't... – swalkner Mar 26 '13 at 20:43
  • Well, that's probably not going to work because you will target the `fieldset`. In my own working version of the Sencha Form example i have `this.getParent().getParent().getScrollable().getScroller().scrollTo(0, e.target.clientHeight);` (this refers to the scroller of the form). If this still isn't working, can you see if any javascript errors are thrown in Android? – Rob Mar 27 '13 at 07:39
  • I just added a demo where you can see my example working on the `bio` field. – Rob Mar 27 '13 at 07:53
  • still no luck with my android in your example... when tapping into the bio-field, my keyboard hides the field – swalkner Mar 27 '13 at 19:43
  • still no luck, unfortunately... please see my video here: https://dl.dropbox.com/u/119600/sencha.MOV (~ 10 MB) – swalkner Mar 28 '13 at 06:17
  • @swalkner Hey man, i finally managed to get a really decent solution after a few hours. Take a look at the example and see it works (Make sure your not caching anything!). If it is still not working, would you post your device and your OS version? – Rob Mar 28 '13 at 09:55
  • looks promising now :) I'll have a look at it later! – swalkner Mar 29 '13 at 16:18
6

Less intrusive solution:

on Application launch method add the following lines:

launch: function() {
    if (Ext.os.is.Android) { //maybe target more specific android versions.
        Ext.Viewport.on('painted', function() {
            Ext.Viewport.setHeight(window.innerHeight);
        });
    }
    // ... rest of the launch method here
}

This works just fine on many cases I have been testing on. Both Cordova and Chrome implementations. You just need to take care, in case of Cordova/Phonegap app, that the fullscreen is set to false. (Tested on Cordova 3.5)

elmasse
  • 221
  • 2
  • 4
1

The "Ext.Viewport.on('painted'"-solution gave me scrolling problem. The whole page could not be scrolled after orientation change, because viewport height would then be larger than window height. (Ext.Viewport.getHeight() will not be the same as Ext.Viewport.getWindowHeight() after orientation change.)

Made a work around using overidden input:

Create a file app/overrides/field/Input.js

Ext.define('myApp.overrides.field.Input', {
  override: 'Ext.field.Input',

  initialize: function() {
    var me = this;

    // Solves problem that screen keyboard hides current textfield
    if (Ext.os.is.Android) {
        this.element.on({
            scope      : this,
            tap        : 'onTap',
        });
    }

    me.callParent();
  },

  onResize: function(input) {
    var me = input;
    //if input is not within window
    //defer so that resize is finished before scroll
    if(me.element.getY() + me.element.getHeight() > window.innerHeight) {
        Ext.Function.defer(function() {
            me.element.dom.scrollIntoView(false);
        }, 100);
    }
  },

  // Solves problem that screen keyboard hides current textfield in e.g. MyTimeRowForm
  //old solution with Viewport.on('painted', gave scroll problem when changeing orientation
  onTap: function(e) {
    me = this;
    window.addEventListener( "resize", function resizeWindow () {
        me.onResize(me);
        window.removeEventListener( "resize", resizeWindow, true );
    }, true );
  },   
});

And add it to app.js

requires: ['myApp.overrides.field.Input']
kaah
  • 121
  • 1
  • 3
0

You may subscribe on show/hide events of keyboard and compensate input's offset. It's been tested on Android 4.2 & 4.4 (HTC One & Nexus 7).

if (Ext.os.is.Android4 && Ext.os.version.getMinor() >= 2) {
    (function() {
        var inputEl = null;
        var onKeyboardShow = function() {
            setTimeout(function() {
                if (!inputEl) {
                    return;
                }
                var currentClientHeight = window.document.body.clientHeight;
                var elRect = inputEl.getBoundingClientRect();
                var elOffset = elRect.top + elRect.height;
                if (elOffset <= currentClientHeight) {
                    return;
                }
                var offset = currentClientHeight - elOffset;
                setOffset(offset);
            }, 100);
        };
        var onKeyboardHide = function() {
            setOffset(0);
        };
        var setOffset = function(offset) {
            var el = Ext.Viewport.innerElement.dom.childNodes[0];
            if (el) {
                el.style.setProperty('top', offset + 'px');
            }
        };
        document.addEventListener('deviceready', function() {
            document.addEventListener("hidekeyboard", onKeyboardHide, false);
            document.addEventListener("showkeyboard", onKeyboardShow, false);
        }, false);
        Ext.define('Ext.field.Input.override', {
            override: 'Ext.field.Input',
            onFocus: function(e){
                inputEl = e.target;
                this.callParent(arguments);
            },
            onBlur: function(e){
                inputEl = null;
                this.callParent(arguments);
            }
        })
    })();
}
CruorVult
  • 823
  • 1
  • 9
  • 17
0

It worked better for me

{
   xtype: 'passwordfield',
   name: 'pass',
   listeners: {
      focus: function (comp, e, eopts) {
        var contr = this;
        setTimeout(function () {
          if (Ext.os.is('Android')) {
            var ost = comp.element.dom.offsetTop;
            contr.getParent().getParent().getScrollable().getScroller().scrollTo(0, ost, true);
          }
        }, 400);
      }
   }
}
Natt
  • 45
  • 9