如何从启动的Activity返回时保留AutoCompleteTextView的下拉状态
解决AutoCompleteTextView返回后保留下拉状态及滚动位置的问题
我完全懂你遇到的这个麻烦——从新Activity返回后,不仅要让AutoCompleteTextView的下拉框保持显示,还要停留在之前滚动到的位置,而不是直接跳回列表顶部。之前你尝试的showDropDown()能让下拉框重新出现,但没处理滚动位置的恢复,这就是核心问题所在。下面给你一套可行的解决方案:
问题根源
AutoCompleteTextView的下拉列表本质是嵌套在PopupWindow里的一个ListView。当你启动新Activity时,原Activity的视图会进入后台,下拉框的PopupWindow会被销毁;返回时调用showDropDown()会重新创建这个PopupWindow和内部的ListView,此时ListView的滚动状态没有被保存,自然会重置到顶部。
解决方案:保存+恢复滚动位置
我们需要在启动新Activity前保存ListView的滚动状态,返回后再精准恢复这个位置,具体步骤如下:
1. 保存下拉列表的滚动位置
在跳转目标Activity之前,获取下拉ListView的当前滚动状态(包括可见项的位置和偏移量),保存到全局变量中:
private int mDropDownFirstVisiblePos = 0; private int mDropDownTopOffset = 0; // 保存滚动位置的方法 private void saveDropDownScrollState(AutoCompleteTextView actv) { ListView dropDownListView = getDropDownListView(actv); if (dropDownListView != null && dropDownListView.getChildCount() > 0) { // 获取第一个可见项的位置 mDropDownFirstVisiblePos = dropDownListView.getFirstVisiblePosition(); // 获取第一个可见项相对于ListView顶部的偏移量(保证恢复精度) View firstVisibleView = dropDownListView.getChildAt(0); mDropDownTopOffset = firstVisibleView.getTop() - dropDownListView.getPaddingTop(); } } // 兼容API 26以下的ListView获取方法(API 26+可直接用actv.getDropDownListView()) private ListView getDropDownListView(AutoCompleteTextView actv) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { return actv.getDropDownListView(); } // 低版本通过反射获取内部的ListView try { Field mPopupField = AutoCompleteTextView.class.getDeclaredField("mPopup"); mPopupField.setAccessible(true); Object popup = mPopupField.get(actv); Field mListViewField = popup.getClass().getDeclaredField("mListView"); mListViewField.setAccessible(true); return (ListView) mListViewField.get(popup); } catch (NoSuchFieldException | IllegalAccessException e) { e.printStackTrace(); return null; } }
2. 启动Activity前调用保存方法
在跳转到新Activity的逻辑中,先保存滚动状态,再执行跳转:
private static final int REQUEST_TARGET_ACTIVITY = 1001; // 下拉项点击事件 mSearchSrcTextView.setOnItemClickListener((parent, view, position, id) -> { // 先保存当前滚动位置 saveDropDownScrollState(mSearchSrcTextView); // 启动目标Activity Intent intent = new Intent(this, TargetActivity.class); startActivityForResult(intent, REQUEST_TARGET_ACTIVITY); });
3. 返回后恢复滚动位置
在onActivityResult中,先显示下拉框,再通过保存的状态精准恢复滚动位置:
@Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if (requestCode == REQUEST_TARGET_ACTIVITY) { // 先让下拉框重新显示 mSearchSrcTextView.showDropDown(); // 延迟执行恢复逻辑(确保下拉框已经完全创建完成) mSearchSrcTextView.post(() -> { ListView dropDownListView = getDropDownListView(mSearchSrcTextView); if (dropDownListView != null && mDropDownFirstVisiblePos >= 0) { // 恢复到之前的滚动位置和偏移量 dropDownListView.setSelectionFromTop(mDropDownFirstVisiblePos, mDropDownTopOffset); } }); } }
额外提示
- 如果你的AutoCompleteTextView的Adapter数据在Activity切换期间发生了变化,恢复滚动位置可能没有意义,需要先确保数据和离开时完全一致。
- 关于
windowSoftInputMode的设置,保持stateUnchanged可以保留键盘的状态,配合上述滚动位置恢复,整体体验会更流畅。
内容的提问来源于stack exchange,提问作者Cheok Yan Cheng
相关产品推荐
相关产品推荐

