You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android中RecyclerView内AutoCompleteTextView搜索时下拉弹窗不显示

RecyclerView中Item内AutoCompleteTextView下拉弹窗无法显示的解决方案

问题描述

我被这个问题困扰了3天多。在RecyclerView的每个Item中都包含一个AutoCompleteTextView,但在AutoCompleteTextView中搜索时,下拉弹窗无法显示。需要指出修改代码的位置或方式,实现在RecyclerView每个Item中正常使用AutoCompleteTextView。

已尝试的方案

  • 手动调用autoCompleteTextView.showDropDown()显示弹窗
  • 用户在AutoCompleteTextView中输入时通知适配器
  • 用户输入时每次重置新的适配器
  • 在AndroidManifest中尝试了android:windowSoftInputMode=""的所有选项
  • 在StackOverflow上查阅了20多个相关问题
  • 在onBindViewHolder()方法中设置ArrayAdapter

现有代码

Activity的XML文件

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">
    <data>
        <variable
            name="viewModel"
            type="com..job..i.viewModel.job.JobViewModel" />
        <import type="android.view.View" />
    </data>

    <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <androidx.core.widget.NestedScrollView
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:fillViewport="true">

            <androidx.appcompat.widget.LinearLayoutCompat
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:background="@color/screenBG"
                android:orientation="vertical">

                    <androidx.recyclerview.widget.RecyclerView
                        android:id="@+id/rvSupervisor"
                        android:layout_width="match_parent"
                        android:layout_height="wrap_content"
                        tools:itemCount="1"
                        tools:listitem="@layout/job_filter_adapter" />
            </androidx.appcompat.widget.LinearLayoutCompat>
        </androidx.core.widget.NestedScrollView>
    </androidx.constraintlayout.widget.ConstraintLayout>
</layout>

适配器类

public class JobFilterAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
    public final String tag = JobFilterAdapter.class.getSimpleName();

    private final Activity _activity;
    private final LayoutInflater inflater;
    private final List<StaffInfo> _staffList;
    private final List<String> jobList;


    public JobFilterAdapter(Activity activity, List<StaffInfo> staffList,
                           List<String> list) {
        jobStaffAdapter = this;
        _activity = activity;
        inflater = _activity.getLayoutInflater();
        _staffList = staffList;
        jobList = list;
    }
    @NonNull
    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        return new AdapterHolder(DataBindingUtil.inflate(inflater, R.layout.row_job, parent, false),
                new JObWatcher());
    }

    @Override
    public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, @SuppressLint("RecyclerView") int position) {
        AdapterHolder adapterHolder = (AdapterHolder) holder;
        
        StaffInfo model = _staffList.get(holder.getAdapterPosition());

        adapterHolder.binding.autoCompleteTxtJob.setText(model.getStaffNo(), false);
        adapterHolder.binding.txtStaffName.setText(model.getStaffName());
        
        adapterHolder.jobWatcher.updateState(position, adapterHolder);
        
    }

    @Override
    public int getItemCount() {
        return _staffList.size();
    }


    class AdapterHolder extends RecyclerView.ViewHolder {
        private final RowJobBinding binding;
        JObWatcher jobWatcher;
        ArrayAdapter jobArrayAdapter;

        public AdapterHolder(@NonNull RowJobBinding _binding, JObWatcher _jobWatcher) {
            super(_binding.getRoot());
            binding = _binding;
            jobWatcher = _jobWatcher;

            jobArrayAdapter = new ArrayAdapter(_activity, R.layout.row_job_item,jobList);
            binding.autoCompleteTxtJob.setThreshold(1);
        }

    }

    public class JObWatcher {
        int position;
        AdapterHolder holder;

        private void updateState(int pos, AdapterHolder viewHolder) {
            position = pos;
            holder = viewHolder;
            manageAutoText();
        }

        private void manageAutoText() {
            holder.binding.autoCompleteTxtJob.setOnFocusChangeListener((view, b) -> {
                if (b) {
                    holder.binding.autoCompleteTxtJob.setAdapter(holder.jobArrayAdapter);
                } else {
                    holder.binding.autoCompleteTxtJob.setAdapter(null);
                }
            });
        }
    }
}

适配器Item的XML文件

<?xml version="1.0" encoding="utf-8"?>

<layout 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">

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

        <androidx.appcompat.widget.LinearLayoutCompat
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical"
            app:layout_constraintTop_toTopOf="parent"
            tools:layout_editor_absoluteX="0dp">


            <androidx.appcompat.widget.LinearLayoutCompat
                android:layout_width="match_parent"
                android:layout_height="@dimen/_25sdp"
                android:orientation="horizontal">

                <androidx.appcompat.widget.AppCompatTextView
                    style="@style/txtJobDetailRowLeft"
                    android:text="@string/lbl_job" />

                <androidx.appcompat.widget.AppCompatAutoCompleteTextView
                    android:id="@+id/autoCompleteTxtJob"
                    android:layout_width="0dp"
                    android:layout_height="match_parent"
                    android:layout_weight="6"
                    android:background="@drawable/bg_et_first"
                    android:gravity="center_vertical"
                    android:inputType="text"
                    android:paddingLeft="@dimen/_5sdp"
                    android:singleLine="true"
                    android:textColor="@color/black"
                    android:textSize="@dimen/_9sdp" />
            </androidx.appcompat.widget.LinearLayoutCompat>

            <androidx.appcompat.widget.LinearLayoutCompat
                android:layout_width="match_parent"
                android:layout_height="@dimen/_25sdp"
                android:layout_marginTop="@dimen/_5sdp"
                android:orientation="horizontal">

                <androidx.appcompat.widget.AppCompatTextView
                    style="@style/txtJobDetailRowLeft"
                    android:text="@string/lbl_staff_name" />

                <androidx.appcompat.widget.AppCompatTextView
                    android:id="@+id/txtStaffName"
                    style="@style/txtJobDetailRowRight" />

            </androidx.appcompat.widget.LinearLayoutCompat>

        </androidx.appcompat.widget.LinearLayoutCompat>
    </androidx.constraintlayout.widget.ConstraintLayout>
