Reputation: 3689
Please note: This issue is about Android PopupWindow, not Dialog.
I'm trying to make an Android PopupWindow non modal:
I've set the touch listener on the content view in the PopupWindow to test if the event is outside of the PopupWindow, and if so to return false. I would expect then the MotionEvent to be propagated to the view where I clicked. But it seems that since those views are outside of the current window then they don't receive the event.
How can I propagate the event to the view located where I clicked even if it's outside of the PopupWindow?
public class NonModalPopupWindow extends PopupWindow {
private static final String TAG = "NonModalPopupWindow";
public NonModalPopupWindow(View contentView, int width, int height) {
super(width, height);
setContentView(contentView);
contentView.setOnTouchListener(createOnTouchListener());
setFocusable(true);
}
private View.OnTouchListener createOnTouchListener() {
return new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
final int x = (int) event.getX();
final int y = (int) event.getY();
final boolean isTouchOutside = (x < 0) || (x >= getWidth()) || (y < 0) || (y >= getHeight());
if (isTouchOutside || event.getAction() == MotionEvent.ACTION_OUTSIDE) {
Log.e(TAG, "Touched OUTSIDE");
// How to propagate this event so that it's received by the View shown
// At the location where I clicked, outside of the PopupWindow?
return false;
} else {
Log.e(TAG, "Touched INSIDE");
return true;
}
}
};
}
}
Upvotes: 2
Views: 1291
Reputation: 5343
For Android versions >=29, you can tell the PopupWindow to transmit touches to the view behind it using
myPopup.setTouchModal(false);
The touch goes thru, and the popup stays up.
I don't know if that lets you ALSO touch INSIDE the popup, because my popup has no controls. But it's still a cleaner solution than playing with lots of Listeners...
Upvotes: 0
Reputation: 59
Just an addition for DialogFragment peradventure you don't want to use an activity or Theme.Dialog
Chooser.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/main_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_margin="@dimen/activity_horizontal_margin"
android:background="@drawable/dialog_bg">
<RelativeLayout
android:id="@+id/layout_Camera"
android:layout_width="0dp"
android:layout_weight = "0.25"
android:layout_height="wrap_content">
<ImageView
android:id="@+id/camera"
android:layout_width="32dp"
android:layout_height="32dp"
android:layout_centerHorizontal="true"
android:src="@drawable/ic_menu_camera_holo_dark" />
<TextView
android:id="@+id/tvCamera"
android:layout_margin="@dimen/margin_very_small"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:textAlignment="center"
android:layout_below="@id/camera"
android:text="Camera"/>
</RelativeLayout>
<RelativeLayout
android:id="@+id/layout_Gallery"
android:layout_width="0dp"
android:layout_weight ="0.25"
android:layout_height="wrap_content">
<ImageView
android:id="@+id/gallery"
android:layout_width="32dp"
android:layout_height="32dp"
android:layout_centerHorizontal="true"
android:src="@drawable/ic_menu_photo_gallery" />
<TextView
android:id="@+id/tvGallery"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:textAlignment="center"
android:layout_below="@id/gallery"
android:text="Gallery"/>
</RelativeLayout>
<RelativeLayout
android:id="@+id/layout_RemovePhoto"
android:layout_width="0dp"
android:layout_weight="0.25"
android:layout_height="wrap_content">
<ImageView
android:id="@+id/removePhoto"
android:layout_width="32dp"
android:layout_height="32dp"
android:layout_centerHorizontal="true"
android:src="@drawable/ic_menu_remove"/>
<TextView
android:id="@+id/tvRemovePhoto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:textAlignment="center"
android:layout_below="@id/removePhoto"
android:text="Remove Photo"/>
</RelativeLayout>
</LinearLayout>
Transparent background in the drawable folder
dialog_bg.xml
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid
android:color="@color/off_white"/>
<corners
android:radius="15dp" />
<padding
android:left="20dp"
android:top="20dp"
android:right="20dp"
android:bottom="20dp" />
<margin
android:left="50dp"
android:bottom="50dp"
android:right="50dp"
android:top="50dp"
/>
</shape>
PhotoChooserFragment
public class photoChooserFragment
extends DialogFragment {
onItemSelectedListener listener;
ImageView imgCamera, imgGallery, imgRemovePhoto;
TextView tvCamera, tvGallery, tvRemovePhoto;
public interface onItemSelectedListener {
void onItemSelected(int position);
}
public void onItemSelected(int position) {
listener.onItemSelected(position);
}
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
// Activities containing this fragment must implement its listener.
if (!(activity instanceof onItemSelectedListener)) {
throw new IllegalStateException(
"Activity must implement fragment's callbacks.");
}
listener = (onItemSelectedListener) activity;
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.chooser, null, false);
imgCamera = view.findViewById(R.id.camera);
imgGallery = view.findViewById(R.id.gallery);
imgRemovePhoto = view.findViewById(R.id.removePhoto);
tvCamera = view.findViewById(R.id.tvCamera);
tvGallery = view.findViewById(R.id.tvGallery);
tvRemovePhoto = view.findViewById(R.id.tvRemovePhoto);
Window window = getDialog().getWindow();
window.requestFeature(Window.FEATURE_NO_TITLE);
window.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
WindowManager.LayoutParams windowLP = window.getAttributes();
//window.setFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL,
// WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL);
window.addFlags(WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH);
//window.clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);
window.setGravity(Gravity.BOTTOM);
windowLP.gravity = Gravity.BOTTOM;
window.setAttributes(windowLP);
getDialog().setCanceledOnTouchOutside(true);
return view;
}
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
imgCamera.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
dismiss();
onItemSelected(1);
}
});
tvCamera.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
dismiss();
onItemSelected(1);
}
});
imgGallery.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
dismiss();
onItemSelected(2);
}
});
tvGallery.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
dismiss();
onItemSelected(2);
}
});
imgRemovePhoto.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
dismiss();
onItemSelected(3);
}
});
tvRemovePhoto.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
dismiss();
onItemSelected(3);
}
});
}
@Override
public void onDetach() {
super.onDetach();
// Reset the active listener interface to null.
listener = null;
}
}
Then in your activity add the interface
implements photoChooserFragment.onItemSelectedListener
and ensure it is implemented
@Override
public void onItemSelected(int position){
switch (position){
case 1: //camera
GetImageFromCamera();
break;
case 2: //gallery
ChooseImageFromGallery();
break;
}
}
Now you can call the fragment, a button will do, in mine I used a floatingactionbutton
faBtnCamera.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//Show menu
photoChooserFragment dialog = new photoChooserFragment();
dialog.show(getSupportFragmentManager(), "chooser");
}
});
Upvotes: 0