Android PopupWindow控制位置

最近比較偷懶哈,已經有一段時間沒有更新分享了,一個原因也是最近需要接觸前端的一些知識,另外也是項目比較忙,周末事情也是比較多和雜,也就沒有多少精力來更新分享了。言歸正傳,今天我們來分享Android的一個小知識點PopupWinow,這個小伙伴們在項目中應該是比較經常用到的。顯示出來是很簡單的,今天重點是想分享下PopupWinow主要的兩種顯示位置的方式,在我們項目中殘忍的UI要求位置靈活一點,還是費了一點時間折騰的,今天就和大家分享下這個折騰的過程。

PopupWinow主要有下面幾種構造函數:

showAsDropDown(View anchor):相對某個控件的位置(正左下方),無偏移
showAsDropDown(View anchor, int xoff, int yoff):相對某個控件的位置,有偏移
showAtLocation(View parent, int gravity, int x, int y):相對于父控件的位置(例如正中央Gravity.CENTER,下方Gravity.BOTTOM等),可以設置偏移或無偏移

簡單寫了個Demo,下面我們分別看下這兩種方式的顯示效果。
showAsDropDown這種方式主要用來將popupWindow顯示在某個view的周圍,也就是以某個view為錨點,可以控制顯示的相對偏移量。


showAsDropDown.png

showAtLocation這種方式就比較自由點,可以控制popupWindow在DecorView上的任意位置進行顯示,項目中我也是用這種方式來滿足UI的各種無理要求~~~


showAtLocation.png

1.初始化PopupWindow

PopupWindow布局文件比較簡單,一個TextView,一個ImageView用來關閉PopupWindow。

<LinearLayout
    android:id="@+id/pop_content"
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:layout_height="70dp"
    android:background="@drawable/pop_bg"
    android:gravity="center_vertical"
    android:orientation="horizontal">

    <TextView
        android:id="@+id/pop_txt"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginLeft="16dp"
        android:text="今天是個好日子"/>

    <ImageView
        android:id="@+id/pop_img"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginLeft="10dp"
        android:layout_marginRight="16dp"
        android:src="@drawable/btn_close"/>

</LinearLayout>

兩種方式初始化PopupWindow的步驟還是一樣的。
有三個點需要注意的:
1.在構造函數中的mView就是可以傳入我們自定義的View,比如可以從LayoutInflater中吹起來;
2.setFocusable(true)就是設置PopupWindow類似模態對話框的功能,也就是PopupWindow彈出后,所有的觸屏和物理按鍵都有PopupWindows處理,home鍵除外,比如一個PopupWindow出現后按back鍵就是先讓PopupWindow消失,然后才是退出activity,小伙伴可以自定試下Demo。相反,如果設置setFocusable(false),那按back鍵就算PopupWindow出現也會直接退出activity。
準確的說是想退出activity你得首先讓PopupWindow消失,因為不是任何情況下按back PopupWindow都會消失,必須在PopupWindow設置了背景的情況下,這個就是下面我們要介紹的第三點。
3.如果需要點擊空白處讓PopupWindow消失,在部門機型上光設置setOutsideTouchable是不行地(我再華為honor 7.0Android系統上倒是可行)。還需要為PopupWindow設置背景,也就是setBackgroundDrawable。

mPopupWindow = new PopupWindow(mView, LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT);
mPopupWindow.setAnimationStyle(R.style.RtcPopupAnimation);

mPopupWindow.setFocusable(true);
mPopupWindow.setOutsideTouchable(true);
mPopupWindow.setBackgroundDrawable(new ColorDrawable(0x00000000));

2.showAsDropDown

showAsDropDown(View anchor, int xoff, int yoff)這個API見名思意就是PopupWindow顯示在anchor周圍,xoff/yoff的坐標系是以anchor這個View的左下角為坐標原點。xoff為正PopupWindow就會向右偏;yoff為正PopupWindow就向下偏。另外有一點需要提醒小伙伴,一般系統中的View放置是設置View的左上角,也就是將坐標設置成View左上角的坐標。

這個API有個比較局限的地方就是放置位置不是那么靈活,或者需要相對于anchor計算位置比較繁瑣。項目中UI需求PopupWindow需要在屏幕中比較靈活顯示,這就引入我們下面的這個API。

在Demo中我們就是這樣用
new LPopupWindow(this.getApplicationContext()).showAsDropDown(mButton, "今天是個好日子", getResources().getDimensionPixelOffset(R.dimen.xoff), getResources().getDimensionPixelOffset(R.dimen.yoff));

3.showAtLocation

showAtLocation(View parent, int gravity, int x, int y)中parent其實容易讓人誤解,并不是要求把PopupWindow放到這個parent里,并不要求parent是一個ViewGroup,其實我發現showAtLocation的parent參數可以很隨意,只要是activity中的view都可以。比如我們Demo中的Button也可以。

官方文檔對這個參數“a parent view to get the token from”,我們開發中一般就是通過parent.getLocationInWindow(location)獲得parent在屏幕上的坐標,其中location是一個大小為2的int數組,第一個就是parent的左上角x坐標,第二個就是parent的左上角y坐標。

第二個參數gravity就是設置屏幕坐標原點,比如Gravity.LEFT | Gravity.TOP就是以屏幕左上角為坐標原點,以此類推。

第三個參數x就是在屏幕坐標系上的x坐標,第四個參數就是y坐標了。

在Demo中我們是這樣用:
new LPopupWindow(this.getApplicationContext()).showAtLocation(mButton, "今天是個好日子", Gravity.LEFT | Gravity.TOP, getResources().getDimensionPixelOffset(R.dimen.xoff), getResources().getDimensionPixelOffset(R.dimen.yoff));

這里x, y位置計算需要說明下,
1.通過parent.getLocationInWindow可以獲得parent在屏幕上的坐標,這個在上面已經解釋過,這里不多說了;

2.popupWindow里面的內容的view的width和height都是wrap_content,通過getMeasuredWidth和getMeasuredHeight拿到的數值會不對,所以在需要強制繪制View,mContent.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED);

3.通過x = 屏幕寬度 - popupWindow里面內容View的寬度 - 你需要設置的相對于屏幕右側的偏移量這個計算式計算得到x給popupWindow的左上角坐標x;

4.通過y = parent在屏幕上的y坐標 - popupWindow里面內容View的高度 - 你需要設置的相對于parent的y方向上的偏移量,計算得到y設置給popupWindow的左上角坐標y。

parent.getLocationInWindow(loc);

mContent.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED);

loc[0] = UIUtils.getScreenWidth(mContext) - mContext.getResources().getDimensionPixelOffset(R.dimen.xoff) - mContent.getMeasuredWidth();
loc[1] -= mContext.getResources().getDimensionPixelOffset(R.dimen.yoff) + mContent.getMeasuredHeight();

這個API用起來位置隨便玩,計算popupWindow的坐標需要一點時間,不過也不算復雜,需要小學基礎即可~~~

4.總結

今天popupWindow的內容比較簡單,就是一些細節需要注意的,showAsDropDown就是用來設置popupWindow相對于anchorView來顯示,從坐標xoff和yoff就可以看出來;showAtLocation就是以一個parent坐標計算得到屏幕上的任意一個位置來顯示popupWindow,計算坐標x和y需要注意parent的坐標取到的值是不是對的,不行需要強制繪制View。

今天的分享就到這里了,希望對大家有點幫助,謝謝!同時感謝@右傾傾的支持哈!

歡迎關注公眾號:JueCode

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容