Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Broken TextInputLayout with support library 24.2.0 #81

Closed
jakubkulhan opened this issue Sep 12, 2016 · 8 comments
Closed

Broken TextInputLayout with support library 24.2.0 #81

jakubkulhan opened this issue Sep 12, 2016 · 8 comments

Comments

@jakubkulhan
Copy link

Android support library 24.2.0 introduced these changes to TextInputLayout:

     public TextInputLayout(Context context, AttributeSet attrs, int defStyleAttr) {
          ...
+        mInputFrame = new FrameLayout(context);
+        mInputFrame.setAddStatesFromChildren(true);
+        addView(mInputFrame);
          ...
     }
     ...
     public void addView(View child, int index, final ViewGroup.LayoutParams params) {
         if (child instanceof EditText) {
+            mInputFrame.addView(child, new FrameLayout.LayoutParams(params));
+
+            // Now use the EditText's LayoutParams as our own and update them to make enough space
+            // for the label
+            mInputFrame.setLayoutParams(params);
+            updateInputLayoutMargins();
+
             setEditText((EditText) child);
-            super.addView(child, 0, updateEditTextMargin(params));
         } else {
         ...

Anvil's rendering breaks TextInputLayout as it always tries to replace FrameLayout inside with EditText. I really like Anvil's reactive views approach, however, I'd like to also use latest stable support library. Any suggestions how to overcome this? Thank you.

@defHLT
Copy link

defHLT commented Nov 10, 2016

That's where a beautiful abstraction over Android Views leaks :(

Any update on this one?

@defHLT
Copy link

defHLT commented Nov 10, 2016

@jakubkulhan Did you check if xml and withId will make any difference?

xml(R.layout.textinputlayout_with_edittext) {
    //...

    withId(R.id.edit_text) {
        //...
    }

  //...

}

@mitchryanjusay
Copy link

using withId will work as I have it working on my code but the problem with using XML layout is it has a bug when calling Anvil.render() see: issue 83

@zserge
Copy link
Collaborator

zserge commented Feb 26, 2017

Well, this is a bugger. I don't see how Anvil can nicely handle this. Support Library developers have broken too many things here - they're injecting views, in the unexpected order, and they've overridden addView() behavior, mess with LayoutParams, and to make it even worse - they've overridden one particular addView() implementation with one particular use case (XMLs).

Still, Anvil is a cool little library that allows to work this around (even with no xmls):

            textInputLayout(() -> {
                size(FILL, WRAP);
                init(() -> {
                    ViewGroup layout = Anvil.currentView();
                    TextInputEditText editText = new TextInputEditText(getContext());
                    editText.setId(123);
                    layout.addView(editText, layout.getChildCount(),
                            new LinearLayout.LayoutParams(FILL, WRAP));
                });
                withId(123, () -> {
                    size(FILL, WRAP);
                    textSize(sip(24));
                });
                hint("Some hint");
                skip();
            });

Here I'm creating a child view directly using its constructor. Then I assign some ID to it (it may not be unique, but it should be unique within the TextInputLayout). Then I find that edit text view by ID, set the rest of its attributes as one would normally do with Anvil, finally, I skip all the child views that were not created by Anvil. This brings the expected results.

However, I have to agree, that if the view is designed to be used exclusively from XML - there is no reason to make it even more painful. I would agree with the suggestion to use an XML layout for this view hierarchy specifically.

By the way, there is a good chance that existing XML-related issues are all gone, you may check the most recent marser branch - I've rewritten too much to describe it here, but you may look at #99 for a bigger picture.

@jakubkulhan
Copy link
Author

Thank you all for support! In the end, we settled for parts of our views (incompatible with latest support library) being written in XML and then bound using xml() & withId() Anvil methods. Workaround with init() seems also nice, will definitely give it a try.

@meoyawn
Copy link

meoyawn commented Apr 17, 2017

is the init() hack the preferred workaround for this?

still getting this error with anvil 0.5.1

@zserge
Copy link
Collaborator

zserge commented Apr 17, 2017

@adelnizamutdinov I'm afraid so. Unless google developers override all "addView()" methods (or remove the current particular override) I don't see how TextInputLayout can be used without XMLs or without the workround above. Perhaps moving TextInputLayout to a separate XML could give you a cleaner abstraction from its ugly internals than init().

@meoyawn
Copy link

meoyawn commented Apr 18, 2017

here's the hack I came up with to solve this

typealias IdRes = Int

inline fun textInputEditHack(id: IdRes, crossinline f: () -> Unit) {
    init {
        val v = Anvil.currentView<TextInputLayout>()
        v.addView(TextInputEditText(v.context).also { it.id = id },
                  v.childCount,
                  LinearLayout.LayoutParams(MATCH, WRAP))
    }

    withId(id) {
        f()
    }
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants