Search code examples
androidandroid-edittextandroid-custom-view

How to check which editext textwatcher listener is called in dynamically created edittext


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

}

Solution

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