3

I'm creating a dropdown menu using AutoCompleteTextView. How do I remove the default margins at the top and bottom of the list?

enter image description here

To recreate:

<com.google.android.material.textfield.TextInputLayout
        style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox.ExposedDropdownMenu"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:layout_constraintStart_toStartOf="parent"
        app:boxBackgroundColor="@color/white"
        android:focusable="false"
        app:boxStrokeWidth="1.5dp"
        app:layout_constraintTop_toBottomOf="@+id/spinner_network">

        <AutoCompleteTextView
            android:id="@+id/autoCompleteTextView"
            android:layout_width="250dp"
            android:layout_height="match_parent"
            android:inputType="none"
            android:dropDownHeight="200dp"
            android:text="Select age" />

    </com.google.android.material.textfield.TextInputLayout>
        List<String> dropdownItems = new ArrayList<>();
        for(int i = 1; i <= 100; i++){
            dropdownItems.add(String.valueOf(i));
        }

        ArrayAdapter<String> spinnerAdapter = new ArrayAdapter<>(
                this, R.layout.dropdown_item, dropdownItems
        );

        AutoCompleteTextView autoCompleteTextView = findViewById(R.id.autoCompleteTextView);
        autoCompleteTextView.setAdapter(spinnerAdapter);

R.layout.dropdown_item

<TextView
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/textView"
    android:layout_width="match_parent"
    android:textColor="@color/black"
    android:padding="14dp"
    android:layout_height="wrap_content"
    android:text="TextView" />
DIRTY DAVE
  • 2,523
  • 2
  • 20
  • 83
  • Why did you wrapped it inside `TextInputLayout`? i think that's the reason . Try removing it and check . or try something Like [This](https://stackoverflow.com/questions/50853203/how-to-remove-bottom-padding-from-textinputlayout). – ADM Jan 05 '22 at 10:14
  • No idea. I was just following a tutorial on how to do it https://www.geeksforgeeks.org/exposed-drop-down-menu-in-android/ I tried removing the TextInputLayout and the whole dropdown menu doesn't work anymore – DIRTY DAVE Jan 05 '22 at 10:15
  • @MikeM. Hmm I still can't seem to get the dropdown to work with ```AutoCompleteTextView``` when I remove the ```TextInputLayout```. When I click on it nothing happens. https://i.imgur.com/878Tstt.png – DIRTY DAVE Jan 08 '22 at 03:13
  • I didn't do anything with the themes, but I removed all the ones I had just in case. Also tried deleting the app and reinstalling, invalidating caches + restart, and tested on my real device. But it's still not displaying a dropdown. ```Are you trying to make this into a Spinner``` I had a working spinner with no margins but I'm trying to migrate it to this solution because I couldn't find a way to limit the maximum dropdown height of a spinner (because 100 items was covering the entire screen). I tried the ```popupBackground``` with the ```TIL``` height set to ```wrap_content``` still margins – DIRTY DAVE Jan 08 '22 at 03:42
  • yeah I'm trying to make it into a Spinner with no editable input. But I'm really confused on why it's not working WITHOUT the TIL. I think theres something wrong with either my XML or code. Is it possible if you could post your working snippets so I can compare what I'm doing incorrectly – DIRTY DAVE Jan 08 '22 at 03:45
  • 2
    OK, yeah, I didn't initially realize what you were doing; you're not really using this as an `AutoCompleteTextView`. Well, ignore my previous comments here, 'cause I thought this was just for a regular `AutoCompleteTextView` setup. I'll let you know if I think of anything else. Btw, there's nothing wrong with your XML or code, really. The ACTV is working as its supposed to. The TIL just adds some bells and whistles, and one of those is the clickable dropdown arrow. ACTV doesn't have that on its own. – Mike M. Jan 08 '22 at 03:53
  • 1
    I found out that setting an `OnClickListener` on that ACTV actually works, since it's not accepting text input. That means that we can basically replicate TIL's behavior without the TIL: https://drive.google.com/file/d/10fpJswrcJ7MiDnRJH7Ycv49p3J37f2nO/view?usp=sharing. I can't get smooth video on this machine atm, but it works: https://i.stack.imgur.com/T2QrH.png. Not sure if you did actually want the border, but you can see that the padding's gone (so that's gotta be coming from the TIL somewhere, but I've not found it yet). Just FYI, if it helps ya. – Mike M. Jan 08 '22 at 05:20
  • 1
    @MikeM. Absolute legend. It fixed the margin issue, works without TIL (I disliked the flickering dropdown animation), and now I can use this solution instead of spinners for a simple dropDownHeight. Thanks a bunch. Post your answer and claim your bounty boss ya deserve it Lol – DIRTY DAVE Jan 08 '22 at 05:41
  • 1
    No problem. I don't post answers here any more, though, so please feel free to finish this up however you prefer. I still want to track down where that padding is coming from, and I'll let you know if I ever figure out some way to turn it off from the XML. Thank you, though. I appreciate the offer. Glad we found something usable. Cheers! – Mike M. Jan 08 '22 at 06:03
  • 1
    I found where that's coming from, and have added some notes on Zain's answer below, since they were first to confirm that the parent's padding was causing those gaps. – Mike M. Jan 08 '22 at 08:42
  • 1
    Just tried your other solution to remove the padding. Works perfectly too :) Thank you for your hard work, seriously. Appreciate it alot. – DIRTY DAVE Jan 08 '22 at 14:40

