Android trên Trình nghe thay đổi văn bản


265

Tôi có một tình huống, nơi có hai lĩnh vực. field1field2. Tất cả những gì tôi muốn làm là trống rỗng field2khi field1được thay đổi và ngược lại. Vì vậy, cuối cùng chỉ có một lĩnh vực có nội dung trên đó.

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

Nó hoạt động tốt nếu tôi đính kèm addTextChangedListenerđể field1chỉ, nhưng khi tôi làm điều đó cho cả hai lĩnh vực ứng dụng bị treo. Rõ ràng là vì họ cố gắng thay đổi nhau vô thời hạn. Khi field1thay đổi, nó sẽ bị xóa field2tại thời điểm field2này và nó sẽ bị xóa field1và cứ thế ...

Ai đó có thể đề nghị bất kỳ giải pháp?


Đối với người dùng mới, sử dụng liên kết dữ liệu hai chiều bằng cách sử dụng trường chuỗi có thể quan sát được, vì tất cả các giải pháp được cung cấp ở đây có thể tạo ra starting waiting blocking gc allocloại lỗi này, thậm chí có thể dẫn đến sự cố và treo .. vì vậy, hãy liên kết dữ liệu, đó là an toàn và được đề xuất bởi google ngay bây giờ ..
Maifee Ul Asad

Câu trả lời:


460

Bạn có thể thêm một kiểm tra để chỉ xóa khi văn bản trong trường không trống (tức là khi độ dài khác 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("");
   }
  });

Tài liệu cho TextWatcher đây .

Ngoài ra xin vui lòng tôn trọng quy ước đặt tên .


1
Làm thế nào để phát hiện sau khi tất cả các trường thay đổi, bởi vì, nó phát hiện mỗi khi nó thay đổi, khi nhấn bất kỳ nút nào.
Rafael Guimarães

20

Tôi biết điều này đã cũ nhưng ai đó có thể gặp lại điều này một ngày nào đó.

Tôi gặp vấn đề tương tự khi tôi gọi setText trên EditText và onTextChanged sẽ được gọi khi tôi không muốn. Giải pháp đầu tiên của tôi là viết một số mã sau khi gọi setText () để hoàn tác các thiệt hại do người nghe gây ra. Nhưng đó không phải là rất thanh lịch. Sau khi thực hiện một số nghiên cứu và thử nghiệm, tôi phát hiện ra rằng việc sử dụng getText (). Clear () sẽ xóa văn bản theo cách tương tự như setText (""), nhưng vì nó không đặt văn bản mà người nghe không gọi, vì vậy giải quyết vấn đề của tôi Tôi đã chuyển tất cả các lệnh gọi setText ("") của mình sang getText (). Clear () và tôi không cần băng bó nữa, vì vậy có lẽ điều đó cũng sẽ giải quyết vấn đề của bạn.

Thử cái này:

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

Nếu bạn đang sử dụng Kotlin để phát triển Android thì bạn có thể thêm TextChangedListener()bằng mã này:

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

Một câu trả lời muộn, nhưng đây là một giải pháp có thể sử dụng lại:

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

Vì vậy, khi sử dụng ở trên, mọi setText()cuộc gọi xảy ra trong TextWatcher sẽ không dẫn đến việc TextWatcher được gọi lại:

/**
 * 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

Tôi cũng đã phải đối mặt với cùng một vấn đề và tiếp tục có stackOverflowngoại lệ, và tôi đi kèm với giải pháp sau đây.

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

khai báo ban đầu boolean SkipOnChange = false;


1
"stack full" Tôi nghĩ bạn có nghĩa là Stack Overflow;)
Một Droid

4

Bạn cũng có thể sử dụng phương thức hasF Focus ():

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

Đã thử nghiệm điều này cho một bài tập đại học mà tôi đang thực hiện để chuyển đổi thang đo nhiệt độ khi người dùng nhập chúng vào. Hoạt động hoàn hảo và đơn giản hơn.


1
Điều gì về editText.setText khi người dùng nhập vào nó? EditText đã tập trung trong trường hợp này
Evgenii Vorobei

giải pháp tốt nhất .
Syed Hissaan

3

kiểm tra String trước khi đặt cái khác EditTextthành trống. nếu Field1trống thì tại sao cần phải đổi lại thành ("")? để bạn có thể kiểm tra kích thước Chuỗi của bạn bằng s.lenght () hoặc bất kỳ giải pháp nào khác

một cách khác mà bạn có thể kiểm tra chiều dài của String là:

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

2

Tôi đã viết phần mở rộng của riêng tôi cho việc này, rất hữu ích cho tôi. (Kotlin)

Bạn chỉ có thể viết như thế:

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

Gia hạn của tôi:

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

            }
        });

trong mã này lưu ý về cơ bản là các đối số được lấy lại đang được đưa vào thụt lề hoặc chuyển qua thụt lề.

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

mã về nhược điểm về cơ bản là mã bổ sung, nếu bạn muốn hiểu rõ hơn.

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.

mã hoạt động mới có tên là NoteEditor.java cho mục đích chỉnh sửa, ứng dụng của tôi là cơ sở cho ứng dụng ghi chú.

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

Trong Kotlin chỉ cần sử dụng chức năng mở rộng KTX : (Nó sử dụng TextWatcher)

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


nhập khẩu core-KTX:

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

1

Chúng ta có thể xóa TextWatcher cho một trường ngay trước khi chỉnh sửa văn bản của nó sau đó thêm lại sau khi chỉnh sửa văn bản.

Khai báo Trình theo dõi văn bản cho cả trường1trường2 dưới dạng các biến riêng biệt để đặt tên cho chúng: vd cho trường1

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

    }

};

sau đó thêm trình theo dõi bằng tên của nó: field1.addTextChangedListener(Field_1_Watcher)cho trường1field2.addTextChangedListener(Field_2_Watcher)cho trường2

Trước khi thay đổi văn bản field2, hãy xóa TextWatcher: field2.removeTextChangedListener(Field_2_Watcher) thay đổi văn bản: field2.setText("")

sau đó thêm TextWatcher trở lại: field2.addTextChangedListener(Field_2_Watcher)

Làm tương tự cho các lĩnh vực khác


-3

Thêm nền động trong onCreatephương thức:

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

cũng xóa nền khỏi XML.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.