目前,当我
Activity
的下拉列表AutoCompleteTextView
Activity
AutoCompleteTextView
的下拉隐藏。我想保留AutoCompleteTextView
的下拉状态,其中包括
Activity
当我从发起的AutoCompleteTextView
回来时,我不确定隐藏Activity
下拉列表的原因。因此,我尝试了两件事
windowSoftInputMode
的{{1}}从Activity
更改为stateAlwaysHidden
。stateUnchanged
中,当关闭已启动的onActivityResult
时,请明确执行Activity
。但是,我仍然面临着这个问题。不保留mSearchSrcTextView.showDropDown();
下拉列表的上一个滚动位置。它会重置回列表顶部。
这是屏幕截图,以更好地说明我面临的问题。
(当前AutoCompleteTextView的下拉列表滚动到结束。我点击最后一项并启动新的AutoCompleteTextView
)
(新Activity
已启动。现在,我点击 BACK 软键两次,关闭键盘,然后关闭Activity
)
(由于Activity
中mSearchSrcTextView.showDropDown();
的显式调用,再次显示下拉列表。但是,之前的滚动位置未被保留。列表的开头显示而不是结束列表)
我想知道,在关闭之前发布的onActivityResult
时,有没有办法保留AutoCompleteTextView的DropDown状态?
答案 0 :(得分:2)
对于AutoCompleteTextView
,它有一个名为dismissDropDown()
的方法。我相信当从新发布的活动回来时,这个功能正在被触发。因此,我们通过扩展AutoCompleteTextView
&来解决此问题。覆盖它dismissDropDown()
。
我们添加一个布尔标记temporaryIgnoreDismissDropDown
,以指示是否暂时忽略dismissDropDown
。
public class MyAutoCompleteTextView extends AutoCompleteTextView {
private boolean temporaryIgnoreDismissDropDown = false;
.....
@Override
public void dismissDropDown() {
if (this.temporaryIgnoreDismissDropDown) {
this.temporaryIgnoreDismissDropDown = false;
return;
}
super.dismissDropDown();
}
public void setTemporaryIgnoreDismissDropDown(boolean flag) {
this.temporaryIgnoreDismissDropDown = flag;
}
}
在启动新活动之前,我们将dismissDropDown
设置为true。从已启动的活动返回后,将调用dismissDropDown
。覆盖方法检查temporaryIgnoreDismissDropDown
是否为真,只需将其设置为false&没做什么。所以跳过真正的dismissDropDown
。
// myAutoCompleteTextView is instance of MyAutoCompleteTextView
myAutoCompleteTextView.setTemporaryIgnoreDismissDropDown(true);
// launch new Activity
startActivity(....);
希望这有帮助,祝你好运!
答案 1 :(得分:1)
经过一个小时的编码,大量的尝试和大量的Google搜索,我已经整理出了一个可以满足你想要的解决方案。它使用反射来访问下拉菜单中的ListView,并在您离开活动时访问下拉状态。
这段代码有点长,所以我将引导您完成所有部分。首先,我有一些我们需要的变量:
boolean wasDropdownOpen;
int oldDropdownY;
Handler handler;
稍后需要处理程序,因为我们必须在onResume()
方法中做一些小技巧。在onCreate()
方法中照常初始化:
handler = new Handler(getMainLooper());
现在,让我们来看看棘手的部分。
在开始任何活动之前,您需要调用以下方法。它不能在onPause()
中完成,因为在调用此方法时,Dropdown菜单已经关闭。在我的测试代码中,我已经覆盖了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();
}
这将保存您的下拉ListView的状态以供日后使用。现在,我们将加载它。这是我们需要的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
的一个子类,实际上在此对象中使用,对于oudside也是不可见的,所以我们必须再次使用Reflection。
以下是我的两个辅助方法的实现:
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)上对此进行了测试,它的工作原理就像您所描述的那样。
我希望我在这个答案中付出的努力让我有机会获得赏金; - )
答案 2 :(得分:0)
听起来你已经知道如何按需显示下拉菜单(通过showDropDown()
),所以我只会说明如何恢复下拉列表的滚动位置。
您可以访问下拉菜单的第一个可见位置,如下所示:
autocomplete.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
int firstVisiblePosition = parent.getFirstVisiblePosition();
// save this value somehow
}
});
保存此int
的值但是你想要(在内存中,通过onSaveInstanceState()
,将其传递给已启动的活动,以便它可以通过onActivityResult()
将其传回去,等等)。然后,无论您何时重新显示下拉列表,请执行以下操作:
autocomplete.showDropDown();
autocomplete.setListSelection(firstVisiblePosition);
这种技术的缺点在于它使firstVisiblePosition
处的项目完全可见,因此如果它在视线中间滚动,则列表位置将无法完美恢复。不幸的是,我不相信有任何方法可以保存/恢复此部分视图偏移。