For some EditText views I want to use a custom keyboard instead of the soft one.
The problem is when I click on an EditText for the first time both keyboards are shown. When I click for the second time - the soft keyboard finally disappeares.
What might be the reason for such behavior?
Here's the code I use:
package pkleczek.profiwan.keyboards;
import android.app.Activity;
import android.inputmethodservice.KeyboardView;
import android.text.InputType;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.View.OnFocusChangeListener;
import android.view.inputmethod.InputMethodManager;
import android.widget.EditText;
public abstract class CustomKeyboard {
/** A link to the KeyboardView that is used to render this CustomKeyboard. */
protected KeyboardView mKeyboardView;
/** A link to the activity that hosts the {#link #mKeyboardView}. */
protected Activity mHostActivity;
/** Returns whether the CustomKeyboard is visible. */
public boolean isCustomKeyboardVisible() {
return mKeyboardView.getVisibility() == View.VISIBLE;
}
/**
* Make the CustomKeyboard visible, and hide the system keyboard for view v.
*/
public void showCustomKeyboard(View v) {
mKeyboardView.setVisibility(View.VISIBLE);
mKeyboardView.setEnabled(true);
if (v != null) {
InputMethodManager inputManager = (InputMethodManager) mHostActivity
.getSystemService(Activity.INPUT_METHOD_SERVICE);
inputManager.hideSoftInputFromWindow(v.getWindowToken(), 0);
}
}
/** Make the CustomKeyboard invisible. */
public void hideCustomKeyboard() {
mKeyboardView.setVisibility(View.GONE);
mKeyboardView.setEnabled(false);
}
/**
* Register <var>EditText<var> with resource id <var>resid</var> (on the
* hosting activity) for using this custom keyboard.
*
* #param resid
* The resource id of the EditText that registers to the custom
* keyboard.
*/
public void registerEditText(int resid) {
EditText edittext = (EditText) mHostActivity.findViewById(resid);
edittext.setOnFocusChangeListener(new OnFocusChangeListener() {
#Override
public void onFocusChange(View v, boolean hasFocus) {
if (hasFocus) {
showCustomKeyboard(v);
} else {
hideCustomKeyboard();
}
}
});
edittext.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
showCustomKeyboard(v);
}
});
edittext.setInputType(edittext.getInputType()
| InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS);
}
}
Try to put the following condition in your InputMethodManager code before inputManager.hideSoftInputFromWindow(v.getWindowToken(), 0);line:
if (inputManager!=null) {
Activity activity = getActivity();
if (acvivity == null)
return;
if (activity.getCurrentFocus() == null)
return;
if (activity.getCurrentFocus().getWindowToken() == null)
return;
inputManager.hideSoftInputFromWindow(activity.getCurrentFocus().getWindowToken(), 0);
}
I used it in ListFragment to hide the default keyboard. First when i press an EditText and keyboard is shown and when on onScrollStateChanged i hide it.
You can also try to put the InputMethodManager code inside the onClickListener of the EditText and then call your showCustomKeyboard() method.
Put an Else statement and Log in it after the if (v != null), maybe your View v is null.
The solution provided by Rotemmiz in the topic Close/hide the Android Soft Keyboard worked for me.
An abstract:
public void setEditTextFocus(EditText editText, boolean isFocused)
{
editText.setCursorVisible(isFocused);
editText.setFocusable(isFocused);
editText.setFocusableInTouchMode(isFocused);
if (isFocused)
{
editText.requestFocus();
}
}
Related
In my app, I'm making use of AlertDialog instances with custom views that contain text fields, to let the user enter values in a modal dialog.
Problem is, there seems to be no clean, simple, reliable way to make sure the keyboard pops up as the AlertDialog is shown AND disappears again as the dialog is dismissed.
So far I'm using the following to display the keyboard:
// 'dialog' is the AlertDialog instance
Window window = dialog.getWindow();
if (window != null) {
window.setSoftInputMode(SOFT_INPUT_STATE_VISIBLE);
}
dialog.show();
This feels a bit dirty already but works consistently so I can't complain. However, hiding the keyboard again is tricky. For starters, I have the following utility method:
public static void hideKeyboard(Activity activity) {
InputMethodManager imm = getIMM(activity);
IBinder windowToken = activity.getWindow().getDecorView().getWindowToken();
imm.hideSoftInputFromWindow(windowToken, HIDE_IMPLICIT_ONLY);
}
Simply calling that (with the topmost activity as the activity argument) in a button callback of my AlertDialog doesn't work. For the utility method to do what it's intended to, I have to call it after a short delay.
Util.runAfterTimeout(5, () -> Util.hideKeyboard(activity));
(The runAfterTimeout method calls a given Runnable on the main thread looper with the given timeout in milliseconds.)
At this point the code really starts to stink. It gets worse though.
With one of my AlertDialog variants, a timeout of 5 milliseconds works. This is short enough to seem immediate to a human.
Another one of my AlertDialogs needs a higher timeout. It seems to start working around 100ms, at which point the delay starts to become noticable.
(The reason is probably that one of the dialogs uses its own ok/cancel buttons in its custom layout, whereas the other uses setPositiveButton and setNegativeButton. The reasons are layout-related.)
I don't know if these values will work on all devices / in all situations. What if a different CPU or even different load on the same CPU causes the scheduler to act differently, and my hack starts to fail again? Should I up the delay to 200ms to be safe? Maybe to 500ms for very slow devices? (It's very noticable at that point.) Who knows!
I can't imagine this scenario being so rare as to warrant such hacks. I just want to show a popup dialog and let the user enter some value(s) into it.
Anyone know a clean solution? Ditch AlertDialog entirely and use something else maybe? Or will using a DialogFragment maybe solve my pains?
Thanks in advance.
You can check this example. It works fine in fragment and activity.
* #param context of the application
*/
public static void showKeyBoard(Context context) {
try {
InputMethodManager imm = (InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE);
if (imm != null) {
imm.toggleSoftInput(InputMethodManager.SHOW_FORCED, InputMethodManager.HIDE_IMPLICIT_ONLY);
}
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* #param context context of the application
* #param contextualView contextual view of the fragment/activity
*/
public static void hideKeyBoard(Context context, View contextualView) {
try {
InputMethodManager imm = (InputMethodManager) context.getSystemService(
Context.INPUT_METHOD_SERVICE);
if (imm != null) {
imm.hideSoftInputFromWindow(contextualView.getWindowToken(), 0);
}
} catch (Exception e) {
e.printStackTrace();
}
}
public void showSingleInput(String title, String previousText, SingleEditTextInput.TextInputListener listener) {
SingleEditTextInput singleEditTextInput = new SingleEditTextInput();
Bundle args = new Bundle();
args.putString("DIALOG_TITLE", title);
args.putString("PREVIOUS_TEXT", previousText);
singleEditTextInput.setArguments(args);
singleEditTextInput.setListener(listener);
singleEditTextInput.show(fragmentManager, POP_UP_DIALOG);
}
public class SingleEditTextInput extends DialogFragment {
private String title = null, previousString = null;
TextInputListener listener;
Context mContext;
private Button btnSubmit;
private Button btnCancel;
EditText editText;
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
}
#NonNull
#Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
mContext = getActivity();
AlertDialog.Builder builder = new AlertDialog.Builder(mContext);
AlertDialog alertDialog = builder.create();
alertDialog.setView(initView());
alertDialog.setCanceledOnTouchOutside(false);
btnSubmit.setOnClickListener(view -> {
String input;
input = editText.getText().toString().trim();
if (input!=null) {
hideKeyBoard(mContext, editText.findFocus());
dismiss();
listener.onClickSubmit(input);
} else
ToastMsg.getInstance(getActivity()).Show(getResources().getString(R.string.description_error));
});
btnCancel.setOnClickListener(view -> {
hideKeyBoard(mContext, editText);
dismiss();
});
editText.addTextChangedListener(textWatcher);
return alertDialog;
}
#Override
public void onPause() {
super.onPause();
hideKeyBoard(mContext, editText.findFocus());
}
private TextWatcher textWatcher = new TextWatcher() {
#Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
#Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
if (s.toString().trim().length() > 0) {
btnSubmit.setEnabled(true);
} else {
btnSubmit.setEnabled(false);
}
}
#Override
public void afterTextChanged(Editable s) {
}
};
private View initView() {
View mView;
mView = LayoutInflater.from(mContext).inflate(R.layout.l_single_edittext, null);
TextView tvTitle = mView.findViewById(R.id.tv_dialog_title);
editText = mView.findViewById(R.id.et_input);
btnSubmit = mView.findViewById(R.id.btn_next);
btnSubmit.setText(R.string.ok);
btnCancel = mView.findViewById(R.id.btn_back);
btnCancel.setText(R.string.cancel_text);
if (getArguments() != null) {
title = getArguments().getString("DIALOG_TITLE", "");
previousString = getArguments().getString("PREVIOUS_TEXT", "");
}
if (title!=null) {
tvTitle.setText(title);
}
if (previousString!=null) {
editText.setText(previousString);
}
showKeyBoard(mContext);
return mView;
}
public void setListener(TextInputListener dialogListener) {
this.listener = dialogListener;
}
public interface TextInputListener {
void onClickSubmit(String input);
}
}
If I may to ask almost the same question here from this topic
I've added in my activity_main.xml file:
android:focusable="true"
android:focusableInTouchMode="true"
activity_main.xml:
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:focusable="true"
android:focusableInTouchMode="true"
tools:context="com.example.stefancvetkovic.stefantest001.MainActivity">
<EditText
android:id="#+id/txtScanedResult"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ems="10"
android:inputType="textPersonName"
tools:layout_editor_absoluteX="16dp"
tools:layout_editor_absoluteY="16dp" />
</android.support.constraint.ConstraintLayout>
And it works fine, but when I want to hide my keyboard on finish event, the keyboard stays opened.
MainActivity.java:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
((EditText)findViewById(R.id.txtScanedResult)).setOnEditorActionListener(
new EditText.OnEditorActionListener() {
#Override
public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
if (actionId == EditorInfo.IME_ACTION_SEARCH ||
actionId == EditorInfo.IME_ACTION_DONE ||
event != null &&
event.getAction() == KeyEvent.ACTION_DOWN &&
event.getKeyCode() == KeyEvent.KEYCODE_ENTER) {
if (event == null || !event.isShiftPressed()) {
// the user is done typing.
//HIDE KEYBOARD
EditText edtView=(EditText)findViewById(R.id.txtScanedResult);
edtView.setInputType((InputType.TYPE_NULL));
//
Toast.makeText(getApplicationContext(),"Voila!",Toast.LENGTH_SHORT)
.show();
return true; // consume.
}
}
return false; // pass on to other listeners.
}
});
}
Toast works perfectly on finish event, but keyboard stays opened.
Hoiw can I manage to be initialy closed keyboard on the load, and to be hidden on finishEvent?
I am running in emulator on Android 5.1
Try this one
/**
* This function is used to hide soft keyboard
*
* #param context mContext
* #param view view for which keyboard is open
*/
public static void hideSoftInput(Context context, View view) {
if (view != null) {
InputMethodManager inputMethodManager = (InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE);
if (!inputMethodManager.isActive()) {
return;
}
inputMethodManager.hideSoftInputFromWindow(view.getWindowToken(), 0);
}
}
/**
* This function is used to hide soft keyboard
*
* #param activity activity
*/
public static void hideSoftInput(Activity activity) {
try {
if (activity != null) {
View focusedView = activity.getCurrentFocus();
hideSoftInput(activity, focusedView);
}
} catch (Throwable t) {
CustomLogHandler.printErrorlog(t);
}
}
/**
* This function is used to show soft keyboard
*
* #param activity activity
*/
public static void showSoftInput(Activity activity) {
try {
if (activity != null) {
View focusedView = activity.getCurrentFocus();
if (focusedView != null) {
InputMethodManager inputMethodManager = (InputMethodManager) activity.getSystemService(Context.INPUT_METHOD_SERVICE);
inputMethodManager.showSoftInput(focusedView, InputMethodManager.SHOW_IMPLICIT);
}
}
} catch (Throwable t) {
CustomLogHandler.printErrorlog(t);
}
}
/**
* This function is used to show soft keyboard
*
* #param view view for which soft keyboard need to be opened
*/
public static void showSoftInput(final View view) {
try {
if (view == null) {
return;
}
view.requestFocus();
InputMethodManager inputManager = (InputMethodManager) view.getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
inputManager.showSoftInput(view, 0);
} catch (Exception e) {
CustomLogHandler.printErrorlog(e);
}
}
or try
getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN);
Call it before showing toast.
public void hideKeyboard(Activity context) {
// Check if no view has focus:
View view = context.getCurrentFocus();
if (view != null) {
InputMethodManager inputManager = (InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE);
inputManager.hideSoftInputFromWindow(view.getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS);
}
}
Try this code:
/**
* Hides the soft keyboard
*/
public void hideSoftKeyboard() {
if(getCurrentFocus()!=null) {
InputMethodManager inputMethodManager = (InputMethodManager) getSystemService(INPUT_METHOD_SERVICE);
inputMethodManager.hideSoftInputFromWindow(getCurrentFocus().getWindowToken(), 0);
}
}
/**
* Shows the soft keyboard
*/
public void showSoftKeyboard(View view) {
InputMethodManager inputMethodManager = (InputMethodManager) getSystemService(INPUT_METHOD_SERVICE);
view.requestFocus();
inputMethodManager.showSoftInput(view, 0);
}
or do this:
In the AndroidManifest.xml:
<activity android:name="com.your.package.ActivityName"
android:windowSoftInputMode="stateHidden" />
or try:
getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN);
I've been following the Custom Keyboard example to make the following:
import android.app.Activity;
import android.inputmethodservice.Keyboard;
import android.inputmethodservice.KeyboardView;
import android.inputmethodservice.KeyboardView.OnKeyboardActionListener;
import android.text.Editable;
import android.text.InputType;
import android.text.method.CharacterPickerDialog;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.View.OnFocusChangeListener;
import android.view.View.OnTouchListener;
import android.view.WindowManager;
import android.view.inputmethod.InputMethodManager;
import android.widget.EditText;
/**
* When an activity hosts a keyboardView, this class allows several EditText's to register for it.
*
* #author Maarten Pennings
* #date 2012 December 23
*/
public class CustomKeyboard {
private static final String TAG = "[CustomKeyboard]: ";
/** A link to the KeyboardView that is used to render this CustomKeyboard. */
private KeyboardView mKeyboardView;
/** A link to the activity that hosts the {#link #mKeyboardView}. */
private Activity mHostActivity;
/** The key (code) handler. */
private OnKeyboardActionListener mOnKeyboardActionListener = new OnKeyboardActionListener() {
public final static int CodeDelete = -5; // Keyboard.KEYCODE_DELETE
public final static int CodeCancel = -3; // Keyboard.KEYCODE_CANCEL
public final static int CodePrev = 55000;
public final static int CodeAllLeft = 55001;
public final static int CodeLeft = 55002;
public final static int CodeRight = 55003;
public final static int CodeAllRight = 55004;
public final static int CodeNext = 55005;
public final static int CodeClear = 55006;
#Override public void onKey(int primaryCode, int[] keyCodes) {
// NOTE We can say '<Key android:codes="49,50" ... >' in the xml file; all codes come in keyCodes, the first in this list in primaryCode
// Get the EditText and its Editable
View focusCurrent = mHostActivity.getWindow().getCurrentFocus();
if( focusCurrent==null || focusCurrent.getClass()!=EditText.class ) return;
EditText edittext = (EditText) focusCurrent;
Editable editable = edittext.getText();
int start = edittext.getSelectionStart();
Log.d(TAG,"Pressed");
// Apply the key to the edittext
if( primaryCode==CodeCancel ) {
hideCustomKeyboard();
} else if( primaryCode==CodeDelete ) {
if( editable!=null && start>0 ) editable.delete(start - 1, start);
} else if( primaryCode==CodeClear ) {
if( editable!=null ) editable.clear();
} else if( primaryCode==CodeLeft ) {
if( start>0 ) edittext.setSelection(start - 1);
} else if( primaryCode==CodeRight ) {
if (start < edittext.length()) edittext.setSelection(start + 1);
} else if( primaryCode==CodeAllLeft ) {
edittext.setSelection(0);
} else if( primaryCode==CodeAllRight ) {
edittext.setSelection(edittext.length());
} else if( primaryCode==CodePrev ) {
View focusNew= edittext.focusSearch(View.FOCUS_LEFT);
if( focusNew!=null ) focusNew.requestFocus();
} else if( primaryCode==CodeNext ) {
View focusNew= edittext.focusSearch(View.FOCUS_RIGHT);
if( focusNew!=null ) focusNew.requestFocus();
} else { // insert character
editable.insert(start, Character.toString((char) primaryCode));
Log.d(TAG,"INPUT is this: "+Character.toString((char)primaryCode));
}
}
#Override public void onPress(int primaryCode) {
// NOTE We can say '<Key android:codes="49,50" ... >' in the xml file; all codes come in keyCodes, the first in this list in primaryCode
// Get the EditText and its Editable
View focusCurrent = mHostActivity.getWindow().getCurrentFocus();
if( focusCurrent==null || focusCurrent.getClass()!=EditText.class ) return;
EditText edittext = (EditText) focusCurrent;
Editable editable = edittext.getText();
int start = edittext.getSelectionStart();
Log.d(TAG,"Pressed");
// Apply the key to the edittext
if( primaryCode==CodeCancel ) {
hideCustomKeyboard();
} else if( primaryCode==CodeDelete ) {
if( editable!=null && start>0 ) editable.delete(start - 1, start);
} else if( primaryCode==CodeClear ) {
if( editable!=null ) editable.clear();
} else if( primaryCode==CodeLeft ) {
if( start>0 ) edittext.setSelection(start - 1);
} else if( primaryCode==CodeRight ) {
if (start < edittext.length()) edittext.setSelection(start + 1);
} else if( primaryCode==CodeAllLeft ) {
edittext.setSelection(0);
} else if( primaryCode==CodeAllRight ) {
edittext.setSelection(edittext.length());
} else if( primaryCode==CodePrev ) {
View focusNew= edittext.focusSearch(View.FOCUS_LEFT);
if( focusNew!=null ) focusNew.requestFocus();
} else if( primaryCode==CodeNext ) {
View focusNew= edittext.focusSearch(View.FOCUS_RIGHT);
if( focusNew!=null ) focusNew.requestFocus();
} else { // insert character
editable.insert(start, Character.toString((char) primaryCode));
Log.d(TAG,"INPUT is this: "+Character.toString((char)primaryCode));
}
}
#Override public void onRelease(int primaryCode) {
}
#Override public void onText(CharSequence text) {
}
#Override public void swipeDown() {
}
#Override public void swipeLeft() {
}
#Override public void swipeRight() {
}
#Override public void swipeUp() {
}
};
/**
* Create a custom keyboard, that uses the KeyboardView (with resource id <var>viewid</var>) of the <var>host</var> activity,
* and load the keyboard layout from xml file <var>layoutid</var> (see {#link Keyboard} for description).
* Note that the <var>host</var> activity must have a <var>KeyboardView</var> in its layout (typically aligned with the bottom of the activity).
* Note that the keyboard layout xml file may include key codes for navigation; see the constants in this class for their values.
* Note that to enable EditText's to use this custom keyboard, call the {#link #registerEditText(int)}.
*
* #param host The hosting activity.
* #param viewid The id of the KeyboardView.
* #param layoutid The id of the xml file containing the keyboard layout.
*/
public CustomKeyboard(Activity host, int viewid, int layoutid) {
mHostActivity= host;
mKeyboardView= (KeyboardView)mHostActivity.findViewById(viewid);
mKeyboardView.setKeyboard(new Keyboard(mHostActivity, layoutid));
mKeyboardView.setPreviewEnabled(false); // NOTE Do not show the preview balloons
mKeyboardView.setOnKeyboardActionListener(mOnKeyboardActionListener);
// Hide the standard keyboard initially
mHostActivity.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN);
}
/** Returns whether the CustomKeyboard is visible. */
public boolean isCustomKeyboardVisible() {
return mKeyboardView.getVisibility() == View.VISIBLE;
}
/** Make the CustomKeyboard visible, and hide the system keyboard for view v. */
public void showCustomKeyboard( View v ) {
mKeyboardView.setVisibility(View.VISIBLE);
mKeyboardView.setEnabled(true);
if( v!=null ) ((InputMethodManager)mHostActivity.getSystemService(Activity.INPUT_METHOD_SERVICE)).hideSoftInputFromWindow(v.getWindowToken(), 0);
}
/** Make the CustomKeyboard invisible. */
public void hideCustomKeyboard() {
mKeyboardView.setVisibility(View.GONE);
mKeyboardView.setEnabled(false);
}
/**
* Register <var>EditText<var> with resource id <var>resid</var> (on the hosting activity) for using this custom keyboard.
*
* #param resid The resource id of the EditText that registers to the custom keyboard.
*/
public void registerEditText(int resid) {
// Find the EditText 'resid'
EditText edittext= (EditText)mHostActivity.findViewById(resid);
// Make the custom keyboard appear
edittext.setOnFocusChangeListener(new OnFocusChangeListener() {
// NOTE By setting the on focus listener, we can show the custom keyboard when the edit box gets focus, but also hide it when the edit box loses focus
#Override public void onFocusChange(View v, boolean hasFocus) {
if( hasFocus ) showCustomKeyboard(v); else hideCustomKeyboard();
}
});
edittext.setOnClickListener(new OnClickListener() {
// NOTE By setting the on click listener, we can show the custom keyboard again, by tapping on an edit box that already had focus (but that had the keyboard hidden).
#Override public void onClick(View v) {
showCustomKeyboard(v);
}
});
// Disable standard keyboard hard way
// NOTE There is also an easy way: 'edittext.setInputType(InputType.TYPE_NULL)' (but you will not have a cursor, and no 'edittext.setCursorVisible(true)' doesn't work )
edittext.setOnTouchListener(new OnTouchListener() {
#Override public boolean onTouch(View v, MotionEvent event) {
EditText edittext = (EditText) v;
int inType = edittext.getInputType(); // Backup the input type
edittext.setInputType(InputType.TYPE_NULL); // Disable standard keyboard
edittext.onTouchEvent(event); // Call native handler
edittext.setInputType(inType); // Restore input type
return true; // Consume touch event
}
});
// Disable spell check (hex strings look like words to Android)
edittext.setInputType(edittext.getInputType() | InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS);
}
}
// NOTE How can we change the background color of some keys (like the shift/ctrl/alt)?
// NOTE What does android:keyEdgeFlags do/mean
with MainActivity containing the following:
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.widget.EditText;
public class MainActivity extends AppCompatActivity {
private final static String TAG = "[MainActivity]:";
EditText expressionEditText;
CustomKeyboard mCustomKeyboard;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mCustomKeyboard = new CustomKeyboard(this, R.id.keyboardview, R.xml.calculatorkbd);
Log.d(TAG,"Init the keyboard");
expressionEditText = (EditText)findViewById(R.id.expressionEditText);
Log.d(TAG,"Found the EditText");
mCustomKeyboard.registerEditText(R.id.expressionEditText);
Log.d(TAG,"Registered with the keyboard");
}
#Override
public void onBackPressed() {
if( mCustomKeyboard.isCustomKeyboardVisible() )
mCustomKeyboard.hideCustomKeyboard();
else this.finish();
}
}
Now, the problem is when I press a key on the custom keyboard, the cursor in the EditText is not moving, and the EditText itself is empty. I've read somewhere here that manufacturers are no longer required to propagate such events, or something to that effect. Is that the problem in my case? If not, what is?
The crux was in the line focusCurrent.getClass()!=EditText.class
As it turns out, the class is something like AppCompatEditText.
I remember someone at SO issuing a warning about this in comments. Now everything works.
i am trying to show keyboard onclick
but it is not showing automatically (keyboard is in hidden state in manifest)
working but on double click...
here is the source.
search.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
search_friends.setVisibility(View.VISIBLE);
//my_friends.setVisibility(View.GONE);
search_friends.requestFocus();
if(search_friends.hasFocus())
{
getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE);
}
else
{
getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN);
}
}
});
i want this on single click...
this is my method, I made it for an Util class, I use it in every project and it works:
/**
* For hide ed == null <br/>
* For show ed !=null
*
* #param context
* Activity
* #param ed
* EditText
*/
public static void hideOrShowSoftKeyboard(Activity context, EditText ed) {
try {
InputMethodManager inputManager = (InputMethodManager) context.getSystemService(context.INPUT_METHOD_SERVICE);
if (ed != null) {
inputManager.showSoftInput(ed, 0);
} else {
inputManager.hideSoftInputFromWindow(context.getCurrentFocus().getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS);
}
} catch (NullPointerException e) {
LogService.log(TAG, "NullPointerException");
}
}
// in your implementation
#Override
public void onClick(View v) {
search_friends.setVisibility(View.VISIBLE);
//for showing the keyboard
AppNameUtils.hideOrShowSoftKeyboard(this,search_friends);
}
Is it possible to have a button in a Toast?
In theory, yes because you can build a custom Toast from a layout in XML, but I tried to put a button in it and couldn't get it to register the click.
Did anyone manage to do something like that?
A toast can not be clicked. It is not possible to capture a click inside a toast message.
You will need to build a dialog for that. Look at Creating Dialogs for more info.
The API on the Toast class state that a toast will never receive the focus and because a toast is not a view there is no onClick message. I would assume that therefore childs of a Toast can not be clicked as well.
A toast cant contain a button. Except that the gmail app and the gallery app in jelly beans have a semi toast that contains a button, here is how Google did it
https://gist.github.com/benvd/4090998
I guess this answers your question.
Snippet shows implementation of custom Toast that:
Have similar interface as original Toast class
Can be used as Dialog (have clickable buttons like Gmail app)
Have possibility to set length in millis
Have possibility to set show and cancel animation
Lives only with initialized Activity
Current Limitations:
No screen orientation change are supported
Usage:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//...
View toastView = new View(getBaseContext());
//init your toast view
ActivityToast toast = new ActivityToast(this, toastView);
//set toast Gravity ( Gravity.BOTTOM | Gravity.FILL_HORIZONTAL by default)
toast.setGravity(Gravity.CENTER);
toast.setLength(10000); //set toast show duration to 10 seconds (2 seconds by default)
Animation showAnim; // init animation
Animation.AnimationListener showAnimListener; //init anim listener
toast.setShowAnimation(showAnim);
toast.setShowAnimationListener(showAnimListener);
Animation cancelAnim; // init animation
Animation.AnimationListener cancelAnimListener; //init anim listener
toast.setCancelAnimation(showAnim);
toast.setCancelAnimationListener(showAnimListener);
toast.show(); //show toast view
toast.isShowing(); // check if toast is showing now
toast.cancel(); //cancel toast view
toast.getView(); //get toast view to update it or to do something ..
}
Sources
import android.app.Activity;
import android.os.Handler;
import android.support.annotation.NonNull;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.AlphaAnimation;
import android.view.animation.Animation;
import android.widget.FrameLayout;
public class ActivityToast {
public static final long LENGTH_SHORT = 2000;
public static final long LENGTH_LONG = 3000;
public static final int DEFAULT_ANIMATION_DURATION = 400;
private final Activity mActivity;
private FrameLayout.LayoutParams mLayoutParams;
private Handler mHandler = new Handler();
private ViewGroup mParent;
private FrameLayout mToastHolder;
private View mToastView;
private Animation mShowAnimation;
private Animation mCancelAnimation;
private long mLength = LENGTH_SHORT;
private Animation.AnimationListener mShowAnimationListener;
private Animation.AnimationListener mCancelAnimationListener;
private boolean mIsAnimationRunning;
private boolean mIsShown;
/**
* #param activity Toast will be shown at top of the widow of this Activity
*/
public ActivityToast(#NonNull Activity activity, View toastView) {
mActivity = activity;
mParent = (ViewGroup) activity.getWindow().getDecorView();
mToastHolder = new FrameLayout(activity.getBaseContext());
mLayoutParams = new FrameLayout.LayoutParams(
ViewGroup.LayoutParams.WRAP_CONTENT,
ViewGroup.LayoutParams.WRAP_CONTENT,
Gravity.BOTTOM | Gravity.FILL_HORIZONTAL
);
mToastHolder.setLayoutParams(mLayoutParams);
mShowAnimation = new AlphaAnimation(0.0f, 1.0f);
mShowAnimation.setDuration(DEFAULT_ANIMATION_DURATION);
mShowAnimation.setAnimationListener(mHiddenShowListener);
mCancelAnimation = new AlphaAnimation(1.0f, 0.0f);
mCancelAnimation.setDuration(DEFAULT_ANIMATION_DURATION);
mCancelAnimation.setAnimationListener(mHiddenCancelListener);
mToastView = toastView;
mToastHolder.addView(mToastView);
mToastHolder.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View view, MotionEvent motionEvent) {
if (motionEvent.getAction() == MotionEvent.ACTION_DOWN) {
cancel();
}
return false;
}
});
}
public void show() {
if (!isShowing()) {
mParent.addView(mToastHolder);
mIsShown = true;
if (mShowAnimation != null) {
mToastHolder.startAnimation(mShowAnimation);
} else {
mHandler.postDelayed(mCancelTask, mLength);
}
}
}
public void cancel() {
if (isShowing() && !mIsAnimationRunning) {
if (mCancelAnimation != null) {
mToastHolder.startAnimation(mCancelAnimation);
} else {
mParent.removeView(mToastHolder);
mHandler.removeCallbacks(mCancelTask);
mIsShown = false;
}
}
}
public boolean isShowing() {
return mIsShown;
}
/**
* Pay attention that Action bars is the part of Activity window
*
* #param gravity Position of view in Activity window
*/
public void setGravity(int gravity) {
mLayoutParams.gravity = gravity;
if (isShowing()) {
mToastHolder.requestLayout();
}
}
public void setShowAnimation(Animation showAnimation) {
mShowAnimation = showAnimation;
}
public void setCancelAnimation(Animation cancelAnimation) {
mCancelAnimation = cancelAnimation;
}
/**
* #param cancelAnimationListener cancel toast animation. Note: you should use this instead of
* Animation.setOnAnimationListener();
*/
public void setCancelAnimationListener(Animation.AnimationListener cancelAnimationListener) {
mCancelAnimationListener = cancelAnimationListener;
}
/**
* #param showAnimationListener show toast animation. Note: you should use this instead of
* Animation.setOnAnimationListener();
*/
public void setShowAnimationListener(Animation.AnimationListener showAnimationListener) {
mShowAnimationListener = showAnimationListener;
}
public void setLength(long length) {
mLength = length;
}
public View getView() {
return mToastView;
}
private Runnable mCancelTask = new Runnable() {
#Override
public void run() {
cancel();
}
};
private Animation.AnimationListener mHiddenShowListener = new Animation.AnimationListener() {
#Override
public void onAnimationStart(Animation animation) {
if (mShowAnimationListener != null) {
mShowAnimationListener.onAnimationStart(animation);
}
mIsAnimationRunning = true;
}
#Override
public void onAnimationEnd(Animation animation) {
mHandler.postDelayed(mCancelTask, mLength);
if (mShowAnimationListener != null) {
mShowAnimationListener.onAnimationEnd(animation);
}
mIsAnimationRunning = false;
}
#Override
public void onAnimationRepeat(Animation animation) {
if (mShowAnimationListener != null) {
mShowAnimationListener.onAnimationRepeat(animation);
}
}
};
private Animation.AnimationListener mHiddenCancelListener = new Animation.AnimationListener() {
#Override
public void onAnimationStart(Animation animation) {
if (mCancelAnimationListener != null) {
mCancelAnimationListener.onAnimationStart(animation);
}
mIsAnimationRunning = true;
}
#Override
public void onAnimationEnd(Animation animation) {
mParent.removeView(mToastHolder);
mHandler.removeCallbacks(mCancelTask);
if (mCancelAnimationListener != null) {
mCancelAnimationListener.onAnimationEnd(animation);
}
mIsAnimationRunning = false;
mIsShown = false;
}
#Override
public void onAnimationRepeat(Animation animation) {
if (mCancelAnimationListener != null) {
mCancelAnimationListener.onAnimationRepeat(animation);
}
}
};
}
My original post on github
Post that shows implementation of custom layout in this post
A custom view passed to a toast can contain anything; however, toasts cannot receive any touch events so no components that use touch events will work in a stock toast (buttons, radiobuttons, etc.). The only choice you have is to create a custom view with a button in it and add it to your layout. There are many examples of how to do this and a few libraries you can check out to see how other people are doing it.
UndoBar
MessageBar
Nurik's UndoBar
Of course you are also welcome to use the SuperToasts library I put together however it might be a little overkill for one usage. The way that I do it is outlined in the SuperActivityToast class.
You should use a Snackbar. It is in the latest android support library(at time of answer) and is compatible with older api levels. It is much easier to implement than a Dialog or custom View and has the ability to have a button unlike a Toast.
Download Android Support Library from Extras in the SDK Manager(revision 22.2.1 or later).
In the build.gradle add this to the class dependencies: com.android.support:design:22.2.0.
Implement:
Snackbar.make(this.findViewById(android.R.id.content), "Toast Message", Snackbar.LENGTH_LONG)
.setAction("Click here to activate action", onClickListener)
.setActionTextColor(Color.RED)
.show;
And that is it. No github projects and implementation is very similiar to Toast. I used it in one of my projects and it works great.
You can try SuperToast in this case. It can create toast with button. It has custom duration feature, colourful background, colourful fonts, custom fonts, animated effect. Hope u will enjoy it
Use an alertbox, if you want to add a button :-). Here are some examples
Dialog boxes in Android
Creating a system overlay window (always on top)
This is suggesting that it can be done, I also need buttons in a toast so I still have to make my own implementation. If I find more I will add it to my post