3 Answers3

5

UPDATE

All the credits and efforts back to @MikeM. from the comments. Many thanks to his efforts.

Cause The padding is coming from the TextInputLayout itself where its DropdownMenuEndIconDelegate sets some MaterialShapeDrawables as the dropdown's background. The value of the vertical padding is 8dp which taken from this resource dimen.

Solution 1:

Override this resource dimen to be 0dp:

<dimen name="mtrl_exposed_dropdown_menu_popup_vertical_padding" tools:override="true">0dp</dimen>

Solution 2:

The previous solution will be applied to all AutoCompleteTextView's, but if you want to do this for a certain ones: change the default dropDown background drawable, for instance:

autoCompleteTextView.setDropDownBackgroundDrawable(new ColorDrawable(Color.WHITE));

With reflections (Not recommended as it's anti-pattern)

The drop down popup of the AutoCompleteTextView can be accessed internally by mPopup field. To get it with reflections:

// Java:

public static ListPopupWindow getPopup(AutoCompleteTextView autoCompleteTextView) {
    try {
        Field field = AutoCompleteTextView.class.getDeclaredField("mPopup");
        field.setAccessible(true);
        return (ListPopupWindow) field.get(autoCompleteTextView);
    } catch (NoSuchFieldException e) {
        e.printStackTrace();
    } catch (IllegalAccessException e) {
        e.printStackTrace();
    }
    return null;
}


//  Kotlin:

fun AutoCompleteTextView.getPopup(): ListPopupWindow? {
    try {
        val field = AutoCompleteTextView::class.java.getDeclaredField("mPopup")
        field.isAccessible = true
        return field.get(this) as ListPopupWindow
    } catch (e: NoSuchFieldException) {
        e.printStackTrace()
    } catch (e: IllegalAccessException) {
        e.printStackTrace()
    }
    return null
}

Then remove the padding by setting it to the parent view of the internal ListView:

// Java:

autoCompleteTextView.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        ListPopupWindow popup = getPopup(autoCompleteTextView);
        if (popup != null) {
            ListView listView = popup.getListView();
            if (listView!= null)
                ((View) listView.getParent()).setPadding(0, 0, 0, 0);
        }
    }
});

// Kotlin

autoCompleteTextView.setOnClickListener {
    val popUp = autoCompleteTextView2.getPopup()?.listView?.parent
    if (popUp != null)
        (popUp as View).setPadding(0, 0, 0, 0)
}

This is done in OnClickListener because the nullability checks won't match as the list is formed when the user hits it.

