AppCompatEditText.getpParent() внутри TextInputLayout возвращает FrameLayout

Я создаю простой AppCompatEditText, добавляя OnFocusChangeListener и помещая его в простой TextInputLayout.

Когда AppCompatEditText теряет фокус, контент должен проверяться методом isValidParam.

Он работал до вчерашнего дня, когда я использовал rev.23.0.3 Но теперь, когда я использовал rev.24.0.2, он дает ошибку, как показано ниже в первой строке метода isValidParam.

java.lang.ClassCastException: android.widget.FrameLayout не может быть cast to android.support.design.widget.TextInputLayout

Я проверил в режиме отладки. AppCompatEditText.getpParent() действительно возвращает Framelayout вместо 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() работал у меня

Ответ 2

Update:
Используйте виджет TextInputEditText вместо EditText внутри TextInputLayout.

старый ответ

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

Это похоже на быстрое исправление. Далеко от идеала.

Ответ 3

Вы можете проверить, находится ли EditText внутри TextInputLayout, используя следующий метод:

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

}

Пример использования:

TextInputLayout textInputLayout = getFirstParent(editText, TextInputLayout.class)

Ответ 4

Просто извлекает из официальные документы Android:

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

Примечание. Фактическая иерархия представлений, присутствующая в TextInputLayout, НЕ гарантированно соответствует иерархии представлений, как написано в XML. В результате, вызовы getParent() для дочерних элементов TextInputLayout - например, TextInputEditText - может не возвращать сам TextInputLayout, но скорее промежуточный вид. Если вам нужно получить доступ к представлению напрямую, установите android: id и используйте findViewById (int).

Поэтому, чтобы решить проблему, вы должны перейти на findViewById вместо getParent из-за дополнительной компоновки между введением в версии 24.

Ответ 5

Вы можете проверить код TextInputLayout v24.x.x.
Теперь он работает с 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);
    }
}

где mInputFrame - FrameLayout.
Это причина вашей проблемы (родительский элемент FrameLayout).

Просто передайте параметр tilParam as вместо использования getParent(), если вам нужно его использовать.

Ответ 6

TextInputLayout имеет метод с именем getEditText(). Это может быть альтернативным способом решения вашей проблемы. Вместо того, чтобы начинать с самого EditText и получать родительский TextInputLayout, вы можете начать с TextInputLayout и просто получить дочернее представление EditText. Для представлений, созданных в формате XML, следующий код является примером:

TextInputLayout someInputLayout = findViewById(R.id.some_input_layout);
EditText someEditText = someInputLayout.getEditText();
String text = someEditText.getText().toString();

Возможно, это более желаемое решение, так как оно не требует каких-либо внешних методов, хотя это не решит вашу проблему, если по какой-то причине вам потребуется начать с EditText. Я знаю, что на это уже давно ответили, но я использовал решение @sylwano, пока не обнаружил, что для моей конкретной проблемы лучше сделать, как указано выше.