AwesomeValidation icon indicating copy to clipboard operation
AwesomeValidation copied to clipboard

UNDERLABEL doesn't work on ConstraintLayout

Open matiit opened this issue 7 years ago • 8 comments

device-2017-07-09-134358

For given layout:

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="anddev.mat.pckplace.CreateAccount">

    <EditText
        android:id="@+id/email"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="8dp"
        android:ems="10"
        android:inputType="textEmailAddress"
        android:text="[email protected]"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <EditText
        android:id="@+id/password"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="16dp"
        android:ems="10"
        android:inputType="textPassword"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/email" />

    <Button
        android:id="@+id/joinButton"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="16dp"
        android:text="Join"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/password" />

    <ProgressBar
        android:id="@+id/progressBar"
        style="?android:attr/progressBarStyle"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintVertical_bias="0.185" />

</android.support.constraint.ConstraintLayout>

matiit avatar Jul 09 '17 12:07 matiit

Thanks for reporting, will check it later.

thyrlian avatar Jul 09 '17 12:07 thyrlian

Just tried with your layout, the UNDERLABEL validation doesn't work properly indeed. I think the problem is because of ConstraintLayout. I'll try to find out a solution and meanwhile update the demo project with ConstraintLayout. Thanks again.

thyrlian avatar Aug 17 '17 17:08 thyrlian

Apart from copying the LayoutParams, I also tried to copy the ConstraintSet for each view inside the ConstraintLayout (and then later apply them to corresponding new container view). Unfortunately this approach doesn't work. After checking the source code of ConstraintSet, I found the cause:

public class ConstraintSet {
    private HashMap<Integer, ConstraintSet.Constraint> mConstraints = new HashMap();
    ...

    public void clone(ConstraintLayout constraintLayout) {
        int count = constraintLayout.getChildCount();
        this.mConstraints.clear();

        for(int i = 0; i < count; ++i) {
            View view = constraintLayout.getChildAt(i);
            LayoutParams param = (LayoutParams)view.getLayoutParams();
            int id = view.getId();
            if(!this.mConstraints.containsKey(Integer.valueOf(id))) {
                this.mConstraints.put(Integer.valueOf(id), new ConstraintSet.Constraint());
            }
            ...

The relationship HashMap mConstraints holds each view's id as the key, that's why simply copying attributes doesn't work. The constraint is bound with view id, always refer to view id at creation, not transferable.

thyrlian avatar Jan 02 '18 21:01 thyrlian

Tried to hack by setting new container's id to EditText's id, then giving EditText a new id, assuming this would hand over all constraints from EditText to its new container parent. But unfortunately it doesn't work either :(

int idOfEditText = editText.getId();
editText.setId(View.generateViewId());
newContainer.setId(idOfEditText);

thyrlian avatar Jan 14 '18 19:01 thyrlian

The private member mConstraintSet of ConstraintLayout is also null:

Field fieldConstraintSet = ((ConstraintLayout) parent).getClass().getDeclaredField("mConstraintSet");
fieldConstraintSet.setAccessible(true);
ConstraintSet constraintSet = (ConstraintSet) fieldConstraintSet.get(parent);
// constraintSet is null here
// the reason is when init, attr != styleable.ConstraintLayout_Layout_constraintSet

thyrlian avatar Jan 14 '18 20:01 thyrlian

Sorry @matiit, finally I gave up - spent too much time on it but could not find a solution, it's way too complicated.

Created and merged a PR: https://github.com/thyrlian/AwesomeValidation/pull/50

In this PR, when the application tries to use UNDERLABEL for ConstraintLayout, a UnsupportedLayoutException will be thrown with message:

UnderlabelValidator doesn't support ConstraintLayout, please use TextInputLayoutValidator or other any other validator.

And in the demo project, I changed the TextInputLayout validation style's layout to ConstraintLayout, to show how it works.

I'll keep this issue open, won't fix for now, but will still look for a solution in the future. I'm really sorry for that and thank you very much for reporting this issue.

thyrlian avatar Jan 15 '18 07:01 thyrlian

When will this issue be fixed?

Sabutori avatar Nov 10 '20 18:11 Sabutori

@Sabutori probably not, at least it won't be fixed by me. As mentioned earlier, I just could not find a solution for this back in time, but also get no time to check this for the moment. Sorry for giving such a negative answer.

thyrlian avatar Nov 10 '20 18:11 thyrlian