0

I am able to add Textwatcher listener for dynamically created Edittext so basically I'll check the first editext ontextchanged if there is any value create another edittext and so on.How can check which edittext is called in the listener.

I have checked couple of links how-to-use-single-textwatcher-for-multiple-edittexts but the Ids are fixed in this case.

Code:

 public class MainActivity extends Activity {

    EditText textIn;
    Button buttonAdd;
    LinearLayout container;
    Button buttonShowAll;
    static int count = 0;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        container = (LinearLayout) findViewById(R.id.container);
        LayoutInflater layoutInflater = (LayoutInflater) getBaseContext()
                .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        final View addView = layoutInflater.inflate(R.layout.row, null);
        final EditText textOut = (EditText) addView.findViewById(R.id.textout);
        textOut.addTextChangedListener(watcher);

        container.addView(addView);

    }

    TextWatcher watcher = new TextWatcher() {

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

            // addView();

        }

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

        }

        @Override
        public void afterTextChanged(Editable s) {
            // TODO Auto-generated method stub
            /*
             * int childcount = container.getChildCount(); for (int i=0; i <
             * childcount; i++){ View v = container.getChildAt(i);
             * 
             * if(i == (childcount -1)){ Toast.makeText(getApplicationContext(),
             * "Last count"+childcount, Toast.LENGTH_SHORT).show(); addView(); }
             * }
             */
        }
    };

    public void addView() {
        LayoutInflater layoutInflater = (LayoutInflater) getBaseContext()
                .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        final View addView = layoutInflater.inflate(R.layout.row, null);
        final EditText textOut = (EditText) addView.findViewById(R.id.textout);
        textOut.addTextChangedListener(watcher);
        addView.setTag(count++);
        container.addView(addView);
    }

}
Community
  • 1
  • 1
Srikanth Roopa
  • 1,782
  • 2
  • 13
  • 19
  • One thing you could do is register an OnGlobalFocusChangeListener to keep track of the View with the current focus. Then, when your TextWatcher callbacks are called, you should be able to assume it is coming from the current focused view. – Michael Krause Feb 23 '15 at 17:46
  • ya i tried that its working but i need to do some operation based on text changed so when particular edittext has no value i need to delete that view. – Srikanth Roopa Feb 23 '15 at 17:48
  • If you use `textOut = new EditText(context);` instead of `textOut = (EditText) addView.findViewById(R.id.textout);` and then set properties on `txtOut` programmatically, you can use my answer. – Hamidreza Samadi Feb 23 '15 at 19:01

2 Answers2

1

If I understood correctly, the whole purpose of using a TextWatcher here is to dynamically add another EditText each time the previous was filled with text. For this purpose I'd simply remove the single TextWatcher instance when creating another one and add it to the new EditText. The solution uses a single TextWatcher, but differs from your request that within the single TextWatcher is only attached to one EditText at a time. Check my sample code (untested).


EDIT code below was edited to also remove unused EditTexts on focus change. The reason to not remove Views on text change is to give the user the opportunity to change previous entered input without destroying the row. Also note that the last row is never deleted. Depending on the expected number of rows, a ListView might be a better choice.

public class MainActivity extends Activity {

    private LinearLayout mContainer;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mContainer = (LinearLayout) findViewById(R.id.container);
        ReusableTextWatcher reusableTextWatcher = new ReusableTextWatcher() {
            @Override
            public void afterTextChanged(Editable s) {
                if (s.length() > 0) addView(this);
            }

            @Override
            public void onListenerRemoved(final View parentView, final EditText editText) {
                editText.setOnFocusChangeListener(new View.OnFocusChangeListener() {
                    @Override
                    public void onFocusChange(View v, boolean hasFocus) {
                        if (!hasFocus && editText.getText().length() == 0) mContainer.removeView(parentView);
                    }
                });
            }
        };
        addView(reusableTextWatcher);
    }

    private void addView(ReusableTextWatcher reusableTextWatcher) {
        final View addView = LayoutInflater.from(this).inflate(R.layout.row, mContainer);
        reusableTextWatcher.listenTo(addView, R.id.textout);
        mContainer.addView(addView);
    }

    private static abstract class ReusableTextWatcher implements TextWatcher {

        private View mParentView;
        private EditText mCurrentEditText;

        public void listenTo(View parentView, int editTextViewId) {
            if (mCurrentEditText != null) {
                mCurrentEditText.removeTextChangedListener(this);
                onListenerRemoved(mParentView, mCurrentEditText);
            }
            mParentView = parentView;
            mCurrentEditText = (EditText) parentView.findViewById(editTextViewId);
            mCurrentEditText.addTextChangedListener(this);
        }

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

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

        public abstract void onListenerRemoved(View parentView, EditText editText);

    }

}
Suau
  • 4,628
  • 22
  • 28
  • ya I am working something similar to that(replicating a long form).How can i check the previous editext ? – Srikanth Roopa Feb 23 '15 at 18:36
  • what you mean with check ? finding it ? It would be easier if you could tell us what needs to be achieved. – Suau Feb 23 '15 at 18:39
  • I am trying to replicate a long form like when user enters first text second will enabled n so on and when particular row is empty it will deleted. – Srikanth Roopa Feb 23 '15 at 18:45
  • This is very dependent on the "rules" for deleting and adding new rows, as for example if using a TextWatcher to detect the empty field and then removing it, would mean this would even happen when correcting text in previous fields. Did you think about the exact conditions when a field is added and when a field is removed ? And how many fields do you expect ? – Suau Feb 23 '15 at 19:05
  • initially single editext will displayed and when user enters some value a new editext will be created and so on and suppose if a particular edittext value is empty that particular view will be deleted. – Srikanth Roopa Feb 23 '15 at 19:12
  • @srikanthgr I've edited my answer to also remove unused EditTexts using a `OnFocusChangeListener` as I can only assume that is what you meant with "when a edittext value is empty". If you mean however deleting the view the very moment the last character was deleted, then simply use a TextWatcher instead. – Suau Feb 24 '15 at 04:02
  • In general I don't see the purpose of using a "single TextWatcher for several EditTexts", except saving a bit memory maybe, but then View recycling would be so much more of a memory saver. – Suau Feb 24 '15 at 04:06
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/71548/discussion-between-srikanth-gr-and-su-au-hwang). – Srikanth Roopa Feb 24 '15 at 05:05
0

Create a linear layout to hold all the views. When the text changes, simply count for the number of views having empty editTexts. If there are no empty editTexts, create a new editText and same the listener to it. If there are multiple editTexts, delete extra editTexts.

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

            int numberOfViews = 0;
            Log.d(TAG, "onTextChanged: "+s.toString());
            for(int i = llNumbers.getChildCount(); --i>=0;)
            {
                View view = llNumbers.getChildAt(i);
                EditText et_num = view.findViewById(R.id.et_data);
                String s1 = et_num.getText().toString();
                if(s1.length() == 0)
                    numberOfViews++;

                if(numberOfViews == 2) {
                    llNumbers.removeViewAt(i);
                    numberOfViews--;
                }
            }

            if(numberOfViews == 0)
                createNumView(new Number("", 2));
        }

        @Override
        public void afterTextChanged(Editable s) {

        }
 };

void createNumView(Number n)
{
    String number = n.number;
    int type[] = new int[]{n.numberType};

    View view = LayoutInflater.from(AddContactActivity.this).inflate(R.layout.data_per_contact, llNumbers, false);
    EditText et_num = view.findViewById(R.id.et_data);
    et_num.setText(number);
    et_num.setHint("Number");
    et_num.addTextChangedListener(numTextWatcher);
}
kanak
  • 1
  • 1