여러 EditText에 단일 TextWatcher를 사용하는 방법은 무엇입니까?


답변:


190

이 문제가 발생했습니다. TextWatcherView를 인수로 취하는 내부 클래스 구현을 만들어 해결했습니다 . 그런 다음 메소드 구현에서보기를 켜서 어떤 Editable것이 오는지 확인하십시오.

선언:

private class GenericTextWatcher implements TextWatcher{

    private View view;
    private GenericTextWatcher(View view) {
        this.view = view;
    }

    public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {}
    public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {}

    public void afterTextChanged(Editable editable) {
        String text = editable.toString();
        switch(view.getId()){
            case R.id.name:
                model.setName(text);
                break;
            case R.id.email:
                model.setEmail(text);
                break;
            case R.id.phone:
                model.setPhone(text);
                break;
        }
    }
}

용법:

name = (EditText) findViewById(R.id.name);
name.setText(model.getName());
name.addTextChangedListener(new GenericTextWatcher(name));

email = (EditText) findViewById(R.id.email);
email.setText(model.getEmail());
email.addTextChangedListener(new GenericTextWatcher(email));

phone = (EditText) findViewById(R.id.phone);
phone.setText(model.getPhone());
phone.addTextChangedListener(new GenericTextWatcher(phone));

1
위 코드에서 '모델'이 무엇이며 어디에 선언해야하는지 알려 주실 수 있습니까?
YuDroid

33
이 대답은 아닙니다 Single TextWatcher for multiple EditTexts. 하나의 TextWatcher 클래스의 3 개 인스턴스입니다. 따라서 3 개의 별도 TextWatcher가 3 개의 EditText를 제어합니다.
Bobs 2012-12-08

2
제안 된 솔루션은 일부 EditText에 대해 하나의 TextWatcher가 아닙니다. 이 답변을 확인하십시오. stackoverflow.com/a/13787221/779408
Bobs

2
측면 방향을 변경할 때 데이터가 손실되지 않도록 양식 요소가 포함 된 조각과 결합하여 매력처럼 작동합니다.
Mathijs Segers

1
@breceivemail 완전히 공정하기 위해 "단일 TextWatcher"는 반드시 단일 인스턴스를 의미하지는 않으며 단일 클래스도 될 수 있습니다.
Malcolm

42

afterTextChanged 비교 편집 가능 항목 만 사용하려는 경우 :

@Override
public void afterTextChanged(Editable editable) {
    if (editable == mEditText1.getEditableText()) {
        // DO STH
    } else if (editable == mEditText2.getEditableText()) {
        // DO STH
    }
}

10
==대신을 사용 하는 경우에만 올바르게 작동합니다 .equals().
Jarett Millard 2014

2
당신은 천재입니다! 이것은 Editable에 저장된 실제 값이 아닌 포인터를 비교하는 것입니다! 예!
Burak Tamtürk 2014

3
mEditText1과 mEditText2가 같은 텍스트를 가지고 있다면 어떨까요?
Tuss

@tuss이는 대신 값의 참조를 기준으로 비교하는 이유입니다
조아킴

1
@Tomasz 어떻게 작동합니까? TextWatcher를 구현 했습니까? 그렇다면 세 가지 방법을 재정의 할 필요가 없습니까?
leonheess

10

MultiTextWatcher 구현

public class MultiTextWatcher {

    private TextWatcherWithInstance callback;

    public MultiTextWatcher setCallback(TextWatcherWithInstance callback) {
        this.callback = callback;
        return this;
    }

    public MultiTextWatcher registerEditText(final EditText editText) {
        editText.addTextChangedListener(new TextWatcher() {
            @Override
            public void beforeTextChanged(CharSequence s, int start, int count, int after) {
                callback.beforeTextChanged(editText, s, start, count, after);
            }

            @Override
            public void onTextChanged(CharSequence s, int start, int before, int count) {
                callback.onTextChanged(editText, s, start, before, count);
            }

            @Override
            public void afterTextChanged(Editable editable) {
                callback.afterTextChanged(editText, editable);
            }
        });

        return this;
    }

    interface TextWatcherWithInstance {
        void beforeTextChanged(EditText editText, CharSequence s, int start, int count, int after);