</layout>

解决方案

问题根源分析

  • NestedScrollView与RecyclerView的嵌套冲突:RecyclerView被包裹在NestedScrollView中,会导致AutoCompleteTextView的下拉弹窗无法计算正确的显示位置,出现被遮挡或不显示的情况。
  • 焦点监听逻辑的问题:失去焦点时清空适配器,会导致再次获取焦点时适配器重绑不及时;仅在获取焦点时设置适配器,无法保证输入时弹窗正常触发。
  • RecyclerView复用机制的影响:ViewHolder复用可能导致AutoCompleteTextView的状态混乱,适配器没有正确绑定到当前Item。

修改步骤

1. 移除NestedScrollView对RecyclerView的包裹

直接让RecyclerView在ConstraintLayout中布局,避免滚动容器嵌套导致的布局计算错误:

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">
    <data>
        <variable
            name="viewModel"
            type="com..job..i.viewModel.job.JobViewModel" />
        <import type="android.view.View" />
    </data>

    <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <androidx.appcompat.widget.LinearLayoutCompat
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:background="@color/screenBG"
            android:orientation="vertical"
            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintStart_toStartOf="parent">

                <androidx.recyclerview.widget.RecyclerView
                    android:id="@+id/rvSupervisor"
                    android:layout_width="match_parent"
                    android:layout_height="match_parent"
                    tools:itemCount="1"
                    tools:listitem="@layout/job_filter_adapter" />
        </androidx.appcompat.widget.LinearLayoutCompat>
    </androidx.constraintlayout.widget.ConstraintLayout>
</layout>

2. 调整适配器中的AutoCompleteTextView绑定逻辑

去掉焦点监听中设置/清除适配器的逻辑,直接在ViewHolder初始化时绑定适配器,并添加文本变化监听确保弹窗触发:

class AdapterHolder extends RecyclerView.ViewHolder {
    private final RowJobBinding binding;
    JObWatcher jobWatcher;
    ArrayAdapter jobArrayAdapter;

    public AdapterHolder(@NonNull RowJobBinding _binding, JObWatcher _jobWatcher) {
        super(_binding.getRoot());
        binding = _binding;
        jobWatcher = _jobWatcher;

        jobArrayAdapter = new ArrayAdapter(_activity, R.layout.row_job_item, jobList);
        binding.autoCompleteTxtJob.setThreshold(1);
        // 直接绑定适配器,无需在焦点变化时重复设置
        binding.autoCompleteTxtJob.setAdapter(jobArrayAdapter);
        
        // 添加文本变化监听,确保输入达到阈值时显示弹窗
        binding.autoCompleteTxtJob.addTextChangedListener(new TextWatcher() {
            @Override
            public void beforeTextChanged(CharSequence s, int start, int count, int after) {}

            @Override
            public void onTextChanged(CharSequence s, int start, int before, int count) {
                if (s.length() >= binding.autoCompleteTxtJob.getThreshold()) {
                    binding.autoCompleteTxtJob.showDropDown();
                }
            }

            @Override
            public void afterTextChanged(Editable s) {}
        });
    }
}

同时删除JObWatcher中不必要的焦点监听逻辑:

public class JObWatcher {
    int position;
    AdapterHolder holder;

    private void updateState(int pos, AdapterHolder viewHolder) {
        position = pos;
        holder = viewHolder;
        // 移除manageAutoText调用及相关逻辑
    }
}

3. 处理RecyclerView复用的状态同步

在onBindViewHolder中更新适配器的过滤状态,避免复用旧数据导致的弹窗异常:

@Override
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, @SuppressLint("RecyclerView") int position) {
    AdapterHolder adapterHolder = (AdapterHolder) holder;
    
    StaffInfo model = _staffList.get(holder.getAdapterPosition());

    adapterHolder.binding.autoCompleteTxtJob.setText(model.getStaffNo(), false);
    adapterHolder.binding.txtStaffName.setText(model.getStaffName());
    
    // 同步当前文本的过滤状态,确保弹窗显示正确数据
    adapterHolder.jobArrayAdapter.getFilter().filter(adapterHolder.binding.autoCompleteTxtJob.getText());
    
    adapterHolder.jobWatcher.updateState(position, adapterHolder);
}

额外优化建议

  • 如果必须保留NestedScrollView,可给RecyclerView添加android:nestedScrollingEnabled="false"属性,但这会禁用RecyclerView自身的滚动能力,仅适合特殊场景。
  • 检查row_job_item布局的有效性,确保下拉项布局没有尺寸异常或不可见的问题。

内容的提问来源于stack exchange,提问作者Ninja

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.02 13:01:12