【问题标题】:Android non modal PopupWindowAndroid非模态PopupWindow
【发布时间】:2015-04-13 09:44:50
【问题描述】:

请注意:这个问题是关于 Android PopupWindow,而不是 Dialog。

我正在尝试将 Android PopupWindow 设为非模式:

  • 单击窗口的内部时,我希望窗口的视图能够正常响应单击
  • 当点击窗口外时,我希望窗口外的其他图形元素正常接收点击(我的意思是 MotionEvent),就像没有显示 PopupWindow 一样。

我已经在 PopupWindow 的内容视图上设置了触摸侦听器,以测试事件是否在 PopupWindow 之外,如果是则返回 false。我希望 MotionEvent 被传播到我单击的视图。但似乎由于这些视图位于当前窗口之外,因此它们不会收到该事件。

如何将事件传播到我单击的视图,即使它位于 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;
            }
        }
    };
}

}

【问题讨论】:

    标签: android popupwindow


    【解决方案1】:

    试试这个:

    setOutsideTouchable(true);

    在你的构造函数中调用它

    【讨论】:

      【解决方案2】:

      只是对 DialogFragment peradventure 的补充,您不想使用活动或 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>
      

      可绘制文件夹中的透明背景

      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;
          }
      }
      

      然后在你的activity中添加界面

      implements  photoChooserFragment.onItemSelectedListener
      

      并确保实施

       @Override
          public  void onItemSelected(int position){
              switch (position){
                  case 1: //camera
                      GetImageFromCamera();
                      break;
                  case 2: //gallery
                      ChooseImageFromGallery();
                      break;
              }
          }
      

      现在你可以调用片段了,一个按钮就可以了,在我的我使用了一个浮动按钮

      faBtnCamera.setOnClickListener(new View.OnClickListener() {
                  @Override
                  public void onClick(View v) {
                      //Show menu
                      photoChooserFragment dialog = new photoChooserFragment();
                      dialog.show(getSupportFragmentManager(), "chooser");
                  }
              });
      

      【讨论】:

        【解决方案3】:

        对于 >=29 的 Android 版本,您可以使用以下命令告诉 PopupWindow 将触摸传输到其背后的视图

        myPopup.setTouchModal(false);

        触摸通过,弹出窗口保持不变。

        我不知道这是否能让您也触摸弹出窗口的内部,因为我的弹出窗口没有控件。但这仍然是一个比使用大量听众更清洁的解决方案......

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2023-03-12
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多