        void onTextChanged(EditText editText, CharSequence s, int start, int before, int count);

        void afterTextChanged(EditText editText, Editable editable);
    }
}

용법

    new MultiTextWatcher()
            .registerEditText(editText1)
            .registerEditText(editText2)
            .registerEditText(editText3)
            .setCallback(new TextWatcherWithInstance() {
                @Override
                public void beforeTextChanged(EditText editText, CharSequence s, int start, int count, int after) {
                    // TODO: Do some thing with editText
                }

                @Override
                public void onTextChanged(EditText editText, CharSequence s, int start, int before, int count) {
                    // TODO: Do some thing with editText
                }

                @Override
                public void afterTextChanged(EditText editText, Editable editable) {
                    // TODO: Do some thing with editText
                }
            });

왜 그들을 연결하기 위해 다른 클래스를 만들까요?! 내 말은 당신은 여전히 ​​어떤 TextView변화가 오는지 모른다는 것을 의미합니다 .
Farid

10

onTextChanged 를 사용하려면 hashCode()아래에 언급 된 비교 -

@Override
public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
    if(charSequence.hashCode() == first_edit_text.getText().hashCode()){
        // do other things 
    }

    if(charSequence.hashCode() == second_edit_text.getText().hashCode()){
       // do other things 
    }

}

또는

afterTextChanged 를 사용하려면 Editable아래에 언급 된 비교 -

@Override
public void afterTextChanged(Editable editable) {
    if (editable == first_edit_text.getEditableText()) {
        // do other things 
    } else if (editable == second_edit_text.getEditableText()) {
       // do other things 
    }
}

9

이 코드와 함께 작동합니다.

TextWatcher watcher = new TextWatcher() {
  @Override
        public void onTextChanged(CharSequence s, int start, int before, int count) {
            //YOUR CODE
        }

        @Override
        public void beforeTextChanged(CharSequence s, int start, int count, int after) {
            //YOUR CODE
        }

        @Override
        public void afterTextChanged(Editable s) {
          String outputedText = s.toString();

  mOutputText.setText(outputedText);

        }
    };

그런 다음 oncreate에 추가하십시오.

  mInputText.addTextChangedListener(watcher);
        e2.addTextChangedListener(watcher);
        e3.addTextChangedListener(watcher);
        e4.addTextChangedListener(watcher);

그렇다면 mOutputText는 어디에서 왔습니까?
Kimi Chiu

5

나는 이것이 오래된 문제이며 올바른 결정이 있음을 알고 있습니다. 나는 그들 자신을 쓸 것이다, 어쩌면 누군가를 도울 것입니다.

N EditText가 있고 모든 필드가 채워지면 버튼을 표시하려는 고전적인 예제를 에뮬레이트합니다. 이 예는 특히 각각에 대해 유효성 검사기를 추가로 사용하는 경우에 의미가 있습니다.

나는 문제와 관련하여 예제를 만들었지 만 어떤 세트도 할 수 있습니다.

MultiEditText.class

public class MultiEditText extends AppCompatActivity{

EditText ed_1, ed_2, ed_3;
Button btn_ok;

@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.multi_edit_text);

    ed_1 = (EditText) findViewById(R.id.ed_1);
    ed_2 = (EditText) findViewById(R.id.ed_2);
    ed_3 = (EditText) findViewById(R.id.ed_3);
    btn_ok = (Button) findViewById(R.id.btn_ok);
    btn_ok.setEnabled(false);

    //if want more here can cycle interface List

     EditText[] edList = {ed_1, ed_2, ed_3};
     CustomTextWatcher textWatcher = new CustomTextWatcher(edList, btn_ok);
     for (EditText editText : edList) editText.addTextChangedListener(textWatcher);

    }
}

이제 아주 간단 해 보입니다.

CustomTextWatcher.class

public class CustomTextWatcher implements TextWatcher {

View v;
EditText[] edList;

public CustomTextWatcher(EditText[] edList, Button v) {
    this.v = v;
    this.edList = edList;
}

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

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

@Override
public void afterTextChanged(Editable s) {
    for (EditText editText : edList) {
        if (editText.getText().toString().trim().length() <= 0) {
            v.setEnabled(false);
            break;
        }
        else v.setEnabled(true);
    }
  }
}

