Android на слушателя изменения текста


265

У меня есть ситуация, когда есть два поля. field1и field2. Все, что я хочу сделать, это пусто, field2когда field1меняется, и наоборот. Таким образом, в конце только одно поле имеет содержимое.

field1 = (EditText)findViewById(R.id.field1);
field2 = (EditText)findViewById(R.id.field2);

field1.addTextChangedListener(new TextWatcher() {

   public void afterTextChanged(Editable s) {}

   public void beforeTextChanged(CharSequence s, int start,
     int count, int after) {
   }

   public void onTextChanged(CharSequence s, int start,
     int before, int count) {
      field2.setText("");
   }
  });

field2.addTextChangedListener(new TextWatcher() {

   public void afterTextChanged(Editable s) {}

   public void beforeTextChanged(CharSequence s, int start,
     int count, int after) {
   }

   public void onTextChanged(CharSequence s, int start,
     int before, int count) {
     field1.setText("");
   }
  });

Он отлично работает , если я прилагаю addTextChangedListenerк field1только, но когда я делаю это для обоих полей приложение падает. Очевидно, потому что они пытаются изменить друг друга на неопределенный срок. Как только field1изменения, которые он очищает, field2в этот момент field2изменяются, поэтому он очищается field1и так далее ...

Может кто-нибудь предложить какое-нибудь решение?


для новых пользователей, используйте двухстороннее связывание данных, используя наблюдаемое поле строки, потому что все решения, представленные здесь, могут привести к starting waiting blocking gc allocтакому типу ошибок, которые могут даже привести к сбою и зависанию ... так что идите на связывание данных, это безопасно и рекомендовано Google сейчас ..
Maifee Ul Asad

Ответы:


460

Вы можете добавить флажок, чтобы очистить только тогда, когда текст в поле не является пустым (т. Е. Когда длина отличается от 0).

field1.addTextChangedListener(new TextWatcher() {

   @Override
   public void afterTextChanged(Editable s) {}

   @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.length() != 0)
        field2.setText("");
   }
  });

field2.addTextChangedListener(new TextWatcher() {

   @Override
   public void afterTextChanged(Editable s) {}

   @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.length() != 0)
         field1.setText("");
   }
  });

Документация для TextWatcher здесь .

Также, пожалуйста, соблюдайте правила именования .


1
как обнаружить после того, как все поле изменилось, потому что оно обнаруживает каждый раз, когда оно изменяется, когда нажимается любая кнопка.
Рафаэль Гимарайнш

20

Я знаю, что это старо, но кто-то может когда-нибудь столкнуться с этим снова.

У меня была похожая проблема, когда я вызывал setText для EditText, а onTextChanged вызывался, когда я этого не хотел. Моим первым решением было написать некоторый код после вызова setText (), чтобы отменить ущерб, нанесенный слушателем. Но это было не очень элегантно. Проведя некоторые исследования и тестирование, я обнаружил, что использование getText (). Clear () очищает текст почти так же, как setText (""), но, поскольку он не устанавливает текст, слушатель не вызывается, так что решил мою проблему. Я переключил все мои вызовы setText ("") на getText (). Clear (), и мне больше не нужны повязки, так что, возможно, это тоже решит вашу проблему.

Попробуй это:

Field1 = (EditText)findViewById(R.id.field1);
Field2 = (EditText)findViewById(R.id.field2);

Field1.addTextChangedListener(new TextWatcher() {

   public void afterTextChanged(Editable s) {}

   public void beforeTextChanged(CharSequence s, int start,
     int count, int after) {
   }

   public void onTextChanged(CharSequence s, int start,
     int before, int count) {
      Field2.getText().clear();
   }
  });

Field2.addTextChangedListener(new TextWatcher() {

   public void afterTextChanged(Editable s) {}

   public void beforeTextChanged(CharSequence s, int start,
     int count, int after) {
   }

   public void onTextChanged(CharSequence s, int start,
     int before, int count) {
     Field1.getText().clear();
   }
  });

11

Если вы используете Kotlin для разработки Android, вы можете добавить TextChangedListener()с помощью этого кода:

