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();
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.
I would really appreciate if this issue could be scheduled because there is no workaround. Thanks.
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.
Marking it invalid since the Titanium behavior matches with the native behavior.
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:
It seems that "focusable" property cannot be changed after TextField is rendered. Is there any other way? :( Thanks.
Ivan, would setting the windowSoftInputMode property of the window have any effect on this?
Thanks Shawn, but unfortunately that has no effect.
I found a workaround (Shawn suggestion pushed me in right direction :) ). The solution is this:
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.
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.
To make all this more user friendly, I added "click" event on window:
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. :)
@Ivan - We will reevaluate this issue based on your feedback.
Thanks Neeraj.
We should reevaluate if we can workaround the native platform behavior without an ugly hack.
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:
cannot reproduce Tested with Titanium Studio, build: 3.0.1.201212181159 Titanium SDK version: 3.1.0 Android Emulator: Android SDK version: 2.2
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.
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]
Don't work with windowSoftInputMode setted to Ti.UI.SOFT_INPUT_STATE_HIDDEN
Hi, We are also facing this issue on Appc SDK 5.5.1 . Its very frustrating. Please look into this. Thanks Pankaj Goyal