레이아웃을 추가하여 시간 낭비하지 않도록

multi_edit_text.xml

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="16dp">

<EditText
    android:id="@+id/ed_1"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_alignParentTop="true"
    android:layout_centerHorizontal="true"
    android:layout_marginTop="8dp" />

<EditText
    android:id="@+id/ed_2"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_below="@+id/ed_1"
    android:layout_centerHorizontal="true"
    android:layout_marginTop="8dp" />

<EditText
    android:id="@+id/ed_3"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_below="@+id/ed_2"
    android:layout_centerHorizontal="true"
    android:layout_marginTop="8dp" />

<Button
    android:id="@+id/btn_ok"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_below="@+id/ed_3"
    android:layout_centerHorizontal="true"
    android:layout_marginTop="8dp"
    android:text="OK" />
</RelativeLayout>

5

클래스가 Activity에서 상속하고 TextWatcher를 구현하도록합니다.

그런 다음 다형성의 마법을 통해 이벤트를 구독하기 만하면됩니다.

이것은 TextEdit가 무엇을 변경했는지 알려주지 않지만 이것과 Sky Kelsey 의 대답을 함께 사용하면 멋지게 정렬 할 수 있습니다.

public YourActivity extends Activity implements TextWatcher {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_YourActivity);

        //Subscribe to the events
        EditText txt1 = (EditText) findViewById(R.id.txt1);
        txt1.addTextChangedListener(this);

        EditText txt2 = (EditText) findViewById(R.id.txt2);
        txt2.addTextChangedListener(this);
    }

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

            EditText txt1 = (EditText) findViewById(R.id.txt1);
            EditText txt2 = (EditText) findViewById(R.id.txt2);
            // You probably only want the text value from the EditText. But you get the idea. 
                doStuff(txt1,txt2);
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.calc, menu);
        return true;
    }

    @Override
    public void afterTextChanged(Editable s) {
        // TODO Auto-generated method stub
    }

    @Override
    public void beforeTextChanged(CharSequence s, int start, int count, int after) {
        // TODO Auto-generated method stub
    }
}

3
TextWatcher watcher = 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) {
    }

    @Override
    public void afterTextChanged(Editable editable) {
    }
};

그때:

editText1.addTextChangedListener(watcher);
editText2.addTextChangedListener(watcher);
editText3.addTextChangedListener(watcher);

2
(Whining post warning) 그는 아마도 모든 컨트롤에 대해 매우 유사한 유효성 검사 코드를 가지고 있으며 3 번 복사하여 붙여넣고 싶지 않습니다. :) 전에 그것을 쳤는데, 왜 그들이 onClickListener에 대한 클릭을 생성 한 컨트롤을 보낼 수 있습니까? 내가 생각할 수있는 유일한 해결 방법은 동일한 절차를 호출하지만 각각의 편집 컨트롤에 대한 포인터가있는 3 개의 TextWatcher를 만드는 것입니다.
Torp

1
@Torp, @bie :이 답변이 흥미로울 수 있습니다. stackoverflow.com/questions/4283062/… 여기에 명시된 문제가 정확히 해결되는지 확실하지 않지만, 표시된대로 CustomTextWatcher가 자동으로 다른 함수를 호출하도록 할 수 있습니다. 편집 가능.
Kevin Coppock 2011

3
public class MainActivity extends AppCompatActivity{
    EditText value1, value2;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        //instantiate EditText controls
        value1 = (EditText)findViewById(R.id.txtValue1);
        value2 = (EditText)findViewById(R.id.txtValue2);

        //set up text changed listener
        value1.addTextChangedListener(new TextChange(value1));               
        value2.addTextChangedListener(new TextChange(value2));                       

        //inner class
        private class TextChange implements TextWatcher {

             View view;
             private TextChange (View v) {
                 view = v;
             }

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

             }


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

                 switch (view.getId()) {
                     case R.id.txtValue1:
                         //insert your TextChangedListener codes here
                         break;

                     case R.id.txtValue2:
                         //insert your TextChangedListener codes here
                         break;
                 }
             }   
         }
     }
}

3