myTextField.addTextChangedListener(object : TextWatcher{
        override fun afterTextChanged(s: Editable?) {}

        override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {}

        override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {}
    })

5

Немного опоздал с ответом, но вот многоразовое решение:

/**
 * An extension of TextWatcher which stops further callbacks being called as 
 * a result of a change happening within the callbacks themselves.
 */
public abstract class EditableTextWatcher implements TextWatcher {

    private boolean editing;

    @Override
    public final void beforeTextChanged(CharSequence s, int start, 
                                                    int count, int after) {
        if (editing)
            return;

        editing = true;
        try {
            beforeTextChange(s, start, count, after);
        } finally {
            editing = false;
        }
    }

    protected abstract void beforeTextChange(CharSequence s, int start, 
                                                     int count, int after);

    @Override
    public final void onTextChanged(CharSequence s, int start, 
                                                int before, int count) {
        if (editing)
            return;

        editing = true;
        try {
            onTextChange(s, start, before, count);
        } finally {
            editing = false;
        }
    }

    protected abstract void onTextChange(CharSequence s, int start, 
                                            int before, int count);

    @Override
    public final void afterTextChanged(Editable s) {
        if (editing)
            return;

        editing = true;
        try {
            afterTextChange(s);
        } finally {
            editing = false;
        }
    }

    public boolean isEditing() {
        return editing;
    }

    protected abstract void afterTextChange(Editable s);
}

Таким образом, при использовании вышеуказанного любые setText()вызовы, происходящие в TextWatcher, не приведут к повторному вызову TextWatcher:

/**
 * A setText() call in any of the callbacks below will not result in TextWatcher being 
 * called again.
 */
public class MyTextWatcher extends EditableTextWatcher {

    @Override
    protected void beforeTextChange(CharSequence s, int start, int count, int after) {
    }

    @Override
    protected void onTextChange(CharSequence s, int start, int before, int count) {
    }

    @Override
    protected void afterTextChange(Editable s) {
    }
}

5

Я также столкнулся с той же проблемой и продолжаю получать stackOverflowисключения, и я пришел со следующим решением.

edt_amnt_sent.addTextChangedListener(new TextWatcher() {    
    @Override
    public void afterTextChanged(Editable s) {
        if (skipOnChange)
            return;

        skipOnChange = true;
        try {
            //method
        } catch (NumberFormatException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } finally {
            skipOnChange = false;
        }
    }
});

edt_amnt_receive.addTextChangedListener(new TextWatcher() {

    @Override
    public void afterTextChanged(Editable s) {

        if (skipOnChange)
            return;

        skipOnChange = true;
        try {
            //method
        } catch (NumberFormatException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } finally {
            skipOnChange = false;
        }
    }
});

первоначально объявлено логическое skipOnChange = false;


1
"стек заполнен" Я думаю, что вы имеете в виду переполнение стека;)
Droid

4

Вы также можете использовать метод hasFocus ():

public void onTextChanged(CharSequence s, int start,
     int before, int count) {
     if (Field2.hasfocus()){
         Field1.setText("");
     }
   }

Протестировал это для задания колледжа, над которым я работал, чтобы преобразовать шкалы температур, когда пользователь их вводил. Работало отлично, и это намного проще.


1
Как насчет editText.setText, когда пользователь вводит в него данные? EditText имеет фокус в этом случае
Евгений Воробей

лучшее решение .
Сайед Хиссаан

3

проверьте строку перед тем, как установить другую EditTextна пустое. если Field1пусто, то зачем снова менять на ("")? так что вы можете проверить размер вашей строки с помощью s.lenght () или любого другого решения

Другой способ проверить длину строки:

String sUsername = Field1.getText().toString();
if (!sUsername.matches(""))
{
// do your job
}

2

Я написал собственное расширение для этого, очень полезно для меня. (Котлин)

Вы можете написать только так:

editText.customAfterTextChanged { editable -> 
    //You have accessed the editable object. 
}

Мое расширение:

