0

I have one linear layout in that I have two views for an email address, one is Textview and another one is Edittext.

  1. When there is empty or not proper email address then Textview's color should change to red,
  2. if the user gets focus on edit text Textview's color should change to blue.
  3. if the user lost focus on EditText then TextView's color should change to black.

To check how to achieve with customview, I have created a custom view of its parent view which is LinearLayout which is below

CustomLinearLayout.java file

public class CustomLinearLayout extends LinearLayout {


int editTextResourceId, textViewResourceId;
EditText editText;
TextView textView;
Context mContext;

public CustomLinearLayout(Context context) {
    super(context);
    mContext = context;
}

public CustomLinearLayout(Context context, AttributeSet attrs) {
    super(context, attrs);
}

public CustomLinearLayout(Context context, AttributeSet attrs, int defStyleAttr) {
    super(context, attrs, defStyleAttr);
    mContext = context;
    inflate(context, R.layout.activity_register_account_new, this);
    TypedArray a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.MyTextView, defStyleAttr, 0);
    editTextResourceId = a.getResourceId(R.styleable.MyTextView_supportedEditText, NO_ID);
    textViewResourceId = a.getResourceId(R.styleable.MyTextView_supportedTextView, NO_ID);
    a.recycle();

}

@Override
public void onAttachedToWindow() {
    super.onAttachedToWindow();
    if (editTextResourceId != 0 && textViewResourceId != 0) {
        editText = (EditText)findViewById(editTextResourceId);
        editText.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){
                    textView.setText(s);
                }
            }
        });
    }

}

}

activity_main.xml file looks like

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:custom="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@color/grey"
    android:orientation="vertical">

    <mobile.android.view.CustomLinearLayout
            style="@style/RegisterItem"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            custom:supportedEditText="@id/edUserName"
            custom:supportedTextView="@id/tvUserName"
            android:orientation="horizontal">

            <TextView
                android:id="@+id/tvUserName"
                style="@style/RegisterTextView"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="@string/username" />

            <EditText
                android:id="@+id/edUserName"
                style="@style/RegisterEditText"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:hint="@string/hint_username"
                android:inputType="textPersonName" />

        </mobile.android.view.CustomLinearLayout>

attris.xml file

 <declare-styleable name="MyTextView">
        <attr name="supportedEditText" />
        <attr name="supportedTextView" />
    </declare-styleable>

But whenever I debug code, it shows me 0 (resource id) instead of proper id or NO_ID.

Can anyone help me how to resolve this? thanks,

Jaymin
  • 2,879
  • 3
  • 19
  • 35
Siddhpura Amit
  • 14,534
  • 16
  • 91
  • 150

2 Answers2

1

Try this code inside CustomLinearLayout.java :

private EditText findEditText() {

    int i = 0;
    for (; i < getChildCount(); i++) {
        if (getChildAt(i) instanceof EditText) {
            return (EditText) getChildAt(i);
        }

    }
    return null;
}

private TextView findTextView() {

    int i = 0;
    for (; i < getChildCount(); i++) {
        if (getChildAt(i) instanceof TextView) {
            return (TextView) getChildAt(i);
        }

    }
    return null;
}

@Override
public void onAttachedToWindow() {
    super.onAttachedToWindow();
    TextView textView = findTextView();
    EditText editText = findEditText();
    if (editText != null) {
        editText.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) {
                    if (textView != null) {
                        textView.setText(s);
                    }
                }
            }
        });
    }

}
NehaK
  • 2,639
  • 1
  • 15
  • 31
  • Do you have any idea why we can not use "a.getResourceId" Why it is returning 0? – Siddhpura Amit Feb 03 '20 at 08:05
  • It's done because it's child view but if I want to make custom EditText then is it possible same thing? – Siddhpura Amit Feb 03 '20 at 08:06
  • sorry I dont know, but I will check. This could be because as in document it says "... As a result, this function will return the resource identifier of the final resource value that was found, not necessarily the original resource that was specified by the attribute. " – NehaK Feb 03 '20 at 08:59
  • https://stackoverflow.com/questions/37628461/getresourceid-method-of-typedarray – NehaK Feb 03 '20 at 08:59
0

