Home > Mobile >  Set width of TextInputEditText to n characters
Set width of TextInputEditText to n characters

Time:03-12

I'm trying to implement a layout where user will input their phone number. The phone number will be 11 digits. And so I wanted to build a text input field with a fixed width that can accommodate 11 characters.

NOTE: I don't want the input field to be wider than 11 characters. Let's say each character is 10px wide. So the input field should be 11*10px = 110px wide (I'm not taking the drawable icon into account here).

Here's what I've tried in XML:

            <com.google.android.material.textfield.TextInputLayout
                android:id="@ id/textField"
                style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginTop="@dimen/margin_48"
                app:startIconDrawable="@drawable/ic_phone">

                <com.google.android.material.textfield.TextInputEditText
                    android:id="@ id/phone"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:ems="11"
                    android:inputType="phone"
                    android:maxLength="11"
                    android:maxLines="1"
                    android:minEms="11"
                    android:text="01"
                    android:textSize="20sp"
                    android:typeface="monospace" />
            </com.google.android.material.textfield.TextInputLayout>

But this produces an output like the following:

Screenshot of UI

As you can see, despite using ems and minEms, the field is 2 characters wide (it's 0 character wide if I don't add android:text). But I want it to have a width of 11 characters (not more or less). Why is ems not effective here and what's the solution?

CodePudding user response:

Just edit your layout width

from

  android:layout_width="wrap_content"

to

   android:layout_width="match_parent"

I just edited your code

        <com.google.android.material.textfield.TextInputLayout
       

         android:id="@ id/textField"
                    
            
            
   style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:layout_marginTop="@dimen/margin_48"
                    app:startIconDrawable="@drawable/ic_phone">
    
                    <com.google.android.material.textfield.TextInputEditText
                        android:id="@ id/phone"
                        android:layout_width="match_parent"
                        android:layout_height="wrap_content"
                        android:ems="11"
                        android:inputType="phone"
                        android:maxLength="11"
                        android:maxLines="1"
                        android:minEms="11"
                        android:text="01"
                        android:textSize="20sp"
                        android:typeface="monospace" />
                </com.google.android.material.textfield.TextInputLayout>

CodePudding user response:

You should set a 11 digits text (the font must be a monospace, in order to have all the characters of the same width) into the xml of your EditText widget (like 12345678901), with android:layout_width="wrap_content", then define a ViewTreeObserver.OnGlobalLayoutListener in your fragment, that calculates the width when the layout is available to be measured:

int viewWidth;

ViewTreeObserver.OnGlobalLayoutListener viewTreeObserver = new ViewTreeObserver.OnGlobalLayoutListener() {
        @Override
        public void onGlobalLayout() {
            if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) {
                YOUR_FRAME_OR_LINEAR_LAYOUT.getViewTreeObserver().removeGlobalOnLayoutListener(this);
            } else {
                YOUR_FRAME_OR_LINEAR_LAYOUT.getViewTreeObserver().removeOnGlobalLayoutListener(this);
            }
            viewWidth = YOUR_EDITTEXT.getMeasuredWidth();
            update();
        }
    };

You could instantiate the observer in onResume() of your fragment, and remove it in onPause():

@Override
public void onResume() {
    super.onResume(); 
    ViewTreeObserver vto = YOUR_FRAME_OR_LINEAR_LAYOUT.getViewTreeObserver();
    vto.addOnGlobalLayoutListener(viewTreeObserver);
}

@Override
public void onPause() {
    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) {
        YOUR_FRAME_OR_LINEAR_LAYOUT.getViewTreeObserver().removeGlobalOnLayoutListener(viewTreeObserver);
    } else {
        YOUR_FRAME_OR_LINEAR_LAYOUT.getViewTreeObserver().removeOnGlobalLayoutListener(viewTreeObserver);
    }
    super.onPause();
}

Your update method simply sets the width and the text (initially empty?) of your EditText widget:

public void update() {
    // Set all the width of your EditText using the viewWidth value,
    // all LayoutParams parameters of the widget,
    // and set an empty text on it
}
  • Related