AutoCompleteTextView下拉列表高度未能根据内容自适应。

3
我的应用程序有一个AutoCompleteTextView,它查询Room数据库并在用户输入时将搜索结果显示在下拉菜单中。结果被正确地显示,但下拉菜单的高度总是太大了(请参见下面的截图)。

Dropdown with results

基本上,AutoCompleteTextView具有一个TextWatcher,它将当前文本发送到ViewModel,然后查询数据库。一旦接收到结果,ViewModel会更新视图状态(Flow),并且观察它的片段将AutoCompleteTextView的适配器重新分配为新数据。
下拉项布局。
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/root"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:padding="@dimen/spacing_8">

    <GridLayout
        android:id="@+id/imageContainer"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        ... />

    <com.google.android.material.textview.MaterialTextView
        android:id="@+id/txtName"
        style="@style/TextAppearance.MaterialComponents.Body1"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        ... />
</androidx.constraintlayout.widget.ConstraintLayout>

碎片布局
<com.google.android.material.textfield.TextInputLayout>
    ...
    <com.google.android.material.textfield.MaterialAutoCompleteTextView
        android:id="@+id/autoCompleteTextView"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:padding="@dimen/spacing_16"/>
</com.google.android.material.textfield.TextInputLayout>

Adapter

internal class StationAdapter(
    context: Context,
    private val stations: List<UiStation>
) : ArrayAdapter<String>(
    context,
    R.layout.item_station,
    stations.map { it.name }
) {

    fun getStation(position: Int): UiStation = stations[position]

    override fun getCount(): Int = stations.size

    override fun getItem(position: Int): String = stations[position].name

    override fun getView(position: Int, convertView: View?, parent: ViewGroup): View {
        return convertView ?: run {
            val inflater = LayoutInflater.from(context)
            val binding = ItemStationBinding.inflate(inflater, parent, false).apply {
                val station = stations[position]
                imageContainer.addIconsForModes(station.modes)
                txtName.text = station.name
            }

            binding.root
        }
    }

    ...
}

Fragment

private fun handleState(state: StationSearchViewState) = with(state) {
    ...

    stations?.let {
        val adapter = StationAdapter(
            context = requireContext(),
            stations = it
        )
        binding.autoCompleteTextView.setAdapter(adapter)
    }
}

这是我尝试过的其他方法,但都没有成功(得到了相同的结果):
  1. 将数据库表的所有结果传递给适配器并实现自定义筛选器
  2. 实现一个函数来提交新数据给适配器并调用notifyDataSetChanged()
  3. 将AutoCompleteTextView的android:dropDownHeight属性设置为wrap_content
唯一有效的方法似乎是使用ArrayAdapterandroid.R.layout.simple_list_item_1布局来显示项目。

找到任何解决方案了吗? - Dipin P J
2个回答

1

我曾经遇到过同样的问题,对于实现自定义的AutoCompleteTextView并不是很满意。但是在一些尝试之后,我找到了一个简单的解决方法。

问题出在ConstraintLayout作为下拉列表项布局的根布局上。我将其包装在RelativeLayout中,问题就得到了解决。

下拉列表项布局

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

    <androidx.constraintlayout.widget.ConstraintLayout
        android:id="@+id/root"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:padding="@dimen/spacing_8">

        ...
    </androidx.constraintlayout.widget.ConstraintLayout>
</RelativeLayout>

我认为FrameLayout或LinearLayout也可以使用,但我还没有测试过。


1

经过三天的努力,我终于找到了一个解决方案,其中部分内容在这个与问题无关的答案中。

以下是我的代码:

private const val DROPDOWN_ITEM_MAX_COUNT = 5
private const val PADDING = 34

class CustomAutoCompleteTextView(
    context: Context,
    attributeSet: AttributeSet?
) : MaterialAutoCompleteTextView(context, attributeSet) {

    override fun onFilterComplete(count: Int) {
        val itemCount = if (count > DROPDOWN_ITEM_MAX_COUNT) {
            DROPDOWN_ITEM_MAX_COUNT
        } else {
            count
        }
        val individualItemHeight = (height / 2) + PADDING

        dropDownHeight = itemCount * individualItemHeight
        super.onFilterComplete(count)
    }
}

本质上,我必须创建一个自定义的AutoCompleteTextView。一旦数据被过滤,它会获取一个项目计数(不大于我设置的最大值),并将其乘以我的下拉列表中每个单独项目的高度(a)加上填充(b),以确保下拉视图始终包裹项目。

a:我通过一些试错达到了这个值,但它仍然适用于不同的屏幕尺寸和密度。

b:非强制性的。我只是认为添加一点填充可以让它看起来更好。

最终结果

Single result

Multiple results


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接