When alert/confirm box is popped up on screen and I press device's back button, then the poped up alert/confirm box is getting close(without firing any event). How can I avoid this?
Below is the calling code:
**var buttons = [
{
text : Messages.LBL_OK,
handler : doLogout
}
];
showSuccess(Messages.ALERT_FILING_CONFIRMATION,buttons);**
function showSuccess(text,buttons){
showDialog(Messages.LBL_CMN_DOALOG_SUCCESS_TITLE, text, buttons);
}
function showDialog(title,text,buttons){
if(title == null || title == undefined){
title = Messages.LBL_CMN_DOALOG_TITLE;
}
if(buttons == null || buttons == undefined){
buttons = [
{
text : Messages.LBL_OK,
handler : defaultOK
}
];
}
WL.SimpleDialog.show(title,text,buttons);
}
This is the expected behavior in Android.
However, if you'd like to avoid this default behavior, you could use the WL.App.overrideBackButton API in key locations in your code so that the button will 'do nothing'. When you're done, you can then use WL.App.resetBackButton to reset the back button's behavior back to its default state.
For example:
WL.App.overrideBackButton(callback);
function callback(){
// doing nothing...
}
You could use the above before calling WL.SimpleDialog.show() and dismiss it in the dialog's button callback.
Related
How can I validate if EditText has setError enabled ?
I want to disable a button if EditText has an error.
Any other way to achieve this.
It kinda works when I put view.calcbutton.setEnabled(false) inside the validateEditText-function, but I use the validateEditText-function to validate multiple EditTexts and only the last function-call disables the button.
if the first function-call disables the button, the second enables it again, and vice versa.
But I want do it outside this function because if one of the multiple EditTexts has setError the button should be disabled.
//global var blockcalcbutton
var blockcalcbutton = 0
//function to validate EditTexts and set blockcalcbutton=1 if setError
validateEditText(view.input_volt, view, getString(R.string.invalid_volt))
if(blockcalcbutton == 1) {
view.calcbutton.setEnabled(false)
view.calcbutton.setText(getString(R.string.calcbutton_disabled))
view.calcbutton.setBackgroundResource(R.color.buttonDisabled)
} else {
view.calcbutton.setEnabled(true)
view.calcbutton.setText(getString(R.string.calcbutton_enabled))
view.calcbutton.setBackgroundResource(R.color.buttonBackground)
}
fun validateEditText(editText: EditText, message: String) {
val myEditText = editText
myEditText.addTextChangedListener(object: TextWatcher {
override fun afterTextChanged(s: Editable?) {
if(myEditText.text.toString() == "" || myEditText.text.toString() == "." || myEditText.text.toString() == "0") {
//setError
myEditText.setError(message)
//var to disable Button
blockcalcbutton = 1
} else {
//delete setError
myEditText.setError(null)
//var to enable Button
blockcalcbutton = 0
}
}
You can create a callback to notify when you set an error or delete it.
interface EditTextErrorListener {
fun onErrorSet()
fun onErrorDeleted()
}
Here you can notify:
if(myEditText.text.toString() == "" || myEditText.text.toString() == "." || myEditText.text.toString() == "0") {
//setError
myEditText.setError(message)
---> listener.onErrorSet()
//var to disable Button
blockcalcbutton = 1
} else {
//delete setError
myEditText.setError(null)
---> listener.onErrorDeleted()
//var to enable Button
blockcalcbutton = 0
}
Try approaching the problem from further away; when you look at this issue, you have multiple inputs (all the fields in your form) and one boolean output:
All fields are OK -> Enable the button
One or more fields are NOT Ok -> disable the button.
Additionally, you have local validation on each field (to display the error, etc.).
I'd argue that the local validation on each field, is to be done at the callback from the edit text (onAfterText, etc.etc.). You are already doing this.
A way to ensure the final validation (of the form as a whole) is fast, you could use a reference counter. E.g.:
Each edit text, validates with afterTextChanged. Each one performs whatever validation you think is right (can be a shared one if they are all the same).
If validation fails, you keep a reference to the failed field.
This will not have side-effects because nothing happens whether the item is or is not on the list.
This is some pseudo-code:
// keep a list of fields (this is just a way to do it, there are many others)
var errorFields = MutableHashSet<EditText>
later in your "validation" (afterTextChanges for example):
if (xxx && yyy && zzz) { //your validations for the individual editText
//setError
myEditText.setError(message)
// Store the reference of the editField in error.
errorFields.add(theEditTextThatHasAFailure).
} else {
myEditText.setError(null)
// If the validation is ok, you remove it:
errorFields.remove(theEditTextThatHasFailure)
}
// The form may have changed, update the global button state.
updateButtonState();
All this method needs to do, is something like:
button.enabled = errorFields.isEmpty()
This will only be empty if there are no error fields.
This is just an idea you may need to combine with callbacks for further control, but remember this one thing:
EditTexts (or any other widget) is and should not be responsible for the business logic that drives the whole "Form"; they are merely individual pieces of a larger puzzle, and as such, it's incorrect to give them the responsibility to drive your Form's validations; they can (and should) however, validate themselves and handle their own error state (like you're doing), but that's as far as it should go.
They can inform of a state change (e.g. via the listener onAfterText, or after gaining/losing focus, etc.) but shouldn't make business logic decisions. EditTexts are designed to take user input and display it on screen, that's all.
Last but not least, don't forget to remove the references when you destroy your views
onDestroy() {
errorFields.clear()
}
I am writing a Xamarin Forms app (.net standard 2.0). Currently it is only being developed for Android but it may be released for other OSs in future. The scenario I am trying to manage is this:
The user goes into a ContentPage with a single Entry
I give the Entry focus by using native Android code in a custom renderer:
if (e.NewElement != null && e.NewElement is CustomEntry)
{
CustomEntry customEntry = (CustomEntry)e.NewElement;
if(customEntry.GiveFocus)
{
//this messes up the onback behaviour - you have to press onback twice to exit the screen, once to get out of the hidden SIP
Control.RequestFocus();
}
}
I do not want the soft keyboard to pop up automatically. Therefore I have added the below line to the OnCreate of the MainActivity:
Window.SetSoftInputMode(SoftInput.StateAlwaysHidden);
The reason I am requesting focus in the custom renderer and not in the Xamarin Forms Entry is I could see the keyboard popup and then immediately disappear when I requested it in the Xamarin Forms control. I don't want the keyboard to appear as this app will be primarily used by users of industrial devices with a hardware keyboard, but the entry will need to have focus as the users will want to enter text into it straight away.
My problem is the user has to press the back button twice to exit the ContentPage in this scenario. Once to get out of the hidden keyboard (and the Entry loses focus) and then again to exit the page. I want to avoid this - they should be able to exit the page with only one click when the keyboard is hidden. Does anyone know how to resolve this? I have tried overriding OnKeyPreIme in the custom renderer as other answers have suggested but it doesn't appear to detect the back click.
You can use Hide Keyboard method when your entry get focused. It might solved your problem.
public interface IKeyboardHelper
{
void HideKeyboard();
}
For Android use :
public class DroidKeyboardHelper : IKeyboardHelper
{
public void HideKeyboard()
{
var context = Forms.Context;
var inputMethodManager = context.GetSystemService(Context.InputMethodService) as InputMethodManager;
if (inputMethodManager != null && context is Activity)
{
var activity = context as Activity;
var token = activity.CurrentFocus?.WindowToken;
inputMethodManager.HideSoftInputFromWindow(token, HideSoftInputFlags.None);
activity.Window.DecorView.ClearFocus();
}
}
}
For iOS :
public class iOSKeyboardHelper : IKeyboardHelper
{
public void HideKeyboard()
{
UIApplication.SharedApplication.KeyWindow.EndEditing(true);
}
}
Use Dependency Injection and call this method while your entry get focused.
Try to use below method for handling back button pressed event.
protected override bool OnBackButtonPressed()
{
// you can handle back button pressed event in Xamarin forms page
return base.OnBackButtonPressed();
}
I've (finally) worked it out. The key is not to override OnKeyPreIME but DispatchKeyEventPreIme instead. This allows you to intercept the 'Back' press. So, in my CustomRenderer I added this method:
public override bool DispatchKeyEventPreIme(KeyEvent e)
{
//if this is back press and the sip is not visible then we need to call the 'OnBack' method at the view model level
if(!SIPVisibleListener.IsSIPVisible && e.KeyCode == Keycode.Back)
{
if(XamarinFormsControl != null && XamarinFormsControl is IOnBackHandler)
{
((IOnBackHandler)XamarinFormsControl).GoBack();
}
}
return base.DispatchKeyEventPreIme(e);
}
IOnBackHandler is an interface I created to handle the back key press. SIPVisibleListener is based on an answer to this question: How do I Detect if Software Keyboard is Visible on Android Device?
Hopefully this will help someone.
How can I keep the keyboard open after the user tap on the "Return" key on the soft keyboard?
I'm calling the focus method on "returnPress" event, which works fine on IOS but not on android:
text() {
let textFieldElement = <TextField>this.textField.nativeElement;
textFieldElement.focus();
}
So turns out I need to overrde "onEditorAction" method on the "OnEditorActionListener" like this:
let tv = <TextField>this.textField.nativeElement;
if (tv.android) {
tv.android.setOnEditorActionListener(new android.widget.TextView.OnEditorActionListener({
onEditorAction: function (callbackType, result) {
if (result == android.view.inputmethod.EditorInfo.IME_ACTION_DONE) {
// do whatever you want when user presses return
}
return true;
}
}));
}
I have been searching around to find a generic way to use the back key on android devices to go back to the previous scene you were on. All I seem to find is how to make it so the button does not close the application.
Here is my current code:
NativeApplication.nativeApplication.addEventListener(KeyboardEvent.KEY_DOWN, onKeyDown, false, 0, true)
function onKeyDown(event:KeyboardEvent):void
{
if( event.keyCode == Keyboard.BACK )
{
event.preventDefault();
event.stopImmediatePropagation();
//handle the button press here.
}
}
Just tested it on my Android device, just change trace() with your function:
stage.addEventListener(KeyboardEvent.KEY_DOWN, onKeyPressed);
private function onKeyPressed(event:KeyboardEvent):void
{
if(event.keyCode == Keyboard.BACK)
{
event.preventDefault();
//Now you can call your function.
trace("Hello World");
}
}
I'm building a mobile AIR app (Android & IOS) with Adobe Flash Builder 4.6 and I'm having this annoying problem.
Because I want to 'catch' the back-key on Android devices I added the following code to my main class:
stage.addEventListener(KeyboardEvent.KEY_DOWN, keyDown);
private function keyDown(k:KeyboardEvent):void {
if(k.keyCode == Keyboard.BACK) {
backClicked(); // function handling the back-action, not important
k.preventDefault();
}
Now somewhere else - nested in some classes - I've got a textfield:
TF = new TextField();
TF.type = TextFieldType.INPUT;
But when I set focus on the textfield the soft keyboard does appear, but I can't type a single character. When I disable the keylistener: no problem.
Seems like the listener is overriding my input field. Is there any workaround on this?
I have also implemented the back button functionality for my mobile apps , but i used to register keydown event only when my particular view is activated and removed the registered when view get deactivated.
in <s:view ....... viewActivate ="enableHardwareKeyListeners(event)" viewDeactivate="destroyHardwareKeyListeners(event)">
// add listener only for android device
if (Check for android device) {
NativeApplication.nativeApplication.addEventListener(KeyboardEvent.KEY_DOWN, handleHardwareKeysDown, false, 0);
NativeApplication.nativeApplication.addEventListener(KeyboardEvent.KEY_UP, handleHardwareKeysUp, false, 0);
this.setFocus();
}
private function destroyHardwareKeyListeners(event:ViewNavigatorEvent):void
{
if (NativeApplication.nativeApplication.hasEventListener(KeyboardEvent.KEY_DOWN))
NativeApplication.nativeApplication.removeEventListener(KeyboardEvent.KEY_DOWN, handleHardwareKeysDown);
if (NativeApplication.nativeApplication.hasEventListener(KeyboardEvent.KEY_UP))
NativeApplication.nativeApplication.removeEventListener(KeyboardEvent.KEY_UP, handleHardwareKeysUp);
}
private function handleHardwareKeysDown(e:KeyboardEvent):void
{
if (e.keyCode == Keyboard.BACK) {
e.preventDefault();
// your code
} else {
}
}
private function handleHardwareKeysUp(e:KeyboardEvent):void
{
if (e.keyCode == Keyboard.BACK)
e.preventDefault();
}
May this can help you.