Android na odbiorniku zmiany tekstu

265

Mam sytuację, w której są dwa pola. field1a field2. Wszystko, co chcę zrobić, to puste field2po field1zmianie i odwrotnie. Na koniec tylko jedno pole zawiera treść.

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("");
   }
  });

To działa dobrze, jeśli mogę dołączyć addTextChangedListenerdo field1tylko, ale kiedy robię to dla obu polach aplikacja wywala. Oczywiście, ponieważ próbują się zmieniać w nieskończoność. Gdy field1zmiany zostaną wyczyszczone, field2w tym momencie field2zostanie zmienione, aby usunąć field1i tak dalej ...

Czy ktoś może zaproponować jakieś rozwiązanie?

inrob
źródło
dla nowych użytkowników, wybierz dwukierunkowe wiązanie danych za pomocą obserwowalnego pola ciągu, ponieważ wszystkie dostarczone tutaj rozwiązania mogą powodować starting waiting blocking gc alloctego rodzaju błędy, które mogą nawet prowadzić do awarii i zawieszenia. więc przejdź do wiązania danych, to jest bezpieczne i zalecane przez Google teraz ..
Maifee Ul Asad

Odpowiedzi:

460

Możesz dodać zaznaczenie, aby wyczyścić tylko wtedy, gdy tekst w polu nie jest pusty (tj. Gdy długość jest różna od 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("");
   }
  });

Dokumentacja TextWatcher tutaj .

Przestrzegaj również konwencji nazewnictwa .

użytkownik2336315
źródło
1
jak wykryć po zmianie wszystkich pól, ponieważ wykrywa za każdym razem, gdy zmienia się, po naciśnięciu dowolnego przycisku.
Rafael Guimarães
20

Wiem, że to stare, ale ktoś może kiedyś się z tym spotkać.

Miałem podobny problem, gdy wywoływałem setText na EditText, a onTextChanged był wywoływany, gdy tego nie chciałem. Moim pierwszym rozwiązaniem było napisanie kodu po wywołaniu setText () w celu cofnięcia szkód wyrządzonych przez nasłuchiwanie. Ale to nie było zbyt eleganckie. Po przeprowadzeniu pewnych badań i testów odkryłem, że użycie getText (). Clear () czyści tekst w podobny sposób jak setText („”), ale ponieważ nie ustawia tekstu, słuchacz nie jest wywoływany, więc rozwiązał mój problem. Zamieniłem wszystkie moje wywołania setText („”) na getText (). Clear () i nie potrzebowałem już bandaży, więc może to również rozwiąże twój problem.

Spróbuj tego:

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();
   }
  });
RTHarston
źródło
11

Jeśli korzystasz z programowania Kotlin dla Androida, możesz dodać TextChangedListener()ten kod:

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) {}
    })
iHulk
źródło
5

Trochę za późno na odpowiedź, ale oto rozwiązanie wielokrotnego użytku:

/**
 * 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);
}

Tak więc, gdy powyższe zostanie użyte, wszelkie setText()wywołania zachodzące w TextWatcherze nie spowodują ponownego wywołania TextWatchera:

/**
 * 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) {
    }
}
Eurig Jones
źródło
5

Napotkałem również ten sam problem i wciąż otrzymuję stackOverflowwyjątki, i przychodzę z następującym rozwiązaniem.

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;
        }
    }
});

zadeklarowane początkowo boolean skipOnChange = false;

Sumit
źródło
1
„stos pełny” Myślę, że masz na myśli Przepełnienie stosu;)
A Droid
4

Możesz także użyć metody hasFocus ():

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

Przetestowałem to na studiach, nad którymi pracowałem, aby przekonwertować skale temperatur, gdy użytkownik je wpisał. Działało idealnie i jest o wiele prostsze.

renam
źródło
1
Co z editText.setText, gdy użytkownik wprowadza w nim dane? EditText skupia się w tym przypadku
Evgenii Vorobei,
najlepsze rozwiązanie.
Syed Hissaan
3

sprawdź String, zanim ustawisz inny EditTextna pusty. jeśli Field1jest pusty, to dlaczego trzeba ponownie zmienić na („”)? dzięki czemu możesz sprawdzić rozmiar swojego ciągu za pomocą s.lenght () lub dowolnego innego rozwiązania

innym sposobem na sprawdzenie długości String jest:

String sUsername = Field1.getText().toString();
if (!sUsername.matches(""))
{
// do your job
}
Shayan Pourvatan
źródło
2

Napisałem do tego własne rozszerzenie, bardzo dla mnie pomocne. (Kotlin)

Możesz pisać tylko tak:

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

Moje rozszerzenie:

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)
    }
})}
Burak Dizlek
źródło
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) {

            }
        });

w tym kodzie noteid to w zasadzie argumenty wzięte z powrotem, które są wstawiane do wcięcia lub przekazywane przez wcięcie.

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

kod wadą jest w zasadzie dodatkowy kod, jeśli chcesz lepiej zrozumieć.

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.

nowy kod aktywności o nazwie NoteEditor.java do celów edycji, moja aplikacja jest w zasadzie aplikacją do notatek.

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) {

            }
        });
    }
}
Lavish Garg
źródło
1

W Kotlin wystarczy użyć funkcji rozszerzenia KTX : (Używa TextWatcher)

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


import core-KTX:

implementation "androidx.core:core-ktx:1.2.0"
Francis
źródło
1

Możemy usunąć TextWatcher dla pola tuż przed edycją jego tekstu, a następnie dodać go z powrotem po edycji tekstu.

Zadeklaruj obserwatorów tekstu zarówno dla pola1, jak i pola2 jako osobne zmienne, aby nadać im nazwę: np. Dla pola1

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) {

    }

};

następnie dodaj obserwatora, używając jego nazwy: field1.addTextChangedListener(Field_1_Watcher) dla pola 1 i field2.addTextChangedListener(Field_2_Watcher)dla pola 2

Przed zmianą pole2 tekst usunąć TextWatcher: field2.removeTextChangedListener(Field_2_Watcher) zmienić tekst: field2.setText("")

następnie dodaj TextWatcher z powrotem: field2.addTextChangedListener(Field_2_Watcher)

Zrób to samo dla drugiego pola

Keith Kiarie
źródło
-3

Dodaj dynamicznie tło w onCreatemetodzie:

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

usuń także tło z XML.

Ankit Kumar
źródło