设备旋转后AutoCompleteTextView下拉列表未显示

13

我有以下的AutoCompleteTextView:

<com.google.android.material.textfield.TextInputLayout
    android:id="@+id/offering_type_dropdown_layout"
    style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox.ExposedDropdownMenu"
    android:layout_width="0dp"
    android:layout_height="wrap_content"
    android:layout_marginEnd="@dimen/date_card_spacing"
    android:layout_marginStart="4dp"
    app:layout_constraintStart_toEndOf="@+id/offering_details_header_image"
    app:layout_constraintEnd_toStartOf="@+id/offering_details_date_layout"
    app:layout_constraintTop_toTopOf="parent"
    android:hint="@string/offering_type_hint">
    <AutoCompleteTextView
        android:id="@+id/offering_details_type_dropdown"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:inputType="textNoSuggestions"
        android:clickable="false"
        android:focusable="false"
        android:focusableInTouchMode="false"
        android:cursorVisible="false"/>
</com.google.android.material.textfield.TextInputLayout>

在我的Activity的onCreate方法中,我像这样填充AutoCompleteTextView:

    String[] TYPES = new String[] {getString(R.string.burnt_offering), getString(R.string.meal_offering), getString(R.string.peace_offering), getString(R.string.sin_offering)};
    ArrayAdapter<String> adapter = new ArrayAdapter<>(OfferingInputActivity.this, R.layout.offering_types_dropdown, TYPES);
    mOfferingTypeCombo.setAdapter(adapter);

然后我使用 Room 数据库填充视图,并预先选择其中一个值。在 Room 回调中,我执行以下操作:

然后我使用 Room 数据库填充视图,并预先选定其中一个值。在 Room 回调中,我执行以下操作:

  mOfferingTypeCombo.setText(getString(R.string.meal_offering)), false);

初始运行时一切正常,并且下拉菜单显示正确:

输入图像描述

现在我将设备旋转到横向。 执行与上面完全相同的代码,但是这一次,下拉框仅显示当前选择:

输入图像描述

因为某种原因,适配器中的所有其他条目都消失了。 我尝试了一些方法,例如在设置适配器之前使用 setAdapter(null) 但没有成功。有人能告诉我为什么旋转后即使执行完全相同的代码后,下拉菜单也会缺少条目吗?


1
这里有一个关于它的 bug:https://github.com/material-components/material-components-android/issues/1464 - Gabriele Mariotti
1
谢谢,你说得对。我的解决方法已经在方案中了。 - to_sam
7个回答

5

目前在这个主题上有一个未解决的错误。

您可以使用setFreezesText方法作为解决方法:

AutoCompleteTextView autoCompleteTextView =
    view.findViewById(R.id.offering_details_type_dropdown);
autoCompleteTextView.setFreezesText(false);

EditText设置freezesText=true。由于这个属性,在旋转后TextView#onRestoreInstanceState(Parcelable)会调用autoCompleteTextView.setText(value,true),它会对适配器的值应用一个过滤器。


这对我不起作用,创建一个继承自autoCompleteTextView的类,并重写其getFreezeText方法,如phillips77在https://github.com/material-components/material-components-android/issues/1464中建议的那样,对我有用。 - Felix Stanley

5
这个定制的MaterialAutoCompleteTextView可以解决所有问题:
class ExposedDropdownMenu : MaterialAutoCompleteTextView {

constructor(context: Context) : super(context)
constructor(context: Context, attrs: AttributeSet?) : super(context, attrs)
constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(
    context,
    attrs,
    defStyleAttr
)

override fun getFreezesText(): Boolean {
    return false
}

init {
    inputType = InputType.TYPE_NULL
}

override fun onSaveInstanceState(): Parcelable? {
    val parcelable = super.onSaveInstanceState()
    if (TextUtils.isEmpty(text)) {
        return parcelable
    }
    val customSavedState = CustomSavedState(parcelable)
    customSavedState.text = text.toString()
    return customSavedState
}

override fun onRestoreInstanceState(state: Parcelable?) {
    if (state !is CustomSavedState) {
        super.onRestoreInstanceState(state)
        return
    }
    setText(state.text, false)
    super.onRestoreInstanceState(state.superState)
}

private class CustomSavedState(superState: Parcelable?) : BaseSavedState(superState) {
    var text: String? = null

