In my Android app I have an EditText
. When the EditText
is focused, a PopupWindow
is shown, which contains a ListView
. The user can continue typing in the EditText
when the PopupWindow
is on screen, and in the mean time he/she should be able to click an item on the ListView
to dismiss the PopupWindow
. (Depending on which ListView
item is clicked, in addition to dismissing the PopupWindow
something else should also happen, but it's irrelevant here.)
The problem is, although the "continue typing" part works, the "click an item" part doesn't, because the OnItemClickListener
of the ListView
never gets called, and I can't figure out why.
Here's my activity_main.xml
:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#ddd"
android:focusableInTouchMode="true"
tools:context="com.example.popuptest3.MainActivity" >
<EditText
android:id="@+id/edtPhone"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="phone" />
</RelativeLayout>
My popup_window.xml
:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#fff" >
<ListView
android:id="@+id/lstItems"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_marginBottom="60dp" />
<Button
android:id="@+id/btnDismiss"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:text="Dismiss" />
</RelativeLayout>
My list_item.xml
:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="50dp" >
<TextView
android:id="@+id/txtItem"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center_vertical"
android:text="Item Text"
android:textAppearance="?android:attr/textAppearanceMedium" />
</RelativeLayout>
In my MainActivity
class I have the following preparation code:
private PopupWindow popup = null;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
prepareControls();
}
private void prepareControls() {
final EditText edtPhone = (EditText)findViewById(R.id.edtPhone);
edtPhone.setOnFocusChangeListener(new OnFocusChangeListener() {
@Override
public void onFocusChange(View v, boolean hasFocus) {
if (hasFocus)
openPopup(edtPhone);
else
closePopup();
}
});
}
That is, I open the PopupWindow
when edtPhone
gets focus, and close the PopupWindow
when edtPhone
loses focus. Then I have:
private void openPopup(View parent) {
closePopup();
// Inflate the view of the PopupWindow.
LayoutInflater layoutInflater = LayoutInflater.from(this);
View view = layoutInflater.inflate(R.layout.popup_window,
new LinearLayout(this), false);
final Activity activity = this;
// Prepare the ListView.
ListView lstItems = (ListView)view.findViewById(R.id.lstItems);
lstItems.setAdapter(new ListAdapter(this));
lstItems.setOnItemClickListener(new OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view,
int position, long id) {
hideKeyboardAndClearFocus(activity);
}
});
// Prepare the Button.
Button btnDismiss = (Button)view.findViewById(R.id.btnDismiss);
btnDismiss.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
hideKeyboardAndClearFocus(activity);
}
});
// Create and show the PopupWindow.
popup = new PopupWindow(view, 400, 300, false);
popup.showAtLocation(parent, Gravity.LEFT | Gravity.TOP, 0, 60);
}
The btnDismiss
button is not part of my plan; I add it here just for demonstration purposes. Finally I have:
private void closePopup() {
if (popup != null) {
popup.dismiss();
popup = null;
}
}
private static void hideKeyboardAndClearFocus(Activity activity) {
InputMethodManager manager = (InputMethodManager)activity.
getSystemService(Activity.INPUT_METHOD_SERVICE);
manager.hideSoftInputFromWindow(
activity.getCurrentFocus().getWindowToken(), 0);
activity.getWindow().getDecorView().clearFocus();
}
I think this doesn't require explanation, and the ListAdapter
class is quite standard so I omit it.
Now, when I click on edtPhone
, it gets focus, the soft keyboard shows up, and the PopupWindow
opens. I can type something into edtPhone
, and when I click on btnDismiss
, edtPhone
loses focus, the soft keyboard is dismissed, and the PopupWindow
closes, all as expected. But if instead of btnDismiss
I click on an item on lstItems
, nothing happens. Using Log
I can see that OnItemClickListener
is not called. The funny thing is, the ListView
can be scrolled well, it just cannot be clicked.
I know this post but that solution doesn't work for my purpose. If I change this line:
popup = new PopupWindow(view, 400, 300, false);
to the following:
popup = new PopupWindow(view, 400, 300, true);
the PopupWindow
becomes focusable and the ListView
becomes clickable, alright, but then I cannot continue typing into edtPhone
. In fact, if there are other controls on the activity, they all become unreachable, as if the PopupWindow
is "modal".
I also tried android:focusable="false"
, no luck. And I'm not doing auto-complete so AutoCompleteTextView
isn't what I need.
So why is OnItemClickListener
not called on non-focusable PopupWindow
? Am I doing anything wrong?
set the popupwindow to non-focusable
extend the ListView and override the following methods
This is how AutoCompleteTextView implements the popup for suggestions. If you need to select the list item using DPAD keys or other navigation keys , then you need to pass the key events from the EditText to the ListView.