Open keyboard only on second touch on an EditText - android

I am trying to achieve the following: my layout has a number of EditTexts. When the user touches one of the EditTexts for the first time, the keyboard should not open but the EditText should just gain focus. This is because I am doing a calculation in the EditText when it gains focus and I want to display the result to the user. Then when the user has seen the result he can touch the EditText again which will selectAll and open the keyboard to enter a new number.
This is the code I am using right now:
myEditText.setOnTouchListener(new View.OnTouchListener() {
public boolean onTouch(View v, MotionEvent event) {
if(iFocus == R.id.eTmyEditText) {
if(iCount == 3) {
myEditText.selectAll();
InputMethodManager imm = (InputMethodManager)getSystemService(Context.INPUT_METHOD_SERVICE);
imm.showSoftInput(myEditText, InputMethodManager.SHOW_IMPLICIT);
}
if(iCount > 3) return false;
iCount++;
}
else iCount=0;
myEditText.requestFocus();
return true;
}
});
I am using the iCount variable to distinguish the first touch from the second and the ones which will follow. iFocus is set in the focusChangeListener and holds the last EditText which had focus.
The code is working fine sometimes but not always. From time to time the keyboard is not opening or already on the first touch, sometimes the text is not selected, etc.
Is it possible that the TouchEvent bounces somehow? So that the TouchListener is executed more often than I would expect it to be? I also tried to separate the down event and the up event but this does not help.
Has anyone a good idea how what I am trying to do could be implemented in a better way? Thanks
EDIT: this is my final solution:
myEditText.setOnTouchListener(new View.OnTouchListener() {
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
myEditText.requestFocus();
if(iCount == 1){
myEditText.postDelayed(new Runnable() {
public void run() {
InputMethodManager manager = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
manager.showSoftInput(myEditText, 0);
myEditText.selectAll();
}
}, 200);
}
iCount++;
break;
default:
break;
}
if(iCount >= 2) return false;
else return true;
}
});

Try this, its working for me when I touch the EditText two Times.
mEditText.setOnTouchListener(new View.OnTouchListener() {
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
iCount++;
if(iCount == 2){
mEditText.requestFocus();
InputMethodManager manager = (InputMethodManager)
getSystemService(Context.INPUT_METHOD_SERVICE);
manager.showSoftInput(mEditText, 0);
iCount = 0;
}
break;
default:
break;
}
return true;
}
});

Try to replace
myEditText.setOnTouchListener(...);
with
myEditText.setOnClickListener(...);

Have a TextView that has the same background and size as the EditText, and switch between them on first tap, and switch them back again when the EditText loses focus.
Or store the current getKeyListener(), setKeyListener(null) and then restore after first click.
Or subclass EditText and override getDefaultEditable() to return false unless it already has focus.

Related

Custom keyboard set visibility gone when touch event dispatch from editText

I want to mimic android keyboard behavior when handling touch event. The android keyboard always hide every time I click somewhere else other the edit text and the keyboard. So far, I could mimic that's behavior using dispatchTouchEvent
Since it will detect for any dispatch touch even, whenever I click my keyboard button then it will close the keyboard it self. I wanna check if I click somewhere else other than my keyboard then hide the keyboard, else keep the keyboard on. I think I just missed piece of code and I can't find it what i missed here. It just need one single step to accomplish this. Please help.
Here my keyboard looks like
and here what i did so far
#Override
public boolean dispatchTouchEvent(MotionEvent ev) {
if (getCurrentFocus() != null) {
View view = getCurrentFocus();
//im not sure this condition would help
if (view == null) {
keyboard.setVisibility(View.GONE);
}
}
return super.dispatchTouchEvent(ev);
}
I can get the view object but i cant determine which view that i need to keep my keyboard on.
The other code (variable declaration)
PhoneKeyboard pk;
InputConnection ic;
LinearLayout keyboard;
pk = findViewById(R.id.phone_keyboard);
ic = phone_no.onCreateInputConnection(new EditorInfo());
pk.setInputConnection(ic);
Handling back pressed (mimic the android keyboard behavior)
#Override
public void onBackPressed(){
if(keyboard.getVisibility() == View.GONE)
super.onBackPressed();
else
keyboard.setVisibility(View.GONE);
}
How I handle request on the editText to make my keyboard visible
phone_no.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View view, MotionEvent motionEvent) {
InputMethodManager imm = (InputMethodManager) getApplicationContext().getSystemService(
android.content.Context.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(view.getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS);
if(view.equals(phone_no) && keyboard.getVisibility() == View.GONE) {
phone_no.requestFocus();
keyboard.setVisibility(View.VISIBLE);
}
return false;
}
});
How I handle submit / enter event at my custom keyboard (for who need the solution for custom keyboard, maybe this post can help other:) )
phone_no.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View view, MotionEvent motionEvent) {
InputMethodManager imm = (InputMethodManager) getApplicationContext().getSystemService(
android.content.Context.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(view.getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS);
if(view.equals(phone_no) && keyboard.getVisibility() == View.GONE) {
phone_no.requestFocus();
keyboard.setVisibility(View.VISIBLE);
}
return false;
}
});
Here is my snippet code for the keyboard layout view
<include
layout="#layout/layout_keyboard_phone_no"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:focusableInTouchMode="false"
app:layout_constraintBottom_toBottomOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
Ps. I also have base activity and it extends to all my activity (if your solution required the base activity)
Update 1
I have try this method
phone_no.setOnFocusChangeListener(new View.OnFocusChangeListener() {
#Override
public void onFocusChange(View v, boolean hasFocus) {
if (!hasFocus) {
keyboard.setVisibility(View.GONE);
}
}
});
Is doing the same thing with the onDispatch event, whenever I click number on my custom keyboard, it also hide the keyboard. I need to check if the view others than the edit text and my custom keyboard then hide the keyboard else keep the keyboard on. Thank you