    override fun writeToParcel(out: Parcel, flags: Int) {
        super.writeToParcel(out, flags)
        out.writeString(text)
    }
}
}

源代码

注意: 在旧的API版本(如23或以下)中可能无法正常工作。 一种方法是使用自定义的ArrayAdapter,以防止过滤文本。

class NoFilterArrayAdapter : ArrayAdapter<Any?> {

constructor(context: Context, resource: Int) : super(context, resource)
constructor(context: Context, resource: Int, objects: Array<out Any?>) : super(context, resource, objects)

override fun getFilter(): Filter {
    return object : Filter() {
        override fun performFiltering(constraint: CharSequence?): FilterResults? {
            return null
        }

        override fun publishResults(constraint: CharSequence?, results: FilterResults?) {}
       }
   }
}

使用方法:

val adapter = NoFilterArrayAdapter(requireContext(), android.R.layout.simple_list_item_1, items)
          

节省了我大量的时间。谢谢。 - Nguyen Tuan Anh

0
为了解决当屏幕方向改变时的问题,在XML中添加以下内容:
android:saveEnabled="false"

0

就像 @Gabriele Mariotti 提到的那样,这是一个 bug。如发布的链接中所述,我采用了以下解决方法,效果很好:

public class ExposedDropDown extends MaterialAutoCompleteTextView {
       public ExposedDropDown(@NonNull final Context context, @Nullable final AttributeSet attributeSet) {
          super(context, attributeSet);
       }

       @Override
       public boolean getFreezesText() {
         return false;
       }
}

是的,它可以工作,但在旋转后项目的文本会被删除。 - Mohsents

0
我通过从AutoCompleteTextView中删除id来解决了这个问题。这个id负责在旋转后保存文本。
在onSaveInstanceState方法中保存AutoCompleteTextView的字符串。
代码:
  <com.google.android.material.textfield.TextInputLayout
                android:id="@+id/inputAddress"
                style="@style/Widget.MaterialComponents.TextInputLayout.FilledBox.ExposedDropdownMenu"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:hint="@string/Address">

                <AutoCompleteTextView
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:inputType="none"
                    />

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

list_item.xml

<TextView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="16dp"
android:ellipsize="end"
android:maxLines="1"
android:textAppearance="?attr/textAppearanceSubtitle1"
/>

fragment.class

class CashierAddFragment : Fragment() {

var mBinding: FragmentCashierAddBinding? = null

override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {

    val binding = FragmentCashierAddBinding.inflate(inflater, container, false)

    if(savedInstanceState == null) {
        initAddressSpinner(binding, "")
    } else {
        initAddressSpinner(binding, savedInstanceState.getString(KEY_ADDRESS))
    }

    mBinding = binding

    return binding.root
}

override fun onSaveInstanceState(outState: Bundle) {
    val address = mBinding!!.inputAddress.getTrimText()
    outState.putString(KEY_ADDRESS, address)

    super.onSaveInstanceState(outState)
}

private fun initAddressSpinner(binding: FragmentCashierAddBinding, initValue: String?) {
    val items = listOf("Option 1", "Option 2", "Option 3", "Option 4")
    val adapter = ArrayAdapter(requireContext(), R.layout.list_item, items)

    val autoTxtAddress = binding.inputAddress.editText as? AutoCompleteTextView
    autoTxtAddress?.setText(initValue)
    autoTxtAddress?.setAdapter(adapter)
}

}


0

@Mohsents 提出的解决方案对我有用。这是我使用的他代码的Java版本:

public class NoFilterArrayAdapter extends ArrayAdapter<Object> {

public NoFilterArrayAdapter(Context context, int resource) {
    super(context, resource);
}

public NoFilterArrayAdapter(Context context, int resource, Object[] objects) {
    super(context, resource, objects);
}

@Override
public Filter getFilter() {
    return new Filter() {
        @Override
        protected FilterResults performFiltering(CharSequence constraint) {
            return null;
        }

        @Override
        protected void publishResults(CharSequence constraint, FilterResults results) {
        }
    };
}
}

0
这个修复在GitHub问题上似乎有效:
autoCompleteTextView.isSaveEnabled = false

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