5分钟搞定PopUpWindow

1e97da0737325a6483ccfebbe0ed9c36da93a5137961c-1j0DuG_fw658.png

前言

最近在项目中用到了 PopUpWindow,并且在机型适配时发现华为等具有虚拟按键的手机在横屏状态时会造成 PopUpWindow 显示位置偏移的情况存在,最后完美解决了这个问题,所以把经验分享出来,看能否对你有用。

弹窗有很多种实现方式,例如:

  1. Dialog
  2. DialogFragment
  3. Fragment
  4. PopUpWindow
  5. ListPopUpWindow

在这些方式中,我们主要讲 PopUpWindow 的使用方式,因为它能在任意位置弹出, 这是其他方式很难做到的。

PopUpWindow 是什么

从 Google 爸爸的开发文档中我们不难看出,首先它是一个 Window,弹出时位于其他控件的上层。

image.png

怎么使用 PopUpWindow

  • 创建布局文件
  • 创建 ContentView
  • 设置 PopUpWindow
  • Show

创建布局文件

PopUpWindow 就是一个容器,是需要编写对应的布局文件,在项目需求中我们要做成这样的效果

image.png
<com.tutu.app.view.TutuRegisterTitleView xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="match_parent"
    android:background="@color/sdk_background"
    android:layout_height="wrap_content">

    <TextView
        android:id="@+id/tutu_game_register_item"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:padding="10dp"
        android:layout_marginTop="4dp"
        android:textAlignment="center"
        android:layout_marginBottom="6dp"
        android:textColor="#333333"
        android:textSize="17dp" />

    <View
        style="@style/TutuGameFullLandscapeLine"
        android:layout_marginLeft="10dp"
        android:layout_marginRight="10dp"/>
</com.tutu.app.view.TutuRegisterTitleView>

创建 ContentView

ContentView 是我们将布局文件生成的View,并且将其放入 PopUpWindow 中。


        // 初始化popUpWindow
        linearLayout = new LinearLayout(getContext());
        // 生成 View 对象
        popRootView =  View.inflate(getContext(), 
        // PopUpWindow 传入 ContentView
        popupWindow = new PopupWindow(popRootView, ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);

设置 PopUpWindow

看到这里,有人可能问:我们在布局文件中已经设置了背景颜色,为什么要在Java代码中重复设置呢?

因为在某些 Andorid 系统版本中会出现点击外部和返回键弹窗却无法消失的 Bug,所以你懂的。

附上某大牛对该 Bug 的分析 PopupWindow 点击外部和返回键无法消失背后的真相

        // 设置背景
        popupWindow.setBackgroundDrawable(new ColorDrawable());
        // 外部点击事件
        popupWindow.setOutsideTouchable(true);

Show

这个就很简单,短短一行代码,控制弹窗的显示实际位置,难点在于 x,y 值的确定

            // 传入 AnchorView ,锚点实际为 Window
            // Gravity.TOP 在该锚点的正上方
            // Gravity.LEFT 在屏幕左侧
            // Gravity.NO_GRAVITY,在屏幕左上角
            // x 为坐标系 x轴方向的偏移量,左负右正
            // y 为坐标系 y轴方向的偏移量,上负下正
            
            popupWindow.showAtLocation(view, Gravity.TOP, 0, y);
      
          
            popupWindow.showAtLocation(view, Gravity.NO_GRAVITY,x, y);

      
            popupWindow.showAtLocation(view, Gravity.TOP, 0, y);
           

怎样使用 ListPopUpWindow

GS20180625140257.gif

和PopUpWindow 相比,它更适合展示多条数据,内部包含了一个 ListView ,那就意味着需要 Adapter 进行数据的绑定。

 listPopupWindow = new ListPopupWindow(getContext());
            // 适配器添加数据
            listPopupWindowAdapter.addAdapterList(list);
            // 添加适配器
            listPopupWindow.setAdapter(listPopupWindowAdapter);
            // 设置弹窗的大小和位置
            listPopupWindow.setWidth(width+horizontalOffset*2);
            listPopupWindow.setHeight(height);
            listPopupWindow.setAnchorView(view);
            listPopupWindow.setModal(true);
            listPopupWindow.setVerticalOffset(-VerticalOffset);
            listPopupWindow.setHorizontalOffset(-horizontalOffset*4);
            // 设置背景
            listPopupWindow.setBackgroundDrawable(
                    BitmapUtils.getDrawableFromResource(getContext(), RUtils.drawable(getContext(),"tutu_area_code_background")));

虚拟按键对 PopUpWindow 的影响

虚拟按键的机型在横屏状态下,会造成一个 x 轴方向的偏移(根据具体代码确定),所以我们使用神器 getLocationInWindow,获取锚点 View 在当前 Window 的坐标,然后通过计算确定弹窗出现位置。

具体决定方案,请看 Fucking Code

  // 获取锚点 View 在屏幕中的坐标
  int[] location = new int[2];
                    back.getLocationInWindow(location);
                    
                    int x = location[0];//获取当前位置的横坐标
                    int y = location[1];//获取当前位置的纵坐标

 // 竖屏不做处理
        if (VERTICAL_SCREEN == getContext().getResources().getConfiguration().orientation){
            popupWindow.showAtLocation(view, Gravity.TOP, 0, y);            
        }
        // 横屏状态
        else if (HORIZONTALL_SCREEN == getContext().getResources().getConfiguration().orientation) {
            // 检测是否有虚拟按键
            if (checkDeviceHasNavigationBar(getContext())){

                  popupWindow.showAtLocation(view, Gravity.NO_GRAVITY,x, y);

            }else {
                popupWindow.showAtLocation(view, Gravity.TOP, 0, y);
            }
        }
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,636评论 5 468
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,890评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,680评论 0 330
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,766评论 1 271
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,665评论 5 359
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,045评论 1 276
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,515评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,182评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,334评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,274评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,319评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,002评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,599评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,675评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,917评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,309评论 2 345
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,885评论 2 341

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,263评论 25 707
  • ¥开启¥ 【iAPP实现进入界面执行逐一显】 〖2017-08-25 15:22:14〗 《//首先开一个线程,因...
    小菜c阅读 6,335评论 0 17
  • 巴比城和巴比塔,坐落在士拿地的平原上。但是此城此塔控诉着人类以自我为忠心的生活方式,也见证着一个全人类的悲剧——口...
    Happy高兴阅读 113评论 0 0