How do I turn off the IME-functionality of an EditText?
Or: How do I avoid the display of the IME-keyboard?
I have a layout where my special keyboard sits below the EditText so there's no need to show the IME. Please understand that I cannot implement my keyboard as IME as it is specific for this very EditText and using it in any other context would only cause problems.
I tried to use
getWindow().setSoftInputMode(LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN);
in the onCreate() of the activity, but that doesn't seem to do anything in this situation.
Think I found a way to do it... subclass EditText and override onCheckIsTextEditor() to return false:
public class EditTextEx extends EditText {
public EditTextEx(Context context, AttributeSet attrs) {
super(context, attrs);
}
#Override
public boolean onCheckIsTextEditor() {
return false;
}
}
I've tested it and I can't get the soft keyboard to show at all.
editText.setInputType(EditorInfo.TYPE_NULL);
While trying to get it working I also tried:
inputField.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
getWindow().setSoftInputMode(LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN);
}
});
inputField.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View view, MotionEvent event) {
getWindow().setSoftInputMode(LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN);
return false;
}
});
Both get called, but neither hide the IME-pop-up.
Related
Is an edittext cursor supposed to continue blinking after the soft keyboard is closed or is this a result of testing on an emulator and wouldn't happen on an actual device? -- as pointed out by the second post in this discussion
Update:
I know that the edittexts still have the cursor blinking because they're still in focus -- logged a message whenever edittext lost focus, but message was never logged when soft keyboard closed.
Update:
I've tried doing:
#Override
public void onBackPressed() {
super.onBackPressed();
getCurrentFocus().clearFocus();
}
So that every time the keyboard is closed, the EditText currently in focus loses that focus and onFocusChanged() is called. The problem is that onBackPressed() isn't called when the back button is pressed when the keyboard is up. I know this because I put a toast in onBackPressed(), and no toast shows when the back button is pressed whilst the keyboard is up.
First create a custom Edit text. Below is the example which has a call back when keyboard back is pressed to dismiss the keyboard
public class EdittextListner extends EditText {
private KeyImeChange keyImeChangeListener;
public EdittextListner(Context context, AttributeSet attrs) {
super(context, attrs);
}
public void setKeyImeChangeListener(KeyImeChange listener) {
keyImeChangeListener = listener;
}
public interface KeyImeChange {
public boolean onKeyIme(int keyCode, KeyEvent event);
}
#Override
public boolean onKeyPreIme(int keyCode, KeyEvent event) {
if (keyImeChangeListener != null) {
return keyImeChangeListener.onKeyIme(keyCode, event);
}
return false;
}
}
Secondly change your EditText to EdittextListner in you layout file.
Finally do the following
mLastNameEditText.setKeyImeChangeListener(new EdittextListner.KeyImeChange() {
#Override
public boolean onKeyIme(int keyCode, KeyEvent event) {
mLastNameEditText.clearFocus();
return true;
}
});
This worked for me. Hope this helps
Edittext is a View which accept input from user, so it is not related with keyborad open or close, when user will click on edittext, that edittext will get focus and cursor will start to blink for taking input,
So you can do one thing as when you are closing keyboard at the same time you can also set visibility of cursor for that edittext so it will stop to blink,
For that you need to write below line when you hide keyboard.
editTextObject.setCursorVisible(false);
This will stope cursor to blink.
As you said, the blinking cursor in the EditText is related to the EditText having focus, but showing or hiding the soft keyboard has no correlation to a View gaining or losing focus. Any View (EditText or otherwise) can be focused independent of whether or not a soft keyboard is showing and there is nothing intrinsic to EditText that would make it behave any differently.
If you want an EditText to lose focus whenever the soft keyboard is hidden, you will need to implement this functionality yourself by listening for changes in the soft keyboard visibility and updating the EditText as a result.
The only way to know keyboard is disappeared is to override
OnglobalLayout and check the height.
Based on that event you can "setCursorVisible(false)" on your edit text
For more information, check this Link.
RelativeLayout mainLayout = findViewById(R.layout.main_layout); // You must use the layout root
InputMethodManager im = (InputMethodManager) getSystemService(Service.INPUT_METHOD_SERVICE);
/*
Instantiate and pass a callback
*/
SoftKeyboard softKeyboard;
softKeyboard = new SoftKeyboard(mainLayout, im);
softKeyboard.setSoftKeyboardCallback(new SoftKeyboard.SoftKeyboardChanged()
{
#Override
public void onSoftKeyboardHide()
{
// Code here
EditText.clearFocus();
}
#Override
public void onSoftKeyboardShow()
{
// Code here
}
});
/*
Open or close the soft keyboard easily
*/
softKeyboard.openSoftKeyboard();
softKeyboard.closeSoftKeyboard();
/* Prevent memory leaks:
*/
#Override
public void onDestroy()
{
super.onDestroy();
softKeyboard.unRegisterSoftKeyboardCallback();
}
try this:
public class EditTextBackEvent extends EditText {
private EditTextImeBackListener mOnImeBack;
public EditTextBackEvent(Context context) {
super(context);
}
public EditTextBackEvent(Context context, AttributeSet attrs) {
super(context, attrs);
}
public EditTextBackEvent(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
#Override
public boolean onKeyPreIme(int keyCode, KeyEvent event) {
if (event.getKeyCode() == KeyEvent.KEYCODE_BACK && event.getAction() == KeyEvent.ACTION_UP) {
if (mOnImeBack != null) mOnImeBack.onImeBack(this, this.getText().toString());
}
return super.dispatchKeyEvent(event);
}
public void setOnEditTextImeBackListener(EditTextImeBackListener listener) {
mOnImeBack = listener;
}
public interface EditTextImeBackListener {
void onImeBack(EditTextBackEvent ctrl, String text);
}
}
in your layout:
<yourpackagename.EditTextBackEvent
android:layout_width="match_parent"
android:layout_height="wrap_content"
/>
and in your fragment:
edittext.setOnEditTextImeBackListener(new EditTextBackEvent.EditTextImeBackListener()
{
#Override
public void onImeBack(EditTextBackEvent ctrl, String text)
{
edittext.clearfocus();
}
});
Try keeping a view in your layout which is focusable above your editText.
<View
android:layout_width="0dp"
android:layout_height="0dp"
android:focusable="true"
android:focusableInTouchMode="true" />
This should work as the blank focusable view should catch focus and not your edittext.
For practicing purpose, I am create a customized Tooltip control. To use the Tooltip control, a hosting UIControl (e.g. a Button) will be assigned to my Tooltip control, and I want my Tooltip control is be able to listen to the mouse press event on the hosting control (i.e. the Button), and show / dismiss itself accordingly.
I am having problem finding a way to listening to mouse events of the hosting control. I tried:
Set the Hosting Control's setOnTouchListener, this works, but it will override the existing OnTouchListener of the Hosting Control, thus undeserable.
Go to the Hosting Control's ViewGroup, and add a **Observer to the ViewGroup. But there is no way to observe the mouse event on the ViewGroup.
So is listening to other control's mouse event doable from a custom view, if so, what's the recommended way to implement it ?
Thanks.
I also thought of another way to do it, as followed:
Get the ViewGroup of the hosting control;
In the ViewGroup, add a transparent view to listen to the mouse event.
In the handler of mouse event of the transparent view, check whether the mouse event is happened on the Hosting Control.
If happened on the Hosting Control, respond correspondingly.
I will try this approach after I post my question, but it seems to be resource-intensive way of implementing something seemingly straightforward.
I will let you know if this approach works or not, any comment / thought is very appreciated.
Thanks ~!
Try to use this approach. I've already tried this approach with OnClickListener and it works great.
public class CustomButton extends Button {
private OnTouchListener outsideListener;
private OnTouchListener innerListener = new OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
if (outsideListener != null) {
outsideListener.onTouch(v, event);
}
//some code here ...
}
};
#Override
public void setOnTouchListener(OnTouchListener listener) {
outsideListener = listener;
}
public CustomButton(Context context) {
super(context);
super.setOnTouchListener(innerListener);
}
public CustomButton(Context context, AttributeSet attrs) {
super(context, attrs);
super.setOnTouchListener(innerListener);
}
public CustomButton(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
super.setOnTouchListener(innerListener);
}
}
as I mentioned in my question, I thought of a way to implement what I wanted. I am sharing my way of implementing here. But still, it seems to be resource-intensive way of solving seemingly simple problem. If you have an easier solution, or any comment, please leave a comment. Much Appreciated ~!
My custom MaterialTooltip class:
public class MaterialToolTip {
/// Implementation
}
An example of how to use my MaterialToolTip class:
public class MainActivity extends AppCompatActivity {
MaterialToolTip toolTip;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// anchorButton is the button to which ToolTip will be added to.
Button anchorButton = (Button)findViewById(R.id.button);
this.toolTip = new MaterialToolTip.Builder(this)
//.anchorView property is used to specify the view that will use this tooltip
.anchorView(anchorButton)
.maxWidth(R.dimen.simpletooltip_max_width)
.build(); // that's all the consumer needs to do, as soon as the tooltip is attached to the View, the tooltip decided when to show / dismiss by listening to View's event.
}
}
Within my MaterialToolTip class:
Create a transparent view that listens to mouse event
#SuppressLint("ViewConstructor")
public class ToolTipPressInterceptView extends View {
OnAnchorViewMouseEventListener mListener;
ToolTipPressInterceptView(Context context, View anchorView) {
super(context);
//get the anchorView's onScreenLocation
int[] output = new int[2];
anchorView.getLocationOnScreen(output);
anchorViewRect = new RectF(output[0], output[1], output[0] + anchorView.getMeasuredWidth(), output[1] + anchorView.getMeasuredHeight()) ;
//set the dimension to match parent
this.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
this.setOnTouchListener(new OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()){
case MotionEvent.ACTION_DOWN:{
if (anchorViewRect.contains(event.getX(), event.getY())){
mListener.onMouseEvent(AnchorViewMouseEventType.PRESSED);
}
}
case MotionEvent.ACTION_UP:{
if (anchorViewRect.contains(event.getX(), event.getY())){
mListener.onMouseEvent(AnchorViewMouseEventType.RELEASED);
}
}
}
return false;
}
});
}
}
Get the ViewGroup of the hosting control, and add the transparent view to the ViewGroup;
private MaterialToolTip(Builder builder){
//.. Other initialisation logic
//.. add the TransparentView to the ViewGroup;
mRootView = (ViewGroup)mAnchorView.getRootView();
ToolTipPressInterceptView view = new ToolTipPressInterceptView(mContext, mAnchorView);
//mAnchorViewTouchListener is listener to Mouse Event
view.setOnTouchListener(mAnchorViewTouchListener);
mRootView.addView(view);
}
If happened on the Hosting Control, respond correspondingly.
private final View.OnTouchListener mAnchorViewTouchListener = new
View.OnTouchListener(){
#Override
public boolean onTouch(View v, MotionEvent event){
int action = MotionEventCompat.getActionMasked(event);
switch(action) {
case (MotionEvent.ACTION_DOWN) :
// show
show();
case (MotionEvent.ACTION_UP) :
// dismiss
dismiss();
}
return false; //return false so the other handlers is able to
}
};
I have a custom dialog which is a DialogFragment. This dialog have a EditText and my own keyboard view so I don't want to use the default virtual keyboard.
I hide the virtual keyboard everytime user touch the EditText:
edtAmount.setOnTouchListener(new OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
v.onTouchEvent(event);
View view = this.getDialog().getCurrentFocus();
if (view != null) {
InputMethodManager imm = (InputMethodManager) getActivity()
.getSystemService(Context.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(view.getWindowToken(),0);
}
return true;
}
});
But because the system still call the virtual keyboard to show (Before is force to hide it), then system move my dialog up and down very quickly. This is not good.
Can someone help me to avoid the dialog pushed up like this, just keep it stay still?
PS: I tried in Manifest:
android:windowSoftInputMode="adjustNothing"
But seem like not work.
Thank you very much.
EDIT
I want to keep the cursor so I find the solution in this thread:
https://stackoverflow.com/a/14184958/2961402
Hope this help some one.
This can only done when you extends the EditText from your custom EditText, please use the below code for custom EditText which never open Soft Keyboard ever...!
public class DisableSoftKeyBoardEditText extends EditText {
public DisableSoftKeyBoardEditText(Context context, AttributeSet attrs) {
super(context, attrs);
}
#Override
public boolean onCheckIsTextEditor() {
return false;
}
}
Try this code. In my app it work perfectly
getActivity().getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN);
I have a LinearLayout with several EditText's, all of them created programmatically (not with an XML layout), and in particular without IDs.
When I'm typing in one of the EditText's, and the next one (respective to focus) is disabled, and I press the Next IME button on the keyboard, the focus advances to the disabled EditText, but I can't type anything in it.
What I was expecting was focus to advance to the next enabled EditText. I also tried, in addition to making the EditText disabled via edittext.setEnabled(false), to disable its focusability via edittext.setFocusable(false) and edittext.setFocusableInTouchMode(false), and to set a TYPE_NULL input type, but to no avail.
Any hints?
Thanks ;)
Solved by examining how the next focusable is found by the keyboard from this blog post and by subclassing EditText:
import android.content.Context;
import android.util.AttributeSet;
import android.view.View;
import android.widget.EditText;
public class MyEditText extends EditText {
public MyEditText(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public MyEditText(Context context, AttributeSet attrs) {
super(context, attrs);
}
public MyEditText(Context context) {
super(context);
}
#Override
public View focusSearch(int direction) {
View v = super.focusSearch(direction);
if (v != null) {
if (v.isEnabled()) {
return v;
} else {
// keep searching
return v.focusSearch(direction);
}
}
return v;
}
}
More details:
ViewGroup implementation of focusSearch() uses a FocusFinder, which invokes addFocusables(). The ViewGroup's implementation tests for visibility, while the View implementation tests for focusability. Neither test for the enabled state, which is why I added this test to MyEditText above.
I solved it setting the focusable property to false, not only the enabled property:
editText.setEnabled(false);
editText.setFocusable(false);
See
EditText editText = (EditText) findViewById(R.id.search);
editText.setOnEditorActionListener(new OnEditorActionListener() {
#Override
public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
boolean handled = false;
if (actionId == EditorInfo.IME_ACTION_SEND) {
sendMessage();
handled = true;
}
return handled;
}
});
This was grabbed from http://developer.android.com/training/keyboard-input/style.html#Action .
If you can figure out how to focus on the next TextView, you can add an OnEditorActionListener to every TextView and have it pass the focus to the next one if it is disabled.
Found two solutions - please see selected answer
When the user clicks in a certain region of an EditText, I want to popup a dialog. I used onClick to capture the click. This partially works: the first time the user taps the EditText, the soft keyboard pops up and the dialog doesn't. Subsequent taps bring up the keyboard and then the dialog (and the keyboard disappears).
I suspect this has something to do with the EditText gaining focus.
Here's a code snip:
public class PrefixEditText extends EditText implements TextWatcher, OnClickListener
{
public PrefixEditText (Context context)
{
super (context);
setOnClickListener (this);
}
#Override
public void onClick(View v)
{
int selStart = getSelectionStart();
if (selStart < some_particular_pos)
bring_up_dialog();
}
}
IMPORTANT: I don't want to completely disable the normal EditText behavior. I want the user to be able to make region selections (for copy & paste). I probably still want it to gain focus (so I don't break the model when people with physical keyboards use the app). And it's ok for the click to set the cursor position. Thus, solutions that override onTouch and block all onTouch actions from the EditText will not work for me.
UPDATE I've discovered a bit more. If the EditText is gaining focus, onFocusChange gets called and onClick does not. If it already has focus, onClick gets called and onFocusChange does not.
Secondly, it's possible to hide the keyboard by calling
setInputType (InputType.TYPE_NULL);
Doing so in onFocusChange works - the keyboard never shows up. Doing so in onClick (assuming the keyboard was hidden before the click) apparently is too late - the keyboard shows up and then disappears.
The next idea to try would be to hide the keyboard during onTouch. However, I'm afraid to mess with that code - seems that whatever I figure out would be very fragile with respect to future versions of EditText.
Any thoughs on this?
May be this can work
EditText e = new EditText(context);
e.setOnFocusChangeListener(new OnFocusChangeListener() {
public void onFocusChange(View v, boolean hasFocus) {
// TODO Auto-generated method stub
if(hasFocus)
{
//dialogue popup
}
}
});
or u can use e.hasFocus(); and then use e.setFocusable(false); to make it unfocus
/////////////// my code
e.setInputType(InputType.TYPE_NULL);
e.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
// TODO Auto-generated method stub
AlertDialog.Builder sa = new Builder(ctx);
sa.create().setOnDismissListener(new OnDismissListener() {
public void onDismiss(DialogInterface dialog) {
// TODO Auto-generated method stub
e.setInputType(InputType.TYPE_CLASS_TEXT);
}
});
sa.show();
}
});
try change capture click by onClick to onTouch
this.editText.setOnTouchListener(new OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
//dialogue popup
}
return false;
}
});
try this if it can help u.first time the edittext will behave as a normal editttext and on condition u can show the dialog as needed
EditText editText;
mTim_edittext.setOnFocusChangeListener(new OnFocusChangeListener() {
public void onFocusChange(View v, boolean hasFocus) {
if(!hasFocus){
//statement
if(condition){
AlertDialog diaBox = Utils.showErrorDialogBox( "Term in Months Cannot be 0", context);
diaBox.show();
}
}
}
});
After lots of experiments, here are two working solutions! I tested them on my two devices - Nexus 7 running 4.2.1, Kyocera C5170 runing 4.0.4. My preference is Solution 2.
SOLUTION 1
For the first, the trick was to determine the cursor position in onTouch instead of onClick, before EditText has a chance to do it's work - particularly before it pops up the keyboard.
One additional comment: be sure to set android:windowSoftInputMode="stateHidden" in your manifest for the popup, or you'll get the keyboard along with the popup.
Here's the whole code:
public class ClickText extends EditText implements OnTouchListener
{
public ClickText (Context context, AttributeSet attrs)
{
super (context, attrs);
setOnTouchListener (this);
}
#Override
public boolean onTouch (View v, MotionEvent event)
{
if (event.getActionMasked() == MotionEvent.ACTION_DOWN)
{
int line = getLayout().getLineForVertical ((int)event.getY());
int onTouchCursorPos = getLayout().getOffsetForHorizontal (line, event.getX());
if (onTouchCursorPos < 10) // or whatever condition
showPopup (this); // or whatever you want to do
}
return false;
}
private void showPopup (final EditText text)
{
Intent intent = new Intent (getContext(), Popup.class);
((Activity)getContext()).startActivity (intent);
}
}
SOLUTION 2
This one is actually simpler and, I think, is better - fewer side effects.
Here, the trick is to let EditText do all its click processing and then override it asynchronously. The gist is: wait for the touch to "let go" - MotionEvent.ACTION_UP - and then instead of doing your action right then, post a Runnable to the event queue and do your action there.
The whole code:
public class ClickText extends EditText implements OnTouchListener
{
public ClickText (Context context, AttributeSet attrs)
{
super (context, attrs);
setOnTouchListener (this);
}
#Override
public boolean onTouch (View v, MotionEvent event)
{
switch (event.getActionMasked())
{
case MotionEvent.ACTION_UP:
{
post (new Runnable ()
{
// Do this asynch so that EditText can finish setting the selectino.
#Override
public void run()
{
int selStart = getSelectionStart();
int selEnd = getSelectionEnd();
// If selStart is different than selEnd, user has highlighed an area of
// text; I chose to ignore the click when this happens.
if (selStart == selEnd)
if (selStart >= 0 && selStart < 10) // or whatever range you want
showPopup (this);
}
});
break;
}
}
return false;
}
private void showPopup (final EditText text)
{
Intent intent = new Intent (getContext(), Popup.class);
((Activity)getContext()).startActivity (intent);
}
}
use this below code snippet
this.editText.setOnTouchListener(new OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
//dialogue popup
}
return false;
}
});