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

如何为带单选列表的AlertDialog添加搜索EditText功能?

问题描述

现有一个AlertDialog.Builder,搭配android.R.layout.select_dialog_singlechoice的ArrayAdapter实现单选列表,对话框底部有3个按钮。尝试添加带搜索功能的EditText时,运行后对话框底部按钮全部消失,EditText也不可见。

问题原因分析

  1. 布局覆盖与遮挡:调用builderSingle.setSingleChoiceItems()后再调用setView(),会替换AlertDialog默认的内容区域(单选列表);同时自定义布局的根LinearLayout设置了layout_height="match_parent",会占满整个对话框空间,直接遮挡底部按钮区域。
  2. 布局结构缺失:自定义布局仅包含EditText,未保留单选列表的容器,导致原有单选列表完全消失。

解决方案

步骤1:创建包含搜索框+单选列表的自定义布局

新建布局文件dialog_search_single_choice.xml,将搜索输入框与单选列表垂直排列,限制高度避免遮挡按钮:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical"
    android:padding="16dp">

    <!-- 搜索输入框 -->
    <EditText
        android:id="@+id/et_search"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="搜索跑步记录"
        android:inputType="text" />

    <!-- 单选列表容器(设置固定高度避免占满对话框) -->
    <ListView
        android:id="@+id/lv_single_choice"
        android:layout_width="match_parent"
        android:layout_height="250dp"
        android:choiceMode="singleChoice" />

</LinearLayout>

步骤2:重构AlertDialog代码逻辑

不再依赖builder.setSingleChoiceItems(),改为通过自定义布局的ListView实现单选,同时保留底部按钮并添加搜索过滤:

DatabaseHandler db = new DatabaseHandler(this);
List<Run> allEntries = db.getAllEntriesOrderedByRunNumber();
int checkedItem = 0;
final int[] whichItemChecked = new int[1];

if (mPolylinePoints.size() > 0) {
    mPolylinePoints.clear();
}

AlertDialog.Builder builderSingle = new AlertDialog.Builder(MapsActivity.this);

// 设置标题与图标
if (allEntries.size() == 0) {
    builderSingle.setTitle(getResources().getString(R.string.no_run_available));
} else {
    builderSingle.setTitle(getResources().getString(R.string.select_one_run));
}
builderSingle.setIcon(R.drawable.icon_notification);
builderSingle.setCancelable(true);

// 初始化列表适配器
final ArrayAdapter<String> arrayAdapter = new ArrayAdapter<>(MapsActivity.this, android.R.layout.select_dialog_singlechoice);
for (int i = 0; i < allEntries.size(); i++) {
    int count = db.countDataOfRun(allEntries.get(i).getNumber_of_run());
    arrayAdapter.add(allEntries.get(i).getNumber_of_run() + ": " + allEntries.get(i).getDateTime() + "\n"
            + count + " points to load");
}

// 加载自定义布局
LayoutInflater inflater = this.getLayoutInflater();
View dialogView = inflater.inflate(R.layout.dialog_search_single_choice, null);
builderSingle.setView(dialogView);

// 绑定单选列表并设置选中逻辑
ListView lvSingleChoice = dialogView.findViewById(R.id.lv_single_choice);
lvSingleChoice.setAdapter(arrayAdapter);
lvSingleChoice.setSelection(checkedItem);
whichItemChecked[0] = checkedItem;
lvSingleChoice.setOnItemClickListener(new AdapterView.OnItemClickListener() {
    @Override
    public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
        whichItemChecked[0] = position;
    }
});

// 添加搜索过滤功能
EditText etSearch = dialogView.findViewById(R.id.et_search);
etSearch.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) {
        arrayAdapter.getFilter().filter(s);
    }

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

