EditText, wyraźne skupienie na dotyku Na Zewnątrz
Mój layout zawiera ListView
, SurfaceView
i EditText
. Kiedy klikam na EditText
, otrzymuje fokus i wyskakuje klawiatura ekranowa. Kiedy klikam gdzieś poza EditText
, nadal ma fokus (nie powinien).
Myślę, że mógłbym ustawić OnTouchListener
' s na innych widokach w layout i ręcznie wyczyścić EditText
'S focus. Ale wydaje się zbyt hakerski...
Mam również taką samą sytuację w innym widoku layout-list z różnymi typami elementów, z których niektóre mają EditText
' S wewnątrz. Działają tylko tak jak pisałem wyżej.
Zadanie polega na tym, aby EditText
stracić ostrość, gdy użytkownik dotknie czegoś poza nim.
Widziałem podobne pytania tutaj, ale nie znalazłem żadnego rozwiązania...
13 answers
Próbowałem tych wszystkich rozwiązań. edc598 był najbliżej pracy, ale zdarzenia dotykowe nie uruchamiały się na innych View
zawartych w układzie. W przypadku, gdyby ktoś potrzebował tego zachowania, To właśnie to zrobiłem:
Stworzyłem (niewidoczny) FrameLayout
o nazwie touchInterceptor jako ostatni View
w układzie, tak aby nakładał się na wszystko (edit: musisz również użyć RelativeLayout
jako nadrzędnego układu i dać touchInterceptor fill_parent
atrybuty). Wtedy użyłem aby przechwycić dotknięcia i określić, czy dotyk był na górze EditText
, czy nie:
FrameLayout touchInterceptor = (FrameLayout)findViewById(R.id.touchInterceptor);
touchInterceptor.setOnTouchListener(new OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
if (mEditText.isFocused()) {
Rect outRect = new Rect();
mEditText.getGlobalVisibleRect(outRect);
if (!outRect.contains((int)event.getRawX(), (int)event.getRawY())) {
mEditText.clearFocus();
InputMethodManager imm = (InputMethodManager) v.getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(v.getWindowToken(), 0);
}
}
}
return false;
}
});
Zwróć false, aby pozwolić, aby dotyk przeszedł.
To jest hacky, ale to jedyna rzecz, która mi pomogła.Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-01-12 18:53:00
Bazując na odpowiedzi Kena, oto najbardziej modułowe rozwiązanie do kopiowania i wklejania.
XML nie jest potrzebny.
Umieść go w swojej aktywności, a będzie on miał zastosowanie do wszystkich edycji, w tym do fragmentów w tej aktywności.
@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())) {
v.clearFocus();
InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(v.getWindowToken(), 0);
}
}
}
return super.dispatchTouchEvent( event );
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-06-19 12:40:01
Dla nadrzędnego widoku EditText niech następujące 3 atrybuty będą " true":
klikalne, focusable, focusableInTouchMode .
Jeśli widok chce otrzymać ostrość, musi spełniać te 3 warunki.
Zobacz android.Widok :
public boolean onTouchEvent(MotionEvent event) {
...
if (((viewFlags & CLICKABLE) == CLICKABLE ||
(viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE)) {
...
if (isFocusable() && isFocusableInTouchMode()
&& !isFocused()) {
focusTaken = requestFocus();
}
...
}
...
}
Mam nadzieję, że to pomoże.Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-04-21 14:39:01
Odpowiedź Kena działa, ale jest hacky. Jak wspomina PCAN w komentarzu odpowiedzi, to samo można zrobić z dispatchTouchEvent. To rozwiązanie jest czystsze, ponieważ pozwala uniknąć hakowania XML za pomocą przezroczystego, fałszywego FrameLayout. Oto jak to wygląda:
@Override
public boolean dispatchTouchEvent(MotionEvent event) {
EditText mEditText = findViewById(R.id.mEditText);
if (event.getAction() == MotionEvent.ACTION_DOWN) {
View v = getCurrentFocus();
if (mEditText.isFocused()) {
Rect outRect = new Rect();
mEditText.getGlobalVisibleRect(outRect);
if (!outRect.contains((int)event.getRawX(), (int)event.getRawY())) {
mEditText.clearFocus();
//
// Hide keyboard
//
InputMethodManager imm = (InputMethodManager) v.getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(v.getWindowToken(), 0);
}
}
}
return super.dispatchTouchEvent(event);
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-11-28 20:48:14
Po prostu umieść te właściwości w top most parent.
android:focusableInTouchMode="true"
android:clickable="true"
android:focusable="true"
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-09-09 04:18:15
Prawdopodobnie już znalazłeś odpowiedź na ten problem, ale szukałem, jak to rozwiązać i nadal nie mogę znaleźć dokładnie tego, czego szukałem, więc pomyślałem, że opublikuję go tutaj.
To co zrobiłem było następujące (To jest bardzo uogólnione, celem jest dać ci pomysł, jak postępować, kopiowanie i wklejanie całego kodu nie będzie działać O: D): {]}
Najpierw umieść edytowany tekst i inne widoki w programie owinięte pojedynczym widokiem. W moim przypadku użyłem LinearLayout do zawijania wszystkiego.
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/mainLinearLayout">
<EditText
android:id="@+id/editText"/>
<ImageView
android:id="@+id/imageView"/>
<TextView
android:id="@+id/textView"/>
</LinearLayout>
Następnie w kodzie musisz ustawić Touch Listener do głównego LinearLayout.
final EditText searchEditText = (EditText) findViewById(R.id.editText);
mainLinearLayout.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
// TODO Auto-generated method stub
if(searchEditText.isFocused()){
if(event.getY() >= 72){
//Will only enter this if the EditText already has focus
//And if a touch event happens outside of the EditText
//Which in my case is at the top of my layout
//and 72 pixels long
searchEditText.clearFocus();
InputMethodManager imm = (InputMethodManager) v.getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(v.getWindowToken(), 0);
}
}
Toast.makeText(getBaseContext(), "Clicked", Toast.LENGTH_SHORT).show();
return false;
}
});
Mam nadzieję, że to pomoże niektórym ludziom. Albo przynajmniej pomaga im rozwiązać swój problem.Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-12-22 22:10:00
Naprawdę uważam, że jest to bardziej solidny sposób użycia getLocationOnScreen
niż getGlobalVisibleRect
. Bo mam problem. Istnieje Listview, który zawiera Edittext i ustawia ajustpan
w aktywności. Znajduję getGlobalVisibleRect
Zwraca wartość, która wygląda tak, że zawiera scrollY w nim, ale zdarzenie.getRawY jest zawsze przy ekranie. Poniższy kod działa dobrze.
public boolean dispatchTouchEvent(MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
View v = getCurrentFocus();
if ( v instanceof EditText) {
if (!isPointInsideView(event.getRawX(), event.getRawY(), v)) {
Log.i(TAG, "!isPointInsideView");
Log.i(TAG, "dispatchTouchEvent clearFocus");
v.clearFocus();
InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(v.getWindowToken(), 0);
}
}
}
return super.dispatchTouchEvent( event );
}
/**
* Determines if given points are inside view
* @param x - x coordinate of point
* @param y - y coordinate of point
* @param view - view object to compare
* @return true if the points are within view bounds, false otherwise
*/
private boolean isPointInsideView(float x, float y, View view) {
int location[] = new int[2];
view.getLocationOnScreen(location);
int viewX = location[0];
int viewY = location[1];
Log.i(TAG, "location x: " + location[0] + ", y: " + location[1]);
Log.i(TAG, "location xWidth: " + (viewX + view.getWidth()) + ", yHeight: " + (viewY + view.getHeight()));
// point is inside view bounds
return ((x > viewX && x < (viewX + view.getWidth())) &&
(y > viewY && y < (viewY + view.getHeight())));
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-07 05:02:13
Aby utracić fokus po dotknięciu innego widoku, oba widoki powinny być ustawione jako widok.focusableInTouchMode (true).
Ale wydaje się, że używanie focusów w trybie dotykowym nie jest zalecane. Proszę spojrzeć tutaj: http://android-developers.blogspot.com/2008/12/touch-mode.html
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-01-28 14:03:04
Mam ListView
składa się z EditText
widoki. Scenariusz mówi, że po edycji tekstu w jednym lub kilku wierszach powinniśmy kliknąć na przycisk o nazwie "Zakończ". Użyłem onFocusChanged
w widoku EditText
wewnątrz listView
, ale po kliknięciu na Zakończ dane nie są zapisywane. Problem został rozwiązany poprzez dodanie
listView.clearFocus();
Wewnątrz onClickListener
dla przycisku "Zakończ" i dane zostały zapisane pomyślnie.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-09-14 16:00:49
Po prostu zdefiniuj dwie właściwości rodzica tego EditText
jako:
android:clickable="true"
android:focusableInTouchMode="true"
Więc gdy użytkownik dotknie poza EditText
Obszar, fokus zostanie usunięty, ponieważ fokus zostanie przeniesiony do widoku nadrzędnego.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-09-05 18:34:38
For me Below things Worked -
1.dodanie android:clickable="true"
i android:focusableInTouchMode="true"
do parentLayout
z EditText
tj. android.support.design.widget.TextInputLayout
<android.support.design.widget.TextInputLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:clickable="true"
android:focusableInTouchMode="true">
<EditText
android:id="@+id/employeeID"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ems="10"
android:inputType="number"
android:hint="Employee ID"
tools:layout_editor_absoluteX="-62dp"
tools:layout_editor_absoluteY="16dp"
android:layout_marginTop="42dp"
android:layout_alignParentTop="true"
android:layout_alignParentRight="true"
android:layout_alignParentEnd="true"
android:layout_marginRight="36dp"
android:layout_marginEnd="36dp" />
</android.support.design.widget.TextInputLayout>
2.nadpisywanie dispatchTouchEvent
w klasie Activity i wstawianie hideKeyboard()
funkcji
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
if (ev.getAction() == MotionEvent.ACTION_DOWN) {
View view = getCurrentFocus();
if (view != null && view instanceof EditText) {
Rect r = new Rect();
view.getGlobalVisibleRect(r);
int rawX = (int)ev.getRawX();
int rawY = (int)ev.getRawY();
if (!r.contains(rawX, rawY)) {
view.clearFocus();
}
}
}
return super.dispatchTouchEvent(ev);
}
public void hideKeyboard(View view) {
InputMethodManager inputMethodManager =(InputMethodManager)getSystemService(Activity.INPUT_METHOD_SERVICE);
inputMethodManager.hideSoftInputFromWindow(view.getWindowToken(), 0);
}
3.dodanie setOnFocusChangeListener
dla EditText
EmployeeId.setOnFocusChangeListener(new View.OnFocusChangeListener() {
@Override
public void onFocusChange(View v, boolean hasFocus) {
if (!hasFocus) {
hideKeyboard(v);
}
}
});
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-12-09 14:49:14
Najlepszym sposobem jest użycie domyślnej metody clearFocus()
onTouchListener
prawda?
Po Prostu zadzwoń EditText.clearFocus()
. Oczyści ostrość w last EditText
.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-07-18 03:49:11
Jak zasugerował @ pcans, możesz to zrobić w swojej aktywności.
Tutaj dostajemy współrzędne dotyku i porównujemy je z granicami widoku. Jeśli dotyk jest wykonywany poza widokiem, zrób coś.
@Override
public boolean dispatchTouchEvent(MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
View yourView = (View) findViewById(R.id.view_id);
if (yourView != null && yourView.getVisibility() == View.VISIBLE) {
// touch coordinates
int touchX = (int) event.getX();
int touchY = (int) event.getY();
// get your view coordinates
final int[] viewLocation = new int[2];
yourView.getLocationOnScreen(viewLocation);
// The left coordinate of the view
int viewX1 = viewLocation[0];
// The right coordinate of the view
int viewX2 = viewLocation[0] + yourView.getWidth();
// The top coordinate of the view
int viewY1 = viewLocation[1];
// The bottom coordinate of the view
int viewY2 = viewLocation[1] + yourView.getHeight();
if (!((touchX >= viewX1 && touchX <= viewX2) && (touchY >= viewY1 && touchY <= viewY2))) {
Do what you want...
// If you don't want allow touch outside (for example, only hide keyboard or dismiss popup)
return false;
}
}
}
return super.dispatchTouchEvent(event);
}
Nie jest również konieczne sprawdzanie istnienia i widoczności widoku, jeśli układ Twojej aktywności nie zmienia się w czasie działania (np. nie dodajesz fragmentów lub nie zastępujesz/usuwasz widoków z układu). Ale jeśli chcesz zamknąć (lub zrobić coś podobnego) niestandardowe menu kontekstowe (podobnie jak w Sklepie Google Play podczas korzystania z menu przelewu elementu) konieczne jest sprawdzenie istnienia widoku. W przeciwnym razie otrzymasz NullPointerException
.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-03-22 22:39:54