Return false in onEditorAction

The TextView's onEditorAction method's documentation says
Return true if you have consumed the action, else false.
Most examples I see online return true. But in this case, the soft keyboard stays opened.
Is it legit to return false to let the system handle the soft keyboard or does that have any side effects?
private TextView.OnEditorActionListener inputListener = new TextView.OnEditorActionListener() {
#Override
public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
switch (actionId) {
case EditorInfo.IME_ACTION_NEXT:
Toast.makeText(MainActivity.this, "Next", Toast.LENGTH_SHORT).show();
break;
case EditorInfo.IME_ACTION_DONE:
Toast.makeText(MainActivity.this, "Done", Toast.LENGTH_SHORT).show();
break;
}
return false;
}
};
That's totally OK.
The documentation refers to the action you want to make, if you succeeded in your action, return true. false otherwise.
So.. the keyboard doesn't matter here. if you have problem with the keyboard just hide it yourself.
// Check if no view has focus:
View view = this.getCurrentFocus();
if (view != null) {
InputMethodManager imm = (InputMethodManager)getSystemService(Context.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(view.getWindowToken(), 0);
}

How to open Keyboard programmatically when move from one activity

i am trying to open keyboard when i move to first activity to second activity.
There is two button in main activity
1) if click on "NotShowKeyboard" button it will open the second.java activity with out keyboard
2) if s"ShowKeyboard" button is clicked then it will open the second.java activity with keyboard and EitdText with focus
But problem is that i don't know how to do that. I put some examples top show keyboard but on "ShowKeyboard" button click keyboard open and immediately disappear.
Main.java:
NotShowKeyboard.setOnTouchListener(new View.OnTouchListener() {
public boolean onTouch(View v, MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
}
if (event.getAction() == MotionEvent.ACTION_UP) {
bundle.putBoolean("show", false);
Intent start = new Intent(Main.this, Start.class);
start.putExtras(bundle);
startActivity(start);
}
return false;
}
});
ShowKeyboard.setOnTouchListener(new View.OnTouchListener() {
public boolean onTouch(View v, MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
}
if (event.getAction() == MotionEvent.ACTION_UP) {
bundle.putBoolean("show", true);
Intent start = new Intent(Main.this, Start.class);
start.putExtras(bundle);
startActivity(start);
}
return false;
}
});
Second.java:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.start);
i = getIntent();
extras = i.getExtras();
search = (EditText) findViewById(R.id.start_edit);
search.addTextChangedListener(myTextWatcher);
if((extras.getBoolean("show"))==true) {
((InputMethodManager)getSystemService(Context.INPUT_METHOD_SERVICE)).toggleSoftInput(InputMethodManager.SHOW_FORCED, InputMethodManager.HIDE_IMPLICIT_ONLY);
}
//getting all stuff like buttons imageViews etc..
}
When NotShowButton Clicked then this should open:
When ShowButton Clicked then this should open:
For hiding keyboard:
InputMethodManager imm = (InputMethodManager)getSystemService(
Context.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(myEditText.getWindowToken(), 0);
For Showing keyboard:
InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
imm.toggleSoftInput(InputMethodManager.SHOW_FORCED, 0);
Have you tried this?
getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE);
Try and put this code in onResume()
Sometimes it depends on the device, if the softkeyboard comes up or not. On my Vodafone Smart II phone there didnt came it (3,5" display) on my Intexo TAB814 (8" display) there it was. Same App, but different results. It also semms to depend on the android version u use. (Vodafone smart II -> 2.1.3, Intenso tablet 4.1) try on another device

