Titanium JIRA Archive
Titanium SDK/CLI (TIMOB)

[TIMOB-6745] Android: UI - TextField's "focus" event is fired without user interaction

GitHub Issuen/a
TypeBug
PriorityHigh
StatusResolved
ResolutionCannot Reproduce
Resolution Date2013-04-26T07:55:58.000+0000
Affected Version/sRelease 1.7.5
Fix Version/s2013 Sprint 09
ComponentsAndroid
Labelsapi
ReporterIvan Skugor
Assigneejithinpv
Created2011-11-24T05:07:00.000+0000
Updated2016-11-11T05:36:05.000+0000

Description

Behavior

It seems that "focus" event doesn't work well on Android and this behavior cause awful user experience. To see the issue, run the test case below. Scroll to the bottom, but don't touch text fields. You'll see in the console output that text field fired "focus" event and that keyboard has shown on the screen. Also, scroll to the bottom, click "Click me!" button to open new window. Then, click "Close me!" button. ScrollView should be scrolled up to the text field that has "focus" (gained by a bug described above!), which creates awful user experience because user needs to scroll back to where he was before opening new window (ScrollView should not scroll after returning from newly created window).

Test case

var win = Ti.UI.createWindow({
	backgroundColor: '#000',
	modal: true,
	navBarHidden: true,
	layout: 'vertical'
});

function createItem() {
	var view = Ti.UI.createView({
		height: 100,
		width: '100%',
		layout: 'horizontal'
	});
	
	var label = Ti.UI.createLabel({
		text: 'Testing ...',
		width: '50%'
	});
	
	var checkbox = Ti.UI.createSwitch({
		style: Ti.UI.Android.SWITCH_STYLE_CHECKBOX
	});
	
	view.add(label);
	view.add(checkbox);
	
	return view;
}

function createTextField() {
	
	var view = Ti.UI.createView({
		height: 100,
		width: '100%',
		backgroundColor: '#0ff',
		layout: 'horizontal'
	});
	
	var label = Ti.UI.createLabel({
		text: 'Text field ...',
		width: '50%'
	});
	
	var textField = Ti.UI.createTextField({
		width: '30%'
	});
	
	textField.addEventListener('focus', function() {
		Ti.API.info('Focus fired');
	});
	
	view.add(label);
	view.add(textField);
	
	return view;
}

var scrollView = Ti.UI.createScrollView({
	layout: 'vertical',
	backgroundColor: '#f00',
	showVerticalScrollIndicator: true,
	height: '100%',
	width: '100%',
	contentHeight: 'auto',
	contentWidth: 'auto',
	top: 0
});

for (var m = 0; m < 3; ++m) {
	for (var i = 0; i < 20; ++i) {
		scrollView.add(createItem());
	}
	var view = createTextField();
	scrollView.add(view);
}

for (var j = 0; j < 20; ++j) {
	scrollView.add(createItem());
}

var button = Ti.UI.createButton({ title: 'Click me!' });

button.addEventListener('click', function() {
	var context = Ti.UI.createWindow({
		backgroundColor: '#000',
		modal: true,
		navBarHidden: true,
		layout: 'vertical'
	});
	
	var closeButton = Ti.UI.createButton({ title: 'Close me!' });
	
	closeButton.addEventListener('click', function() {
		context.close();
	});
	
	context.add(closeButton);
	
	context.open();
});

scrollView.add(button);

win.add(scrollView);

Ti.API.info('App runnning ...');

win.open();