Zain
  • 37,492
  • 7
  • 60
  • 84
  • Dang is there really no simple XML solution? I really don't want to add all this bloat just to remove margins – DIRTY DAVE Jan 08 '22 at 03:14
  • Really did some research before posting this, from xml attributes to styles, searching the web couldn't find any clues unfortunately – Zain Jan 08 '22 at 04:16
  • Hi there, Zain. I found where that padding's coming from. [TIL's `DropdownMenuEndIconDelegate` sets some `MaterialShapeDrawable`s](https://github.com/material-components/material-components-android/blob/master/lib/java/com/google/android/material/textfield/DropdownMenuEndIconDelegate.java#L218) as the dropdown's background, with [some vertical paddings from a resource dimen](https://github.com/material-components/material-components-android/blob/master/lib/java/com/google/android/material/textfield/res/values/dimens.xml#L65). The only way I can think of atm to fix that in XML is to override… – Mike M. Jan 08 '22 at 08:28
  • 1
    …that value; e.g., `0dp`. Alternatively, in code, that means we can set a background drawable to get rid of that padding, without having to resort to reflection to get at the popup; e.g., `autoCompleteTextView.setDropDownBackgroundDrawable(new ColorDrawable(Color.WHITE));`. Just FYI, really, if any of that is of any use to ya. Cheers! – Mike M. Jan 08 '22 at 08:28
  • @MikeM. This is really brilliant and elegant.. pls post this as an answer ..I'll remove this answer shortly..thanks again for letting me know – Zain Jan 08 '22 at 13:05
  • Add both of Mike's solutions to your reflection solution – DIRTY DAVE Jan 08 '22 at 14:31
  • It's cool, Zain. :-) Please feel free to add that stuff into to your answer so Dave can finish up their question here. I don't do answers any more, and you got us on the right track to start, so I think it's only fair. Cheers, everybody! – Mike M. Jan 08 '22 at 15:00
  • 1
    (Please don't feel like you _have_ to, though, if you'd rather delete this, or whatever. I just figured that the bounty shouldn't go to waste.) – Mike M. Jan 08 '22 at 15:28
  • @MikeM. That's kind of you; thanks.. just hoped if you could do it yourself; though appreciate your thoughts of not answering .. you really the one that deserve the bounty; just afraid of losing these info for future users. Anyways I will update it; I am not fully aware if the bounty can be retained to the OP by the any means or even dropped though. – Zain Jan 08 '22 at 15:57
  • 1
    The bounty has worked as intended for the OP, so they got their money's worth. No need to let the rep just disappear, and if you're willing to put in the effort to put together a proper answer from all of this, I'd say that deserves some points. Besides, I'm a lazy, lazy man, Zain. You'd be doing me a favor, too. :-) – Mike M. Jan 08 '22 at 16:06
0

Try removing dropDownHeight attribute from the AutoCompleteTextView

android:dropDownHeight="200dp" --> remove this line

And also set your AutoCompleteTextView height as wrap_content.

DrHowdyDoo
  • 2,327
  • 2
  • 7
  • 21
0

It won't let me edit the answer but another solution by https://stackoverflow.com/users/2850651/mike-m to remove padding:

Calling .showDropDown() in autoCompleteTextView's .setOnClickListener()

<com.google.android.material.textfield.MaterialAutoCompleteTextView
        android:id="@+id/autoCompleteTextView"
        android:layout_width="250dp"
        android:layout_height="50dp"
        android:drawableEnd="@drawable/ic_arrow_drop_down"
        android:dropDownHeight="200dp"
        android:inputType="none"
        android:text="Select age" 
        ...../>

List<String> dropdownItems = new ArrayList<>();
for (int i = 1; i <= 10; i++) {
     dropdownItems.add(String.valueOf(i));
}

ArrayAdapter<String> spinnerAdapter = new ArrayAdapter<>(
    this, R.layout.dropdown_item, dropdownItems
);


MaterialAutoCompleteTextView autoCompleteTextView = findViewById(R.id.autoCompleteTextView);
autoCompleteTextView.setAdapter(spinnerAdapter);

//.showDropDown() removes the padding
autoCompleteTextView.setOnClickListener(v -> autoCompleteTextView.showDropDown());

enter image description here

DIRTY DAVE
  • 2,523
  • 2
  • 20
  • 83