AppCompatEditText.getpParent() inside TextInputLay

2019-02-06 12:48发布

问题:

I am creating simple AppCompatEditText adding OnFocusChangeListener and putting it in the simple TextInputLayout.

When AppCompatEditText loosing focus it's content should be validate by isValidParam method.

It worked till yesterday, when I used rev.23.0.3 But now, when I used rev.24.0.2, it gives error as below on the 1st row of isValidParam method.

java.lang.ClassCastException: android.widget.FrameLayout cannot be cast to android.support.design.widget.TextInputLayout

I checked in debugging mode. AppCompatEditText.getpParent() really returns Framelayout instead TextInputLayout.

LinearLayout llParams = new LinearLayout(context);
llParams.setOrientation(LinearLayout.VERTICAL);

// Create label for param
final TextInputLayout tilParam = new TextInputLayout(context);
// Add label into layout
llParams.addView(tilParam);


// Create Editor for param
final AppCompatEditText etParam = new AppCompatEditText(context);

edParam.setOnFocusChangeListener(new View.OnFocusChangeListener() {
    @Override
    public void onFocusChange(View v, boolean hasFocus) {
        if (!hasFocus)
            if (isValidParam(etParam)) {
                do some thing;
            } else {
                do other thing;
            }
    }
});

tilParam.addView(etParam);


// validation method
boolean isValidParam(AppCompatEditText editText) {
    TextInputLayout til = (TextInputLayout) editText.getParent();

    String text = editText.getText().toString().trim();

    if (!text.equls("some criteria") {
        till.setError("Error text")
        return false;
    }

    return true;
}

回答1:

getParentForAccessibility() worked for me



回答2:

Update:
Use the widget TextInputEditText instead of EditText inside a TextInputLayout.

old answer

TextInputLayout textInputLayout = (TextInputLayout) editText.getParent().getParent();

That seems to work as a quick fix. Far from ideal.



回答3:

Just extracts from Android official documents:

 <android.support.design.widget.TextInputLayout
     android:layout_width="match_parent"
     android:layout_height="wrap_content">

     <android.support.design.widget.TextInputEditText
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
         android:hint="@string/form_username"/>

 </android.support.design.widget.TextInputLayout>

Note: The actual view hierarchy present under TextInputLayout is NOT guaranteed to match the view hierarchy as written in XML. As a result, calls to getParent() on children of the TextInputLayout -- such as an TextInputEditText -- may not return the TextInputLayout itself, but rather an intermediate View. If you need to access a View directly, set an android:id and use findViewById(int).

Therefore, to resolve the issue you have to turn to findViewById instead of getParent due to an extra layout in between introduced in version 24.



回答4:

You can check if EditText is inside TextInputLayout using following method:

public static <ParentClass> ParentClass getFirstParent(View view, Class<ParentClass> parentClass) {
    if (view.getParent() instanceof View) {

        if (parentClass.isInstance(view.getParent())) {
            return (ParentClass) view.getParent();
        } else {
            return getFirstParent((View) view.getParent(), parentClass);
        }

    } else {
        return null;
    }

}

Example of use:

TextInputLayout textInputLayout = getFirstParent(editText, TextInputLayout.class)


回答5:

You can check the code of the TextInputLayout v24.x.x.
Now it works with a FrameLayout.

@Override
public void addView(View child, int index, final ViewGroup.LayoutParams params) {
    if (child instanceof EditText) {
        mInputFrame.addView(child, new FrameLayout.LayoutParams(params));
        //...
     } else {
        // Carry on adding the View...
        super.addView(child, index, params);
    }
}

where mInputFrame is a FrameLayout.
It is the reason of your issue (the parent is a FrameLayout).

Just pass the tilParam as parameter , instead of using getParent() if you need to use it.