Search code examples
androidandroid-layoutandroid-edittextandroid-spinnerandroid-textinputlayout

Android EditText for multiple unit types


I have a form in Android where the user has to enter their height. However, I have a spinner where the user can select the measurement units (feet/inches, and centimeters), and then an EditText where they can enter the actual value

If the user selects cm as their units, I want a single EditText. If they select feet/inches, I want to display 2 EditText fields

The way I'm currently handling this seems inefficient. I have 3 EditText fields: 1 for cm, 1 for feet, and 1 for inches

I then attach an onItemSelected listener to the spinner. If the user selects the cm option, I setVisibility(view.VISIBLE) on the cm EditText, and setVisibility(view.INVISIBLE) on both the feet and inches EditText fields. If they select the feet/inches option, I just do the visibility in reverse and show/hide the corresponding fields.

Is there a more appropriate way to handle multiple unit types that require a different number of EditText fields?

Note: my EditText are actually wrapped up in TextInputLayouts so I can get Material animations on hints, and its on the TextInputLayouts that I'm setting visibility.

The code looks something like this:

public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {

        //Height unit spinner
        String [] values = {"cm","ft"};
        Spinner spinner = (Spinner) view.findViewById(R.id.input_height_spinner);
        spinner.setOnItemSelectedListener(this);
        ArrayAdapter<String> LTRadapter = new ArrayAdapter<>(this.getActivity(), android.R.layout.simple_spinner_item, values);
        LTRadapter.setDropDownViewResource(android.R.layout.simple_dropdown_item_1line);
        spinner.setAdapter(LTRadapter);

        heightCMWrapper = (TextInputLayout) view.findViewById(R.id.input_height_cm_wrapper);
        heightFTWrapper = (TextInputLayout) view.findViewById(R.id.input_height_ft_wrapper);
        heightINWrapper = (TextInputLayout) view.findViewById(R.id.input_height_in_wrapper);

//Some other code for inflating layout etc.
}

@Override
    public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {

        switch (position) {
            case 0:
                heightCMWrapper.setVisibility(view.VISIBLE);
                heightCMWrapper.setHint("Height (cm)");
                heightCMWrapper.requestFocus();

                heightFTWrapper.setVisibility(view.INVISIBLE);
                heightFTWrapper.setHint("");
                heightINWrapper.setVisibility(view.INVISIBLE);
                heightINWrapper.setHint("");
                break;
            case 1:
                heightCMWrapper.setVisibility(view.INVISIBLE);
                heightCMWrapper.setHint("");

                heightFTWrapper.setVisibility(view.VISIBLE);
                heightFTWrapper.setHint("Feet");
                heightFTWrapper.requestFocus();
                heightINWrapper.setVisibility(view.VISIBLE);
                heightINWrapper.setHint("Inches");
                break;
        }
    }

Solution

  • You could do it using just 2 EditTexts instead of 3. Have a primary EditText for both feet and cms and a secondary one for inches if they choose feet and inches. Then you just have to set the hint of the primary EditText and toggle the secondary EditText visibility.

    If you want to optimise your current solution with 3 EditText theres a few things you can do. You shouldn't have to set the hint every time they toggle the units, you should be able to just set it once in onCreateView since each unit has its own EditText. This will drop 6 lines from your method. You could take it further and make a method toggleVisibility(EditText editText, boolean visible, boolean giveFocus) but thats up to you.

    As a side note you might want to use View.GONE instead of View.INVISIBLE. View.INVISIBLE just makes it not visible but it still consumes its space in the layout. So if this is your layout:

    (input1) (input 2)

    and you set (input1) to invisible, this is what the layout would look like:

    (blank) (input2)

    instead if you set (input1) to View.GONE this is what it would look like

    (input 2)