I built one thing like you want and I call it : EditTextComponent This is java source code for EditTextComponent:

public class EdittextComponent extends InputComponent {

protected TextView tvTitle;
protected EditText edtInput;

protected int mInputType = InputType.TYPE_CLASS_TEXT;
protected int mMaxLine = 1;
protected InputFilter[] mInputFilter;
protected boolean hasFirstChange = false;
protected TextView tvWarning;

protected int mIDLayout = R.layout.component_edittext;
protected boolean isAlwaysShowWarning = false;

@Override
public View createView() {

    LayoutInflater inflater = LayoutInflater.from(mContext);
    rootView = inflater.inflate(mIDLayout, null, false);

    tvTitle = rootView.findViewById(R.id.tv_title);
    if (Utils.validateString(mTitle)) {
        tvTitle.setText(mTitle);
    }

    edtInput = rootView.findViewById(R.id.edt_input);

    if (Utils.validateString(mPlaceHolder)) {
        edtInput.setHint(mPlaceHolder);
    }

    edtInput.setInputType(mInputType);
    edtInput.setMaxLines(mMaxLine);
    if (null != mInputFilter && mInputFilter.length > 0) {
        edtInput.setFilters(mInputFilter);
    }

    if (Utils.validateString(mValue)) {
        edtInput.setText(mValue);
    }

    if(null != mValueSelected){
        isCompleted = true;
        String value = (String) mValueSelected;
        if(Utils.validateString(value)) {
            edtInput.setText(value);
        }
    }

    edtInput.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) {
            if (null != s) {
                hasFirstChange = true;
                checkChange(s.toString().trim());
            }
        }
    });

    tvWarning = rootView.findViewById(R.id.tv_warning);


    return rootView;
}

protected void checkChange(String source) {
    if (null != mValidator) {
        boolean newState = mValidator.validate(source);
        if (isCompleted != newState) {
            notifyStateChanged(newState, source);

        }
    } else {
        if (source.length() == 0) {
            if (isCompleted) {
                notifyStateChanged(false, source);
            }
        } else if (!isCompleted) {
            notifyStateChanged(true, source);
        }
    }

    if(isCompleted){
        edtInput.setBackgroundResource(R.drawable.bg_input);
        tvWarning.setVisibility(View.INVISIBLE);
    }
    else{
        showWarning(true);
    }

}

protected void notifyStateChanged(boolean is_complete, String source) {
    isCompleted = is_complete;
    if (null != mCallBack) {
        mCallBack.onChanged(isCompleted, source);
    }
}

public void updateValue(String value){
    mValue = value;
    if(null != edtInput){
        edtInput.setText(value);
    }
    checkChange(value);
}


@Override
public boolean validate() {

    if(!isVisible){
        return true;
    }

    if (!isCompleted ) {
            showWarning(false);
    }
    return isCompleted;
}

protected void showWarning(boolean isCallByItSelf) {
    String message = "Cannot be empty";
    if (null != mValidator) {
        message = mValidator.getMessage();
    }
    if(null != tvWarning) {
        tvWarning.setText(message);
        tvWarning.setVisibility(View.VISIBLE);
    }


    if(null != edtInput) {
        edtInput.setBackgroundResource(R.drawable.bg_input_warning);
    }
}

@Override
public String getValue() {
    mValue = edtInput.getText().toString();
    return mValue;
}

@Override
public Object getData() {
    return getValue();
}

public void setInputType(int inputType) {
    mInputType = inputType;
}

public void setMaxLine(int maxLine) {
    mMaxLine = maxLine;
}

public void setInputFilter(InputFilter[] inputFilter) {
    mInputFilter = inputFilter;
}

public void setIDLayout(int IDLayout) {
    mIDLayout = IDLayout;
}

public void setAlwaysShowWarning(boolean alwaysShowWarning) {
    isAlwaysShowWarning = alwaysShowWarning;
}}

