Skip to content

Commit

Permalink
[TextInputLayout] Fix onMeasure() infinite loop bug caused by posting…
Browse files Browse the repository at this point in the history
… requestLayout() before endLayout is fully rendered.

Brief explanation: in TextInputLayout#onMeasure, TextInputLayout will try to send a post to trigger requestLayout() method based on the boolean value returned from updateDummyDrawbles() method, but in shouldUpdateEndDummyDrawable(), we try to get the endLayout.getMeasureWidth() which is not reliable, if the endLayout hasn't rendered fully, the getMeasureWidth() will return 0 making the updateDummyDrawables() to return TRUE to trigger requestLayout() in an infinite loop.

To fix this issue, we need to introduce ViewTreeObserver to help us to run posing the requstLayout() after endLayout/startLayout is fully rendered.

PiperOrigin-RevId: 571765829
  • Loading branch information
Material Design Team authored and drchen committed Oct 10, 2023
1 parent 5559cbc commit 93360a5
Showing 1 changed file with 22 additions and 11 deletions.
33 changes: 22 additions & 11 deletions lib/java/com/google/android/material/textfield/TextInputLayout.java
Expand Up @@ -57,6 +57,7 @@
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewStructure;
import android.view.ViewTreeObserver.OnGlobalLayoutListener;
import android.view.accessibility.AccessibilityEvent;
import android.widget.AutoCompleteTextView;
import android.widget.EditText;
Expand Down Expand Up @@ -197,7 +198,7 @@
* developer guidance</a> and <a href="https://material.io/components/text-fields/overview">design
* guidelines</a>.
*/
public class TextInputLayout extends LinearLayout {
public class TextInputLayout extends LinearLayout implements OnGlobalLayoutListener {

private static final int DEF_STYLE_RES = R.style.Widget_Design_TextInputLayout;

Expand Down Expand Up @@ -452,6 +453,8 @@ public interface OnEndIconChangedListener {

private boolean restoringSavedState;

private boolean globalLayoutListenerAdded = false;

public TextInputLayout(@NonNull Context context) {
this(context, null);
}
Expand Down Expand Up @@ -715,6 +718,21 @@ public TextInputLayout(@NonNull Context context, @Nullable AttributeSet attrs, i
setHelperText(helperText);
}

@Override
public void onGlobalLayout() {
if (VERSION.SDK_INT < VERSION_CODES.JELLY_BEAN) {
endLayout.getViewTreeObserver().removeGlobalOnLayoutListener(this);
} else {
endLayout.getViewTreeObserver().removeOnGlobalLayoutListener(this);
}
globalLayoutListenerAdded = false;
boolean updatedHeight = updateEditTextHeightBasedOnIcon();
boolean updatedIcon = updateDummyDrawables();
if (updatedHeight || updatedIcon) {
editText.post(() -> editText.requestLayout());
}
}

@Override
public void addView(
@NonNull View child, int index, @NonNull final ViewGroup.LayoutParams params) {
Expand Down Expand Up @@ -3247,16 +3265,9 @@ public void onRtlPropertiesChanged(int layoutDirection) {
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);

boolean updatedHeight = updateEditTextHeightBasedOnIcon();
boolean updatedIcon = updateDummyDrawables();
if (updatedHeight || updatedIcon) {
editText.post(
new Runnable() {
@Override
public void run() {
editText.requestLayout();
}
});
if (!globalLayoutListenerAdded) {
endLayout.getViewTreeObserver().addOnGlobalLayoutListener(this);
globalLayoutListenerAdded = true;
}
updatePlaceholderMeasurementsBasedOnEditText();
endLayout.updateSuffixTextViewPadding();
Expand Down

0 comments on commit 93360a5

Please sign in to comment.