Open neuronix opened 4 years ago
On a side note, this bug has plagued AIR for years now, we used to have some hacks like delaying the focus or moving the textfield every key stroke (yeah... developer desperation...) but they no longer work and we actually had to remove them for the soft keyboard to actually show since last SDK (.217).
So we no longer have a workaround other than a proper fix in AIR.
We are using a custom solution for this and I am not aware of any Android 10 related problems. Feel free to give it a try. First we have the base class that works on pure AS3, and based on that we have a inherited class that uses the Distriqt Application ANE that delivers more accurate results for the softkeyboard size. You need to instantiate one of them (preferably the SoftKeyboardPannerAne class) and keep a reference of it during the lifetime of your application.
Base class
public class SoftKeyboardPanner
{
protected var _stage:Stage;
private var _mainView:Sprite;
private var _panning:Number = 0;
private var _currentTextfield:TextField;
public function SoftKeyboardPanner(mainView:Sprite)
{
_mainView = mainView;
_stage = _mainView.stage;
addSystemHandlers();
}
public function dispose():void
{
releaseCurrentTextfield();
_stage.removeEventListener(Event.ENTER_FRAME, enterFrameHandler);
removeSystemHandlers();
_stage = null;
_mainView = null;
}
// **************************************
// GETTERS AND SETTERS
// **************************************
protected function get keyboardHeight():Number
{
return _stage.softKeyboardRect.height;
}
// **************************************
// PUBLIC FUNCTIONS
// **************************************
// **************************************
// PROTECTED FUNCTIONS
// **************************************
protected function addSystemHandlers():void
{
_stage.addEventListener(SoftKeyboardEvent.SOFT_KEYBOARD_ACTIVATE, keyboardActivateHandler);
_stage.addEventListener(SoftKeyboardEvent.SOFT_KEYBOARD_DEACTIVATE, keyboardDeactivateHandler);
_stage.addEventListener(FocusEvent.FOCUS_IN, focusChangedHandler);
}
protected function removeSystemHandlers():void
{
_stage.removeEventListener(SoftKeyboardEvent.SOFT_KEYBOARD_ACTIVATE, keyboardActivateHandler);
_stage.removeEventListener(SoftKeyboardEvent.SOFT_KEYBOARD_DEACTIVATE, keyboardDeactivateHandler);
_stage.removeEventListener(FocusEvent.FOCUS_IN, focusChangedHandler);
}
protected function setPanning(value:Number):void
{
_panning = value;
//you could also use a Tween here:
_mainView.y = -_panning;
}
// **************************************
// PRIVATE FUNCTIONS
// **************************************
private function releaseCurrentTextfield():void
{
if (_currentTextfield)
{
_currentTextfield.removeEventListener(SoftKeyboardEvent.SOFT_KEYBOARD_DEACTIVATE, keyboardDeactivateHandler);
_currentTextfield.removeEventListener(Event.REMOVED_FROM_STAGE, keyboardDeactivateHandler);
_currentTextfield = null;
}
}
private function checkPanning():void
{
var textfield:Rectangle = _currentTextfield.getRect(_stage);
var kh:Number = keyboardHeight;
//Keyboard ANE will report correct keyboard height with a delay if renderMode is direct
if (kh == 0)
{
_stage.addEventListener(Event.ENTER_FRAME, enterFrameHandler);
return;
}
//make sure we receive keyboard resize updates, e.g. when word suggestions pop in
_stage.addEventListener(Event.ENTER_FRAME, enterFrameHandler);
var keyboardStart:Number = _stage.stageHeight - kh;
var textfieldEnd:Number = textfield.y + textfield.height + _panning;
if (keyboardStart < textfieldEnd)
{
setPanning(textfieldEnd - keyboardStart);
_currentTextfield.addEventListener(SoftKeyboardEvent.SOFT_KEYBOARD_DEACTIVATE, keyboardDeactivateHandler);
_currentTextfield.addEventListener(Event.REMOVED_FROM_STAGE, keyboardDeactivateHandler);
}
}
// **************************************
// EVENT LISTENERS
// **************************************
protected function keyboardActivateHandler(e:SoftKeyboardEvent):void
{
_currentTextfield = e.target as TextField;
if (!_currentTextfield) return;
checkPanning();
}
protected function keyboardDeactivateHandler(e:Event = null):void
{
_stage.removeEventListener(Event.ENTER_FRAME, enterFrameHandler);
if (_panning == 0) return;
releaseCurrentTextfield();
setPanning(0);
}
private function enterFrameHandler(e:Event):void
{
checkPanning();
}
protected function focusChangedHandler(e:FocusEvent):void
{
//if user clicks another Textfield, Softkeyboard stays open but panning has to be recalculated
if (_panning != 0)
{
keyboardDeactivateHandler();
if (_stage.focus is TextField && TextField(_stage.focus).type == TextFieldType.INPUT)
{
_currentTextfield = _stage.focus as TextField;
checkPanning();
}
}
}
}
ANE Subclass:
public class SoftKeyboardPannerAne extends SoftKeyboardPanner
{
private var _keyboardOpen:Boolean = false;
public function SoftKeyboardPannerAne(mainView:Sprite)
{
super(mainView);
try
{
Application.service.display.setDisplayMode(DisplayMode.IMMERSIVE);
} catch (e:Error)
{
trace(this, e.message);
}
}
// **************************************
// GETTERS AND SETTERS
// **************************************
override protected function get keyboardHeight():Number
{
try
{
var n:Number = Application.service.keyboard.height;
//n = n * 1.15;
return n;
} catch (e:Error)
{
return super.keyboardHeight;
}
return super.keyboardHeight;
}
// **************************************
// PUBLIC FUNCTIONS
// **************************************
// **************************************
// PROTECTED FUNCTIONS
// **************************************
protected override function addSystemHandlers():void
{
_stage.addEventListener(SoftKeyboardEvent.SOFT_KEYBOARD_ACTIVATE, openKeyboardHandler);
_stage.addEventListener(SoftKeyboardEvent.SOFT_KEYBOARD_DEACTIVATE, removeKeyboardHandler);
_stage.addEventListener(FocusEvent.FOCUS_IN, focusChangedHandler);
}
protected override function removeSystemHandlers():void
{
_stage.removeEventListener(SoftKeyboardEvent.SOFT_KEYBOARD_ACTIVATE, openKeyboardHandler);
_stage.removeEventListener(SoftKeyboardEvent.SOFT_KEYBOARD_DEACTIVATE, removeKeyboardHandler);
_stage.removeEventListener(FocusEvent.FOCUS_IN, focusChangedHandler);
}
// **************************************
// PRIVATE FUNCTIONS
// **************************************
// **************************************
// EVENT LISTENERS
// **************************************
private function keyboardActivatingHandler(e:SoftKeyboardEvent):void
{
}
protected function openKeyboardHandler(e:SoftKeyboardEvent):void
{
if (!_keyboardOpen)
{
_keyboardOpen = true;
//Show soft navigation in soft keyboard
var visibility:int = Application.service.display.getSystemUiVisibility();
Application.service.display.setSystemUiVisibility(
visibility & ~AndroidSystemUiFlags.SYSTEM_UI_FLAG_HIDE_NAVIGATION
);
}
super.keyboardActivateHandler(e);
}
protected function removeKeyboardHandler(e:Event = null):void
{
if (_keyboardOpen)
{
_keyboardOpen = false;
//go back to previous displaymode
Application.service.display.setDisplayMode( DisplayMode.IMMERSIVE );
}
super.keyboardDeactivateHandler(e);
}
}
I am not saying this should not be fixed in Air, but maybe this workaround is helpful. Let me know
Thanks @rewb0rn for the tip, will give it a try!
When the soft keyboard is shown after focusing on a flash.display.Textfield input, the stage does not align properly on many devices, mostly Android 10.
Here are two devices, same build using and SDK AIR 33.1.1.217 and android:hardwareaccelerated="true" in xml:
Huawei device, Android 10 working fine
Samsung Galaxy S10, Android 10, not working