经过一个小时的编码、大量尝试和大量谷歌搜索,我已经制定了一个解决方案,可以满足您的需求。它使用反射来访问下拉菜单中的 ListView,并在您离开活动时访问下拉状态。
此代码有点长,所以我将引导您完成所有部分。首先,我需要一些变量:
boolean wasDropdownOpen;
int oldDropdownY;
Handler handler;
处理程序稍后将是必需的,因为我们必须在 onResume() 方法中做一些小技巧。在你的 onCreate() 方法中像往常一样初始化它:
handler = new Handler(getMainLooper());
现在,让我们进入棘手的部分。
您需要在开始任何活动之前调用以下方法。它不能在onPause() 中完成,因为在调用此方法时下拉菜单已经关闭。在我的测试代码中,我重写了 startActivity() 和 startActivityForResult() 方法,并在那里调用了它,但您可以随意执行此操作。
private void processBeforeStart() {
ListPopupWindow window = getWindow(textView);
if(window == null) return;
wasDropdownOpen = window.isShowing();
ListView lv = getListView(window);
if(lv == null) return;
View view = lv.getChildAt(0);
oldDropdownY = -view.getTop() + lv.getFirstVisiblePosition() * view.getHeight();
}
这将保存您的下拉列表视图的状态以备后用。现在,我们将加载它。这是我们需要的onResume() 方法:
@Override
protected void onResume() {
super.onResume();
if (wasDropdownOpen)
textView.showDropDown();
handler.postDelayed(new Runnable() {
@Override
public void run() {
ListView lv = getListView(getWindow(textView));
if (lv != null)
scrollToY(lv, oldDropdownY);
}
}, 150);
}
首先,让我解释一下这个方法。如果下拉菜单打开,我们会保存状态,所以如果菜单打开,我们会重新打开。简单的。下一部分是滚动。我们需要在 Handler 中执行此操作,因为调用 onResume() 时 UI 尚未完全加载,因此仍然无法访问 ListView。
您看到的scrollToY() 方法是this post 代码的修改版本,因为Android 的ListView 没有内置方法来精确地设置滚动位置。
该方法的实现如下:
private void scrollToY(ListView lv, int position) {
int itemHeight = lv.getChildAt(0).getHeight();
int item = (int) Math.floor(position / itemHeight);
int scroll = (item * itemHeight) - position;
lv.setSelectionFromTop(item, scroll);// Important
}
现在,您可能已经看到了我在上面使用的getWindow() 和getListView() 方法。这些是我们必须使用的反射方法,因为 Android 没有公开公共 API 来访问 ListPopupWindow 的 AutoCompleteTextView 内的 ListView。此外,DropDownListView 是 ListView 的子类,实际在该对象中使用,对于外部也不可见,因此我们必须再次使用反射。
这是我的两个辅助方法的实现:
private ListView getListView(ListPopupWindow window) {
for (Field field : window.getClass().getDeclaredFields()) {
if (field.getType().getName().equals("android.widget.DropDownListView")) {
field.setAccessible(true);
try {
return (ListView) field.get(window);
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
return null;
}
private ListPopupWindow getWindow(AutoCompleteTextView tv) {
Class realClass = tv.getClass().getName().contains("support") ? tv.getClass().getSuperclass() : tv.getClass();
for (Field field : realClass.getDeclaredFields()) {
if (field.getType().getName().equals(ListPopupWindow.class.getName())) {
field.setAccessible(true);
try {
return (ListPopupWindow) field.get(tv);
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
return null;
}
我已经在 Android O(API 级别 26)上对此进行了测试,它的工作原理与您描述的一样。
我希望我在这个答案中付出的努力让我有机会获得赏金;-)