how to restore the edittext cursor position to end after requesting focus

When i request for a focus for an editext few times it is moving the cursor to beginning even if there is some text. How can we place the cursor in such a way that it will be immediately after the text that is already present in it??
This will set the cursor to the last position of the text:
editText.setSelection(editText.getText().length());
Edit Text has a property called append.I think the following line of code will also serve the purpose.
editText.append("");
In Layout EditText give android:ellipsize property as end like this android:ellipsize="end"
Hope this will help
I had a similar requirement, when user wants to edit and clicks on EditText, cursor should be at the end. I achieved the same using below:
edtDisplayName.setOnTouchListener(new OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_UP || event.getAction() == MotionEvent.ACTION_DOWN) {
edtDisplayName.setSelection(edtDisplayName.getText()
.length());
edtDisplayName.requestFocus();
//Open key board for user to edit
Commons.showKeyBoard(OnBoardActivity.this, edtDisplayName);
return true;
}
return false;
}
});
Here's how I opened the key-board:
public static void showKeyBoard(Context context, View view) {
InputMethodManager imm = (InputMethodManager) context
.getSystemService(Context.INPUT_METHOD_SERVICE);
imm.showSoftInput(view, 0);
}

Tap outside edittext to lose focus

I just want when click outside the "edittext" to automatically lose focus and hide keyboard. At the moment, if I click on the "edittext" it focuses but i need to hit the back button to unfocus.
To solve this problem what you have to do is first use setOnFocusChangeListener of that Edittext
edittext.setOnFocusChangeListener(new View.OnFocusChangeListener() {
#Override
public void onFocusChange(View v, boolean hasFocus) {
if (!hasFocus) {
Log.d("focus", "focus lost");
// Do whatever you want here
} else {
Log.d("focus", "focused");
}
}
});
and then what you need to do is override dispatchTouchEvent in the activity which contains that Edittext see below code
#Override
public boolean dispatchTouchEvent(MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
View v = getCurrentFocus();
if ( v instanceof EditText) {
Rect outRect = new Rect();
v.getGlobalVisibleRect(outRect);
if (!outRect.contains((int)event.getRawX(), (int)event.getRawY())) {
Log.d("focus", "touchevent");
v.clearFocus();
InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(v.getWindowToken(), 0);
}
}
}
return super.dispatchTouchEvent(event);
}
Now what will happen is when a user click outside then, firstly this dispatchTouchEvent will get called which then will clear focus from the editext, now your OnFocusChangeListener will get called that focus has been changed, now here you can do anything which you wanted to do, hope it works :)
#woodshy has the answer for hiding the keyboard, but maybe putting the code in onClick is not as good as putting it in onFocusChanged. As for forcing it to lose focus, you need to set the object you want to transfer the focus to, in its XML file:
android:focusable="true"
android:focusableInTouchMode ="true"
Suppose your EditText is placed on Linear layout or other ViewGroup. Then you should make this container clickable, focusable and focusableInTouchMode. After that set onClickListener to this container with following code in onClick Override method:
#Override
public void onClick(View view) {
InputMethodManager imm = (InputMethodManager) view.getContext()
.getSystemService(Context.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(view.getWindowToken(), 0);
}
You can achieve this by doing the following steps:
1.Make the parent view(content view of your activity) clickable and focusable by adding the following attributes
android:clickable="true"
android:focusableInTouchMode="true"
2.Implement a hideKeyboard() method
public void hideKeyboard(View view) {
InputMethodManager inputMethodManager =(InputMethodManager)getSystemService(Activity.INPUT_METHOD_SERVICE);
inputMethodManager.hideSoftInputFromWindow(view.getWindowToken(), 0);
}
3.Lastly, set the onFocusChangeListener of your edittext.
edittext.setOnFocusChangeListener(new View.OnFocusChangeListener() {
#Override
public void onFocusChange(View v, boolean hasFocus) {
if (!hasFocus) {
hideKeyboard(v);
}
}
});
The following code works perfectly for me, and I regularly use this for closing the SoftKeyboard onTouch anywhere outside the EditText.
public void hideSoftKeyboard()
{
//Hides the SoftKeyboard
InputMethodManager inputMethodManager = (InputMethodManager) getActivity().getSystemService(Activity.INPUT_METHOD_SERVICE);
inputMethodManager.hideSoftInputFromWindow(getActivity().getCurrentFocus().getWindowToken(), 0);
}
public void setupUI(View view)
{
String s = "inside";
//Set up touch listener for non-text box views to hide keyboard.
if (!(view instanceof EditText)) {
view.setOnTouchListener(new View.OnTouchListener() {
public boolean onTouch(View v, MotionEvent event) {
hideSoftKeyboard();
return false;
}
});
}
//If a layout container, iterate over children and seed recursion.
if (view instanceof ViewGroup) {
for (int i = 0; i < ((ViewGroup) view).getChildCount(); i++) {
View innerView = ((ViewGroup) view).getChildAt(i);
setupUI(innerView);
}
}
}
So you just need to call the setupUI() function once in your onCreate() method and voilla, your hidingSoftKeyboard is setup!
For Losing complete focus of the EditText, simply do editText.clearFocus() in your hideSoftKeyboard() function.
Here universal method for all screens. Put it in your activity
override fun dispatchTouchEvent(ev: MotionEvent?): Boolean {
clearFocusOnOutsideClick()
return super.dispatchTouchEvent(ev)
}
/*
* Clear focus on outside click
* */
private fun clearFocusOnOutsideClick() {
currentFocus?.apply {
if (this is EditText) {
clearFocus()
}
//Hide keyboard
val imm: InputMethodManager =
getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
imm.hideSoftInputFromWindow(windowToken, InputMethodManager.HIDE_NOT_ALWAYS)
}
}
kotlin clearfocus android outside
So I searched around a little bit, and no other solutions was exactly what I was looking for. In my opinion the focus behave strangely on EditText views.
What I did was...
Make sure the root view is a RelativeLayout
Add an overlay layout that is OVER the area that will make the keyboard disapear, but not the EditText. Something like below:
In my case, the EditText was in a container at the bottom of the screen. so it covered everyhting else.
Have a method that looks a bit like this one :
private void hideKeyboard() {
final InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(editText.getWindowToken(), 0);
keyboardOverlay.setVisibility(View.GONE);
editText.clearFocus();
}
Now call this method on the onClick of the overlay you created.
What we want now is to make the overlay visible when you press on the editText. You cannot use the onFocus event (at least I did not get it to work...) So what i did is I managed the onTouch event instead.
editText.setOnTouchListener(new OnTouchListener() {
#Override
public boolean onTouch(final View v, final MotionEvent event) {
keyboardOverlay.setVisibility(View.VISIBLE);
editText.requestFocus();
return false;
}
});
The requestFocus() here is to not override the focus event with the onTouch.
Quick advice, when you try this out, you can add a background color to the overlay to see exactly what is happening.
Hope it works for you!
set in a button or any view: this.getCurrentFocus().clearFocus();
For example:
#Override
public boolean onMenuOpened(int featureId, Menu menu) {
InputMethodManager imm = (InputMethodManager) getSystemService(INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(getCurrentFocus().getWindowToken(), 0);
this.getCurrentFocus().clearFocus();
return super.onMenuOpened(featureId, menu);
}
I had the same requirement as I had to hide the keyboard once I touch anywhere outside my EditText box. The setOnFocusChangeListener does not do the job as even if you touch outside the edit text box is still selected.
For this I used the solution edc598 here.
I first got the MainLayout containing the whole view and add touch listener to it.
When onTouch event was triggered I check if the EditText box has focus.
If the EditText box has focus then I check the event's X-Y co-ordinates.
Based on the placement of my EditText box I hide the key board if touched anywhere outside the box
Code sample modified from here:
LinearLayout MainLayout = (LinearLayout) findViewById(R.id.MainLayout);
EditText textBox = (EditText) findViewById(R.id.textBox);
int X_TOP_LEFT = 157;
int Y_TOP_LEFT = 388;
int X_BOTTOM_RIGHT = 473;
int Y_BOTTOM_RIGHT = 570;
MainLayout.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
// TODO Auto-generated method stub
if(textBox.isFocused()){
Log.i("Focussed", "--" + event.getX() + " : " + event.getY() + "--");
if(event.getX() <= 157 || event.getY() <= 388 || event.getX() >= 473 || event.getY() >= 569){
//Will only enter this if the EditText already has focus
//And if a touch event happens outside of the EditText
textBox.clearFocus();
InputMethodManager imm = (InputMethodManager) v.getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(v.getWindowToken(), 0);
//Do something else
}
}
Log.i("X-Y coordinate", "--" + event.getX() + " : " + event.getY() + "--");
//Toast.makeText(getBaseContext(), "Clicked", Toast.LENGTH_SHORT).show();
return false;
}
});

Categories

Resources