// 设置底部按钮(保留原有业务逻辑)
if (allEntries.size() > 0) {
    builderSingle.setNegativeButton(getResources().getString(R.string.buttonWithoutColoring), new DialogInterface.OnClickListener() {
        @Override
        public void onClick(DialogInterface dialog, int which) {
            // 原有逻辑不变
            int numberOfRun = allEntries.get(whichItemChecked[0]).getNumber_of_run();
            final LatLng[] latLng = new LatLng[1];
            ExecutorService executor = Executors.newSingleThreadExecutor();
            Handler handler = new Handler(Looper.getMainLooper());
            executor.execute(new Runnable() {
                @Override
                public void run() {
                    List<Run> allEntries = db.getSingleEntryOrderedByDateTime(numberOfRun);
                    for (int i = 0; i < allEntries.size(); i++) {
                        latLng[0] = new LatLng(allEntries.get(i).getLat(), allEntries.get(i).getLng());
                        mPolylinePoints.add(latLng[0]);
                    }
                    handler.post(new Runnable() {
                        @Override
                        public void run() {
                            mMap.clear();
                            drawView.setVisibility(View.INVISIBLE);
                            textViewSlow.setVisibility(View.INVISIBLE);
                            textViewFast.setVisibility(View.INVISIBLE);
                            mMap.addMarker(new MarkerOptions()
                                    .position(new LatLng(mPolylinePoints.get(0).latitude, mPolylinePoints.get(0).longitude))
                                    .title(getString(R.string.starting_position)));
                            polyline = mMap.addPolyline(new PolylineOptions().addAll(mPolylinePoints).color(Color.MAGENTA).jointType(JointType.ROUND).width(15.0f));
                            createCheckerFlag(mPolylinePoints);
                        }
                    });
                }
            });
        }
    });

    builderSingle.setNeutralButton("Show", new DialogInterface.OnClickListener() {
        @Override
        public void onClick(DialogInterface dialogInterface, int i) {
            // 原有逻辑不变
            int numberOfRun = allEntries.get(whichItemChecked[0]).getNumber_of_run();
            final LatLng[] latLng = new LatLng[1];
            ExecutorService executor = Executors.newSingleThreadExecutor();
            Handler handler = new Handler(Looper.getMainLooper());
            executor.execute(new Runnable() {
                @Override
                public void run() {
                    List<Run> allEntries = db.getSingleEntryOrderedByDateTime(numberOfRun);
                    List<ColoredPoint> sourcePoints = new ArrayList<>();
                    for (int i = 0; i < allEntries.size(); i++) {
                        latLng[0] = new LatLng(allEntries.get(i).getLat(), allEntries.get(i).getLng());
                        if (allEntries.get(i).getSpeed() > 8) {
                            sourcePoints.add(new ColoredPoint(latLng[0], Color.GREEN));
                        } else if (allEntries.get(i).getSpeed() > 6 && allEntries.get(i).getSpeed() < 8) {
                            sourcePoints.add(new ColoredPoint(latLng[0], Color.YELLOW));
                        } else {
                            sourcePoints.add(new ColoredPoint(latLng[0], Color.RED));
                        }
                        mPolylinePoints.add(latLng[0]);
                    }
                    handler.post(new Runnable() {
                        @Override
                        public void run() {
                            showPolyline(sourcePoints);
                        }
                    });
                }
            });
        }
    });

    builderSingle.setPositiveButton("Update", new DialogInterface.OnClickListener() {
        @Override
        public void onClick(DialogInterface dialogInterface, int i) {
            // 原有逻辑不变
            String numberOfRun = arrayAdapter.getItem(whichItemChecked[0]);
            String[] splittedString = numberOfRun.split(":");
            int intNumberOfRun = Integer.parseInt(splittedString[0]);
            List<Run> run = db.getLastCommentEntryOfSelectedRun(intNumberOfRun);

            final EditText edittext = new EditText(MapsActivity.this);
            edittext.setHint(run.get(0).getComment());

            AlertDialog.Builder builder = new AlertDialog.Builder(MapsActivity.this);
            builder.setCancelable(true);
            builder.setTitle("Enter your new comment here");
            builder.setView(edittext);
            builder.setPositiveButton(
                    "Update",
                    new DialogInterface.OnClickListener() {
                        public void onClick(DialogInterface dialog, int id) {
                            db.updateCommentById(intNumberOfRun, edittext.getText().toString());
                            Toast.makeText(getApplicationContext(), getResources().getString(R.string.update_entry), Toast.LENGTH_LONG).show();
                        }
                    });
            builder.setNegativeButton(
                    "Delete",
                    new DialogInterface.OnClickListener() {
                        public void onClick(DialogInterface dialog, int id) {
                            db.deleteSingleEntry(intNumberOfRun);
                            Toast.makeText(getApplicationContext(), getResources().getString(R.string.single_entry_deleted), Toast.LENGTH_LONG).show();
                        }
                    });
            AlertDialog alert = builder.create();
            alert.show();
        }
    });
} else {
    builderSingle.setNegativeButton(getResources().getString(R.string.buttonCloseDialog), new DialogInterface.OnClickListener() {
        @Override
        public void onClick(DialogInterface dialog, int which) {
            dialog.cancel();
        }
    });
}

AlertDialog alertDialog = builderSingle.create();
alertDialog.show();

关键说明

  • 布局高度控制:自定义布局根容器使用wrap_content,ListView设置固定高度,避免占满对话框空间,保证底部按钮可见。
  • 单选逻辑迁移:通过ListView的choiceMode="singleChoice"实现单选,手动监听点击事件记录选中项,替代原setSingleChoiceItems()方法。
  • 搜索过滤:利用ArrayAdapter自带的Filter功能,监听EditText输入自动过滤列表内容,无需额外编写过滤逻辑。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.02 09:15:55