Comments

  1. Ivan Skugor 2011-12-01

    I have more info about this issue. It seems that this problem does not exist if user press-hold-and-scroll through scroll view component very slowly. So, to **not** see the issue, you have to press scroll view area, hold it and slowly scroll down and release your finger. The issue can be seen only if user tap-and-scroll. I hope you understand what I mean, it's hard to explain. If you need more explanation, please let me know.
  2. Ivan Skugor 2012-03-12

    I would really appreciate if this issue could be scheduled because there is no workaround. Thanks.
  3. Hieu Pham 2012-06-11

    This is native Android behavior. Android will try to switch focus to the first visible focusable view. Here's a couple articles that talk about it: http://stackoverflow.com/questions/5375838/scrollview-disable-focus-move http://stackoverflow.com/questions/8100831/stop-scrollview-from-setting-focus-on-edittext I'm sure its annoying but I'm not sure whether its a good idea to diverge from native behavior.
  4. Neeraj Gupta 2012-06-11

    Marking it invalid since the Titanium behavior matches with the native behavior.
  5. Ivan Skugor 2012-06-12

    If native behavior creates awful UX, then I don't see a reason why Titanium should blindly stick to native behavior (if some native functionality has a bug, would you leave that bug in Titanium?). I doubt that Titanium developers want to have buggy native behavior. Instead, I think that they want something that works as it should. Users don't care about native-like behavior, they want to have nice UX. With this bug, that is not possible to achieve. Anyway, is there any workaround? I tried to set "focusable" to "false" and then on "click" event change "focusable" event, but that didn't work:
           var textField = Ti.UI.createTextField({
           	top: 150,
           	left: 50,
           	width: '150dp',
           	focusable: false,
           	height: '75dp',
           });
           
           textField.addEventListener('click', function() {
           	textField.setFocusable(true);
           });
       
    It seems that "focusable" property cannot be changed after TextField is rendered. Is there any other way? :( Thanks.
  6. Ivan Skugor 2012-06-12

  7. Shawn Lipscomb 2012-06-12

    Ivan, would setting the windowSoftInputMode property of the window have any effect on this?
  8. Ivan Skugor 2012-06-12

    Thanks Shawn, but unfortunately that has no effect.
  9. Ivan Skugor 2012-06-12

    I found a workaround (Shawn suggestion pushed me in right direction :) ). The solution is this:
       var textField = Ti.UI.createTextField({
           softKeyboardOnFocus : Ti.UI.Android.SOFT_KEYBOARD_HIDE_ON_FOCUS,
           width: '30%'
       });
       
    So, I prevent keyboard from showing (by setting "softKeyboardOnFocus" to "Ti.UI.Android.SOFT_KEYBOARD_HIDE_ON_FOCUS" when text field is created). That makes scrolling normal experience, that is, user is not annoyed by constant keyboard pop-ups. Still, "focus" event is fired without user interaction.
       textField.addEventListener('click', function() {
           textField.softKeyboardOnFocus = Ti.UI.Android.SOFT_KEYBOARD_SHOW_ON_FOCUS;
           textField.focus();
       });
       
    Now, since user want to write to text field, a keyboard needs to be shown. I cannot use "focus" event because it is being fired randomly (even firing "focus" is not reliable when user scrolls) and I cannot prevent that by setting "focusable" property because it cannot be changed when text field is rendered. So I need to use "click" event. Inside "click" event listener I reset "softKeyboardOnFocus" property and call "focus" so that keyboard shows. This is not perfect because, as I said, "focus" is being fired randomly and sometimes user needs to click once more on text field. That's another Android crap, text field needs to be "focused" so it can be "click"ed ... that is, user need to click twice to get "click" event fired (first for "focus"). One more thing that needs to be done is to set "softKeyboardOnFocus" back to initial value ("SOFT_KEYBOARD_HIDE_ON_FOCUS") when text field looses focus.
       textField.addEventListener('blur', function() {
           textField.softKeyboardOnFocus = Ti.UI.Android.SOFT_KEYBOARD_HIDE_ON_FOCUS;
       });
       
    To make all this more user friendly, I added "click" event on window:
       win.addEventListener('click', function(e) {
           if (!/(TextField|TextArea)/.test(e.source.toString())) {
                Ti.UI.Android.hideSoftKeyboard();
           }
           
       });
       
    that hides keyboard when user clicks outside text field. Now, UX is better, but it is not perfect. Since "focus" event is being fired randomly, user will sometimes have to click one time, and sometimes two times to get keyboard shown. Hope this helps. :)
  10. Neeraj Gupta 2012-06-12

    @Ivan - We will reevaluate this issue based on your feedback.
  11. Ivan Skugor 2012-06-12

    Thanks Neeraj.
  12. Neeraj Gupta 2012-06-17

    We should reevaluate if we can workaround the native platform behavior without an ugly hack.
  13. Ivan Skugor 2012-06-20

    It seems that this workaround that I suggested has one issue, if keyboard type property is set, it is being reset to initial value. That can be fixed by resetting that value to initial value. Here is full example:
                var win = Ti.UI.createWindow({
        	    backgroundColor: '#000',
        	    modal: true,
        	    navBarHidden: true,
        	    layout: 'vertical'
        	});
        	 
        	function createItem() {
        	    var view = Ti.UI.createView({
        	        height: 100,
        	        width: '100%',
        	        layout: 'horizontal'
        	    });
        	     
        	    var label = Ti.UI.createLabel({
        	        text: 'Testing ...',
        	        width: '50%'
        	    });
        	     
        	    var checkbox = Ti.UI.createSwitch({
        	        style: Ti.UI.Android.SWITCH_STYLE_CHECKBOX
        	    });
        	     
        	    view.add(label);
        	    view.add(checkbox);
        	     
        	    return view;
        	}
        	 
        	function createTextField() {
        	     
        	    var view = Ti.UI.createView({
        	        height: 100,
        	        width: '100%',
        	        backgroundColor: '#0ff',
        	        layout: 'horizontal'
        	    });
        	     
        	    var label = Ti.UI.createLabel({
        	        text: 'Text field ...',
        	        width: '50%'
        	    });
        	     
        	    var textField = Ti.UI.createTextField({
        	    	keyboardType: Ti.UI.KEYBOARD_NUMBER_PAD,
        	    	softKeyboardOnFocus : Ti.UI.Android.SOFT_KEYBOARD_HIDE_ON_FOCUS,
        	        width: '30%'
        	    });
        	     
        	    textField.addEventListener('click', function() {
        	        textField.softKeyboardOnFocus = Ti.UI.Android.SOFT_KEYBOARD_SHOW_ON_FOCUS;
                        textField.keyboardType = Ti.UI.KEYBOARD_NUMBER_PAD;
            		textField.focus();
        	    });
        	    
        	    textField.addEventListener('blur', function() {
        		    textField.softKeyboardOnFocus = Ti.UI.Android.SOFT_KEYBOARD_HIDE_ON_FOCUS;
        		});
        	     
        	    view.add(label);
        	    view.add(textField);
        	     
        	    return view;
        	}
        	 
        	var scrollView = Ti.UI.createScrollView({
        	    layout: 'vertical',
        	    backgroundColor: '#f00',
        	    showVerticalScrollIndicator: true,
        	    height: '100%',
        	    width: '100%',
        	    contentHeight: 'auto',
        	    contentWidth: 'auto',
        	    top: 0
        	});
        	 
        	for (var m = 0; m < 3; ++m) {
        	    for (var i = 0; i < 20; ++i) {
        	        scrollView.add(createItem());
        	    }
        	    var view = createTextField();
        	    scrollView.add(view);
        	}
        	 
        	for (var j = 0; j < 20; ++j) {
        	    scrollView.add(createItem());
        	}
        	 
        	var button = Ti.UI.createButton({ title: 'Click me!' });
        	 
        	button.addEventListener('click', function() {
        	    var context = Ti.UI.createWindow({
        	        backgroundColor: '#000',
        	        modal: true,
        	        navBarHidden: true,
        	        layout: 'vertical'
        	    });
        	     
        	    var closeButton = Ti.UI.createButton({ title: 'Close me!' });
        	     
        	    closeButton.addEventListener('click', function() {
        	        context.close();
        	    });
        	     
        	    context.add(closeButton);
        	     
        	    context.open();
        	});
        	 
        	scrollView.add(button);
        	 
        	win.add(scrollView);
        	 
        	Ti.API.info('App runnning ...');
        	 
        	win.open();
        
  14. jithinpv 2013-04-26

    cannot reproduce Tested with Titanium Studio, build: 3.0.1.201212181159 Titanium SDK version: 3.1.0 Android Emulator: Android SDK version: 2.2
  15. Alberto Marcone 2014-01-14

    this is still happening: Titanium SDK version: 3.1.3 Android Emulator: any When you open a page, and there is a textfield, it will automatically be focused.
  16. Ivan Skugor 2014-01-14

    Hi Alberto. Try to set "windowSoftInputMode" to "Ti.UI.SOFT_INPUT_STATE_HIDDEN", check out Window docs [http://docs.appcelerator.com/titanium/latest/#!/api/Titanium.UI.Window]
  17. Pedro Brasileiro Cardoso Junior 2014-02-10

    Don't work with windowSoftInputMode setted to Ti.UI.SOFT_INPUT_STATE_HIDDEN
  18. Pankaj Goyal 2016-11-11

    Hi, We are also facing this issue on Appc SDK 5.5.1 . Its very frustrating. Please look into this. Thanks Pankaj Goyal

JSON Source