And here is component_edittext.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
                android:layout_width="match_parent"
                android:layout_height="match_parent">

    <TextView
        android:id="@+id/tv_title"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentTop="true"
        android:layout_marginStart="10dp"
        android:layout_marginTop="5dp"
        android:layout_marginEnd="10dp"

        android:text="Last name"
        android:textColor="#333333"
        android:textSize="14sp"/>

    <EditText
        android:id="@+id/edt_input"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_below="@id/tv_title"
        android:layout_marginStart="10dp"
        android:layout_marginTop="9dp"
        android:layout_marginEnd="10dp"
        android:background="@drawable/bg_input_inactive"

        android:paddingStart="19dp"
        android:paddingTop="16dp"
        android:paddingBottom="15dp"
        android:textColor="#333333"
        android:textSize="14sp"/>

    <TextView
        android:id="@+id/tv_warning"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@+id/edt_input"
        android:layout_alignParentEnd="true"
        android:layout_marginStart="10dp"
        android:layout_marginTop="5dp"
        android:layout_marginEnd="10dp"

        android:text="Cannot be empty"
        android:textColor="#DD4033"
        android:textSize="12sp"
        android:visibility="invisible"/>
</RelativeLayout>

InputComponent.java

public class InputComponent extends BaseComponent {
protected String mTitle;
protected String mValue;
protected String mKey;
protected String mPlaceHolder;
protected Validator mValidator;
protected boolean isCompleted = false;
protected InputCallBack mCallBack;
protected float mWeight = 1;

public boolean validate(){
    return false;
}

public String getTitle() {
    return mTitle;
}

public void setTitle(String title) {
    mTitle = title;
}

public String getValue() {
    return mValue;
}

public void setValue(String value) {
    mValue = value;
}

public String getKey() {
    return mKey;
}

public void setKey(String key) {
    mKey = key;
}

public void setCallBack(InputCallBack callBack) {
    mCallBack = callBack;
}

public void setPlaceHolder(String placeHolder) {
    mPlaceHolder = placeHolder;
}

public void setValidator(Validator validator) {
    mValidator = validator;
}

public float getWeight() {
    return mWeight;
}

public void setWeight(float weight) {
    mWeight = weight;
}

}

BaseComponet.java

public class BaseComponent  implements Comparable<BaseComponent>{
protected View rootView;
protected String mIDComponent;
protected Context mContext;
protected Object mValueSelected;
protected int mPosition;
protected boolean isVisible = true;

public BaseComponent() {
    mContext = Manager.getInstance().getCurrentActivity();
}

public View createView() {
    return rootView;
}

public Object getValueSelected() {
    return mValueSelected;
}

public void setValueSelected(Object valueSelected) {
    mValueSelected = valueSelected;
}

public String getIDComponent() {
    return mIDComponent;
}

public void setIDComponent(String IDComponent) {
    mIDComponent = IDComponent;
}

public void setRootView(View rootView) {
    this.rootView = rootView;
}

public int getPosition() {
    return mPosition;
}

public void setPosition(int position) {
    mPosition = position;
}

public Object getData(){
    return  null;
}

public void removeAllView(){

}

public boolean isVisible() {
    return isVisible;
}

public void setVisible(boolean visible) {
    isVisible = visible;
}

public void updateView(){
    if(null != rootView){
        if(isVisible){
            rootView.setVisibility(View.VISIBLE);
        }
        else{
            rootView.setVisibility(View.GONE);
        }
    }
}

public View getRootView() {
    return rootView;
}

@Override
public int compareTo( BaseComponent otherComponent) {
    if (null != otherComponent) {
        return (otherComponent.getPosition() - getPosition());
    }
    return 0;
}

}

And this is how you can use EditTextComponent:

        EdittextComponent lastNameComponent = new EdittextComponent();
        lastNameComponent.setPlaceHolder("Enter last name");
        lastNameComponent.setTitle("Last name");
        lastNameComponent.setKey("lastname");
        lastNameComponent.setCallBack(new InputCallBack() {
            @Override
            public void onChanged(boolean isSelected, Object data) {

                checkComplete();
            }
        });

        listInputComponents.add(lastNameComponent);

You can use this component to create email, last name, phonecode .... and add them to listInputComponents ( an array) Then you can add them to a linearlaylout like this:

    LinearLayout llBody = findViewById(...)
for(BaseComponent component: listInputComponents)
{ llBody.addView(component.createView()
}
NhatVM
  • 1,964
  • 17
  • 25