이것이 kotlin에 대한 나의 해결책입니다. 참조 평등 (===)을 사용하여 동일한 객체를 확인하면 완벽하게 작동합니다.

val mTextWatcher = object : TextWatcher {
        override fun afterTextChanged(et: Editable?) {

            when {
                et === et1.editableText -> {
                    Toast.makeText(this@MainActivity, "EditText 1", Toast.LENGTH_LONG).show()
                }
                et === et2.editableText -> {
                    Toast.makeText(this@MainActivity, "EditText 2", Toast.LENGTH_LONG).show()
                }

            }
        }

        override fun beforeTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {
        }
        override fun onTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {
        }
    }
    et1.addTextChangedListener(mTextWatcher)
    et2.addTextChangedListener(mTextWatcher)

0

이 질문이 오래되었다는 것을 알고 있지만 Kotlin에서 내 솔루션 중 하나를 공유하고 싶습니다. 내 솔루션은 @Shwarz Andrei의 답변을 개선 한 것입니다. 내 이유는 더 많은 물건 / 객체를 조작하고 싶다면 어떨까요?

list of EditTextsa Button매개 변수 를 모두 전달하는 대신 list of editText. 그런 다음 사용자 정의 클래스 내에서 다음과 같은 람다를 구현합니다.

var hasFilled:((Boolean)->Unit)? = null 

그런 다음 내부에 설정하거나 올릴 것입니다. afterTextChanged

override fun afterTextChanged(p0: Editable?) {
       for (edit in _editTextList) {
           if (edit?.text.toString().trim().isEmpty()) {
                 hasFilled?.invoke(false) //<-- here 
               break
           } else {
               hasFilled?.invoke(true) //<--- here 
           }
       }
   }

따라서 매번 람다가 호출되는 일부 EditText가 변경됩니다.

        val editTexts = listOf(emailEditText,passwordEditText) // your list of editText
        val textWatcher = customTextWatcher(editTexts) // initialize your custom object 
        editTexts.forEach { it -> it?.addTextChangedListener(textWatcher) } // each editText would listen for changes 


        textWatcher.hasFilled = { value ->  // now you have access to your lambda 
            if (value != true)  {
               // change the state of the button to unable 
              // do other things 
            } else {
              // change the state of the button to enable 
              // do other things 
            }
        }

0

내가 한 방법은 다음과 같습니다.

EditText의 ArrayList를 만든 다음 for 루프를 사용하여 모든 EditText에 대해 TextWatcher를 적용하고, 모든 editText에 대해 하나의 동작이있는 경우 거기에 적용하고, 특정 editText에 대한 특정 동작을 적용하면 if를 사용할 수 있습니다. 문을 선택하여 개별 editText에 적용합니다.

내 코드는 다음과 같습니다.

ArrayList<EditText> editTexts = new ArrayList<>(); // Container list

editText1 = (EditText) findViewById(R.id.editText1);
editText2 = (EditText) findViewById(R.id.editText2);
editText3 = (EditText) findViewById(R.id.editText3);

editTexts.add(editText1); // editTexts[0]
editTexts.add(editText2); // editTexts[1]
editTexts.add(editText3); // editTexts[2]

for (final EditText editText : editTexts) { //need to be final for custom behaviors 
    editText.addTextChangedListener(new TextWatcher() {
        @Override
        public void beforeTextChanged(CharSequence s, int start, int count, int after) {

        }

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

        }

        @Override
        public void afterTextChanged(Editable s) {
            //Apply general behavior for all editTexts

            if (editText == editTexts.get(1)) {
                //Apply custom behavior just for this editText                           
            }
        }
    });

}

도움이 되었기를 바랍니다


답변 주셔서 감사합니다.하지만 이것이 정말 유일한 방법인가요? 내 말 onTextChanged은 EditText에서 와 같이 일반적인 것에 대해 다소 복잡해 보입니다 . onFocusChange여러 위젯에 대한를 추가하는 것은 메서드 호출과 함께 보낸 사람 개체를 전달했기 때문에 훨씬 간단합니다. 그런 다음 어떤 개체가 호출을 트리거했는지 확인하고 거기에서 처리 할 수 ​​있습니다.
BdR
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.