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 зосередився на цій справі
Євгеній Воробей

найкраще рішення.
Syed Hissaan

3

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

ще один спосіб перевірити довжину String - це:

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 для поля безпосередньо перед редагуванням його тексту, а потім додати його після редагування тексту.

Declare Текст Watchers для обох 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

Перш ніж змінювати текст field2, видаліть 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.