fun EditText.customAfterTextChanged(action: (Editable?)-> Unit){
    this.addTextChangedListener(object : TextWatcher {
       override fun beforeTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {}
       override fun onTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {}
       override fun afterTextChanged(editable: Editable?) {
        action(editable)
    }
})}

2
editText.addTextChangedListener(new TextWatcher() {
            @Override
            public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {

            }
            @Override
            public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
                if (noteid != -1) {
                    MainActivity.notes.set(noteid, String.valueOf(charSequence));
                    MainActivity.arrayAdapter.notifyDataSetChanged();
                }
            }
            @Override
            public void afterTextChanged(Editable editable) {

            }
        });

в этом коде noteid - это в основном возвращаемые аргументы, которые помещаются в отступ или передаются через отступ.

  Intent intent = getIntent();
         noteid = intent.getIntExtra("noteid", -1);

код на нижней стороне в основном дополнительный код, если вы хотите понять более четко.

how to make the menu or insert the menu in our code , 
    create the  menu folder this the folder created by going into the raw
    ->rightclick->
    directory->name the folder as you wish->
    then click on the directory formed->
    then click on new file and then name for file as you wish ie the folder name file
    and now type the 2 lines code in it and see the magic.

новый код активности, названный NoteEditor.java для редактирования, мое приложение - просто приложение заметок.

package com.example.elavi.notes;
import android.content.Intent;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.text.Editable;
import android.text.TextWatcher;
import android.widget.EditText;
import android.widget.Toast;

import static android.media.CamcorderProfile.get;
public class NoteEditorActivity extends AppCompatActivity {
    EditText editText;
    int noteid;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_note_editor);
        editText = findViewById(R.id.editText);
        Intent intent = getIntent();
         noteid = intent.getIntExtra("noteid", -1);
        if (noteid != -1) {
            String text = MainActivity.notes.get(noteid);
            editText.setText(text);

           Toast.makeText(getApplicationContext(),"The arraylist content is"+MainActivity.notes.get(noteid),Toast.LENGTH_SHORT).show();
        }
        else
        {
            Toast.makeText(getApplicationContext(),"Here we go",Toast.LENGTH_SHORT).show();
            MainActivity.notes.add("");
            noteid=MainActivity.notes.size()-1;
        }
        editText.addTextChangedListener(new TextWatcher() {
            @Override
            public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {

            }
            @Override
            public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
                if (noteid != -1) {
                    MainActivity.notes.set(noteid, String.valueOf(charSequence));
                    MainActivity.arrayAdapter.notifyDataSetChanged();
                }
            }
            @Override
            public void afterTextChanged(Editable editable) {

            }
        });
    }
}

1

В Kotlin просто используйте функцию расширения KTX : (он использует TextWatcher)

yourEditText.doOnTextChanged { text, start, count, after -> 
        // action which will be invoked when the text is changing
    }


импорт core-KTX:

implementation "androidx.core:core-ktx:1.2.0"

1

Мы можем удалить TextWatcher для поля непосредственно перед редактированием его текста, а затем добавить его обратно после редактирования текста.

Объявите наблюдатели текста для field1 и field2 как отдельные переменные, чтобы дать им имя: например, для field1

private TextWatcher Field_1_Watcher = new TextWatcher() {
    @Override
    public void beforeTextChanged(CharSequence s, int start, int count, int after) {
    }

    @Override
    public void afterTextChanged(Editable s) {
    }

    @Override
    public void onTextChanged(CharSequence s, int start, int before, int count) {

    }

};

затем добавьте наблюдателя, используя его имя: field1.addTextChangedListener(Field_1_Watcher)для field1 , и field2.addTextChangedListener(Field_2_Watcher) для field2

Перед сменой поля2 текста удалите TextWatcher: field2.removeTextChangedListener(Field_2_Watcher) измените текст: field2.setText("")

затем добавьте обратно TextWatcher: field2.addTextChangedListener(Field_2_Watcher)

Сделайте то же самое для другого поля


-3

Добавить фон динамически в onCreateметоде:

getWindow().setBackgroundDrawableResource(R.drawable.background);

также удалить фон из XML.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.