fprg2 2023-04-25 19:24 采纳率: 0%
浏览 5

popupwindow,缩成竖条

Android中,popupWindow缩成一竖条是怎么回事?

  • 写回答

1条回答 默认 最新

  • CSDN-Ada助手 CSDN-AI 官方账号 2023-04-25 22:19
    关注
    • 你可以看下这个问题的回答https://ask.csdn.net/questions/361969
    • 这篇博客你也可以参考下:Android中popupwindow弹出灰色背景遇到的坑
    • 同时,你还可以查看手册:android PopupWindow 该类表示一个弹出式窗口,可用于显示一个 任意的视图。 中的内容
    • 除此之外, 这篇博客: 浅谈PopupWindow在Android开发中的使用中的 PopupWindow的使用 部分也许能够解决你的问题, 你可以仔细阅读以下内容或跳转源博客中阅读:
    • 其实PopupWindow的使用非常简单,总的来说分为两步:

      • 1、调用PopupWindow的构造器创建PopupWindow对象,并完成一些初始化设置。
      • 2、调用PopupWindow的showAsDropDown(View view)将PopupWindow作为View组件的下拉组件显示出来;或调用PopupWindow的showAtLocation()方法将PopupWindow在指定位置显示出来。
      PopupWindow popupWindow = new PopupWindow(this);
      popupWindow.setWidth(ViewGroup.LayoutParams.WRAP_CONTENT);
      popupWindow.setHeight(ViewGroup.LayoutParams.WRAP_CONTENT);
      popupWindow.setContentView(LayoutInflater.from(this).inflate(R.layout.layout_popupwindow_style01, null));
      popupWindow.setBackgroundDrawable(new ColorDrawable(0x00000000));
      popupWindow.setOutsideTouchable(false);
      popupWindow.setFocusable(true);
      

      其中,setWidth、setHeight和setContentView三者必须实现,否则将不会显示任何视图。 setwidth和setHeight的参数值可以是具体的数值,也可以是MATCH_PARENT或者是WRAP_CONTENT。setContentView则是为PopupWindow设置视图内容。 setFocusable顾名思义就是让PopupWindow获得焦点。 setBackgroundDrawable从字面理解就是为PopupWindow设置一个背景。 setOutsideTouchable则表示PopupWindow内容区域外的区域是否响应点击事件,Android官方给出的文档则表示点击内容区域外的区域是否关闭窗口,那么设置为true应该就是表示关闭,设置为false就是表示不关闭咯! 那么我们就动手试一下吧,验证一下是不是和我们想象的相吻合:

      QQ截图20160509191045.png

      实验结果似乎和我们想象的不太一样,于是试着上网找找结果看得出如下结论:setFocusable确实是让PopupWindow获得焦点,获得焦点的PopupWindow能够处理物理按钮的点击事件,否则点击事件将向上传递由Activity处理,这也能够解释为什么在setFocusable(false)的情况下点击返回按钮会退出当前Activity。关于焦点设置需要注意的一点是:*如果PopupWindow中有Editor的话,focusable必须要为true。*

      可是还是有一点我似乎不太明白,为什么设置setOutsideTouchable(true),点击外部区域还是不会关闭窗口呢,这似乎与Google官方给出的解释有点出入,于是试着从源码寻找答案:

      源码截图

      不看不知道,原来另有玄机,外部点击事件的响应还backgroundDrawable有关,在backgroundDrawable!=null的情况下,PopupWindow会以backgroundDrawable作为背景生成一个根据contentView和backgroundDrawable生成一个PopupBackgroundView并返回,而如果在backgroundDrawable==null的情况下,则直接返回contentView。于是乎接着往下搜索,原来PopupBackgroundView是一个内部私有类继承至FrameLayout,且该类完成了对onKey和onTouch事件的分发处理。因为contentView我们并没有进行onKey和onTouch事件的分发处理,所以在backgroundDrawable!=null的情况下,即使PopupWindow获得屏幕焦点,PopupWindow也不能处理物理按键的点击事件,因此就算点击返回按钮也会没有任何反应,更别说外部点击事件的响应了。这样也就能解释为什么在backgroundDrawable!=null的情况下点击返回键或者是点击外部区域都不会关闭窗口了,因此我们在使用PopupWindow的时候都会设置焦点并且再设置一个背景,但为了不影响显示效果可以设置一个全透明背景:

       setBackgroundDrawable(new ColorDrawable(0x00000000));
      

      但是,眼尖的朋友已经发现,还有一种情况似乎解释不通在setBackgroundDrawable(new ColorDrawable(0x00000000))、setOutsideTouchable(false)、setFocusable(true)的情况下,话说背景也有了,也设置焦点了,为什么setOutsideTouchable(false)点击外部区域还是会关闭窗口呢? 说实话看了半天源码也没能明白个啥意思,好吧,这可能也是Android的一个Bug,只能想办法去解决,于是我想着是否可以重写setOutsideTouchable方法和setContentView方法来解决问题呢。在setContentView的时候,使contentView获得焦点并添加按键监听事件,于是在任何情况下都能响应返回按钮的点击事件了。在setOutsideTouchable的时候判断为true的话就设置PopupWindow的backgroundDrawable,如果backgroundDrawable==null的话,就新建一个透明背景,也不影响显示效果。

      重写setContentView():

      @Override
      public void setContentView(View contentView) {
          if(contentView != null) {
              super.setContentView(contentView);
              contentView.setFocusable(true);   //
              contentView.setFocusableInTouchMode(true);   //
              contentView.setOnKeyListener(new View.OnKeyListener() {
      
                  @Override
                  public boolean onKey(View v, int keyCode, KeyEvent event) {
                      switch (keyCode) {
                          case KeyEvent.KEYCODE_BACK:
                              dismiss();
                              return true;
                          default:
                              break;
                      }
                      return false;
                  }
              });
          }
      }
      

      重写setOutsideTouchable():

      @Override
      public void setOutsideTouchable(boolean touchable) {
          super.setOutsideTouchable(touchable);
          if(touchable) {
              if(mBackgroundDrawable == null) {
                  mBackgroundDrawable = new ColorDrawable(0x00000000);
              }
              super.setBackgroundDrawable(mBackgroundDrawable);
          } else {
              super.setBackgroundDrawable(null);
          }
      }
      

      尝试着运行一遍, Bingo! 完美解决!!!

      PopupWindow的显示大致又可以分为两类:相对于视图中某个控件的相对位置(默认位于控件的正左下方)和相对于父控件的相对位置;

      相对于视图中某个控件的相对位置:

      • showAsDropDown(View anchor):相对某个控件的位置(正左下方),无偏移。
      • showAsDropDown(View anchor, int xoff, int yoff):相对某个控件的位置,同时可以设置偏移。
      • showAsDropDown(View anchor, int xoff, int yoff, int gravity):相对某个控件的位置,对齐方式(尝试过,但似乎没有效果),同时可以设置偏移。

      相对于父控件的相对位置:

      • showAtLocation(View parent, int gravity, int x, int y):相对于父控件的位置,同时可以设置偏移量。

      setOutsideTouchable.gif

      好了,关于PopupWindow的使用就介绍到这里。如果文中有什么叙述不当的地方,希望能够指出,期待您的意见,我们一起交流。最后附上我自己尝试去写的BasePopupWindow基类,包含窗口出现和消失的一个背景渐变动画,可以使窗口出现消失显得不那么生硬,BasePopupWindow:

      public class BasePopupWindow extends PopupWindow {
      
          private Context mContext;
          private float mShowAlpha = 0.88f;
          private Drawable mBackgroundDrawable;
      
          public BasePopupWindow(Context context) {
              this.mContext = context;
              initBasePopupWindow();
          }
      
          @Override
          public void setOutsideTouchable(boolean touchable) {
              super.setOutsideTouchable(touchable);
              if(touchable) {
                  if(mBackgroundDrawable == null) {
                      mBackgroundDrawable = new ColorDrawable(0x00000000);
                  }
                  super.setBackgroundDrawable(mBackgroundDrawable);
              } else {
                  super.setBackgroundDrawable(null);
              }
          }
      
          @Override
          public void setBackgroundDrawable(Drawable background) {
              mBackgroundDrawable = background;
              setOutsideTouchable(isOutsideTouchable());
          }
      
          /**
           * 初始化BasePopupWindow的一些信息
           * */
          private void initBasePopupWindow() {
              setAnimationStyle(android.R.style.Animation_Dialog);
              setHeight(ViewGroup.LayoutParams.WRAP_CONTENT);
              setWidth(ViewGroup.LayoutParams.WRAP_CONTENT);
              setOutsideTouchable(true);  //默认设置outside点击无响应
              setFocusable(true);
          }
      
          @Override
          public void setContentView(View contentView) {
              if(contentView != null) {
                  contentView.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED);
                  super.setContentView(contentView);
                  addKeyListener(contentView);
              }
          }
      
          public Context getContext() {
              return mContext;
          }
      
          @Override
          public void showAtLocation(View parent, int gravity, int x, int y) {
              super.showAtLocation(parent, gravity, x, y);
              showAnimator().start();
          }
      
          @Override
          public void showAsDropDown(View anchor) {
              super.showAsDropDown(anchor);
              showAnimator().start();
          }
      
          @Override
          public void showAsDropDown(View anchor, int xoff, int yoff) {
              super.showAsDropDown(anchor, xoff, yoff);
              showAnimator().start();
          }
      
          @Override
          public void showAsDropDown(View anchor, int xoff, int yoff, int gravity) {
              super.showAsDropDown(anchor, xoff, yoff, gravity);
              showAnimator().start();
          }
      
          @Override
          public void dismiss() {
              super.dismiss();
              dismissAnimator().start();
          }
      
          /**
           * 窗口显示,窗口背景透明度渐变动画
           * */
          private ValueAnimator showAnimator() {
              ValueAnimator animator = ValueAnimator.ofFloat(1.0f, mShowAlpha);
              animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
      
                  @Override
                  public void onAnimationUpdate(ValueAnimator animation) {
                      float alpha = (float) animation.getAnimatedValue();
                      setWindowBackgroundAlpha(alpha);
                  }
              });
              animator.setDuration(360);
              return animator;
          }
      
          /**
           * 窗口隐藏,窗口背景透明度渐变动画
           * */
          private ValueAnimator dismissAnimator() {
              ValueAnimator animator = ValueAnimator.ofFloat(mShowAlpha, 1.0f);
              animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
      
                  @Override
                  public void onAnimationUpdate(ValueAnimator animation) {
                      float alpha = (float) animation.getAnimatedValue();
                      setWindowBackgroundAlpha(alpha);
                  }
              });
              animator.setDuration(320);
              return animator;
          }
      
          /**
           * 为窗体添加outside点击事件
           * */
          private void addKeyListener(View contentView) {
              if(contentView != null) {
                  contentView.setFocusable(true);
                  contentView.setFocusableInTouchMode(true);
                  contentView.setOnKeyListener(new View.OnKeyListener() {
      
                      @Override
                      public boolean onKey(View view, int keyCode, KeyEvent event) {
                          switch (keyCode) {
                              case KeyEvent.KEYCODE_BACK:
                                  dismiss();
                                  return true;
                              default:
                                  break;
                          }
                          return false;
                      }
                  });
              }
          }
      
          /**
           * 控制窗口背景的不透明度
           * */
          private void setWindowBackgroundAlpha(float alpha) {
              Window window = ((Activity)getContext()).getWindow();
              WindowManager.LayoutParams layoutParams = window.getAttributes();
              layoutParams.alpha = alpha;
              window.setAttributes(layoutParams);
          }
      }
      
    • 以下回答由chatgpt基于相关博客总结生成:

      针对该问题,可以尝试以下解决方案:

      1.检查PopupWindow的布局文件是否正确,是否包含多个根元素。PopupWindow只支持单个根元素,因此需要将多个元素放在一个布局容器中,使用单个根元素。 2.检查布局文件中使用的控件是否在类中正确地被引用,使用findViewById()方法来查找View对象,并确保它们的ID值与布局文件中匹配。 3.检查PopupWindow是否正确地初始化和显示。调用PopupWindow构造函数时,需要传入一个View对象和PopupWindow的宽度和高度。在showAsDropDown()或showAtLocation()之前,需要调用setTouchable()和setOutsideTouchable()等必要的方法。 4.一些特定的机型可能会出现popupWindow缩成一竖条的问题,这时应该尝试调整窗口的宽度和高度,或者使用其他方式来显示内容。如:可以尝试使用Dialog或Alert等其他方式来进行弹窗显示。 5.修改代码后,重新运行应用程序来查看是否解决了该问题。

      参考代码:

      PopupWindow popupWindow = new PopupWindow();
      popupWindow.setContentView(view);
      popupWindow.setWidth(width);
      popupWindow.setHeight(height);
      popupWindow.setFocusable(true);
      popupWindow.setOutsideTouchable(true);
      popupWindow.setBackgroundDrawable(new ColorDrawable(0));
      popupWindow.showAsDropDown(anchorView, xOffset, yOffset);
      
    评论

报告相同问题?

问题事件

  • 创建了问题 4月25日

悬赏问题

  • ¥15 程序实在不会写,要秃了
  • ¥15 pycharm导入不了自己的包
  • ¥15 C#.net通过内网url地址获取文件并下载问题,浏览器postman可以正常下载,用程序不行
  • ¥15 本人本科机械,目前研一。没有深度学习基础,目前对研究生课题一片迷茫,请教各位!
  • ¥15 关于R语言单因素与多因素线性回归的平均值
  • ¥15 服务器清除BIOS之后引导不了
  • ¥15 CPLEX用OPL编写的混合整数线性优化问题。
  • ¥15 可以用EasyConnect连接实验室内网,但无法连接内网才能访问的服务器,为什么?
  • ¥15 前端预览docx文件,文件从后端传送过来。
  • ¥15 层次聚类和蛋白质相似度