PopupWindow使用詳解

創建

一般用的構造方法.

PopupWindow ()	// 創建一個空的PopupWindow

PopupWindow (View contentView)	

PopupWindow (int width, 
                int height)

PopupWindow (View contentView, 	// PopupWindow的內容View, 相當於setContentView
                int width, 	// 寬, 相當於setwidth()
                int height,  // 高, 相當於setHeight
                boolean focusable) // 是否可獲取焦點, 相當於setFocusable()
複製代碼

通過上下文創建PopupWindow, 創建後默認有一個透明的背景.默認寬高(0,0), 沒有內容和焦點的PopupWindow. 具體作用我也不知道, 估計是寫自定義控件的吧. 但是PopupWindow並沒有繼承View.一般不使用該構造.

PopupWindow (Context context)
  
PopupWindow (Context context, 
                AttributeSet attrs)
  
PopupWindow (Context context, 
                AttributeSet attrs, 
                int defStyleAttr)
  
PopupWindow (Context context, 
                AttributeSet attrs, 
                int defStyleAttr, 
                int defStyleRes)
複製代碼

創建PopuWindow必要的三個條件:

void setHeight (int height) // 因爲PopupWindow沒有默認佈局所以必須指定寬高
void setWidth (int width)
void setContentView (View contentView) // 需要顯示的內容
複製代碼

缺少一個就無法顯示.

前面提到PopupWindow需要設置寬高, 那如果想用佈局中的寬高怎麼辦呢?

可以用到LayoutParams.WRAP_CONTENT包裹布局. 佈局多大就顯示多大的PopupWindow

PopupWindow popupWindow = new PopupWindow(popupView, ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT, true);
複製代碼

顯示

顯示PopupWindow可以分爲兩種方式:

  1. 附着某個控件showAsDropDown
  2. 設置屏幕座標showAtLocation

相對於當前控件

默認是PopupWindow的左上角對其控件的左下角

或者設置Gravity.RIGHT, PopupWindow的右上角對齊控件的右下角

不存在Gravity.TOPGravity.BOTTOM效果

void showAsDropDown (View anchor) // 彈窗顯示在anchor控件左下方

void showAsDropDown (View anchor, 
                int xoff,  // 以控件左下角爲原點的偏移座標
                int yoff)
                
void showAsDropDown (View anchor, 
                int xoff, 
                int yoff, 
                int gravity) 
  // 彈窗顯示在控件的左下方還是右下方, 參數Gravity.RIGHT/Gravity.LEFT. 默認是左下方
複製代碼

相對於當前窗口

當前窗口的任意位置(不包括狀態欄)

void showAtLocation (View parent, // 該屬性只要是屏幕上任意控件對象即可
                int gravity, // 屏幕位置
                int x,  // 偏移座標
                int y)
複製代碼

parent:該屬性只要是當前任意控件對象即可(View和ViewGroup都行), 官方文檔介紹該對象參數主要是爲了得到該對象的getWindowToken()方法.

需要注意的是多次調用show方法, 只會執行第一句

mPopupWindow.showAtLocation(popupwindow, Gravity.TOP, 100, 0); // 只有該行生效
mPopupWindow.showAtLocation(popupwindow, Gravity.LEFT, 100, 0);
mPopupWindow.showAtLocation(popupwindow, Gravity.RIGHT, 100, 0);
mPopupWindow.showAtLocation(popupwindow, Gravity.BOTTOM, 100, 0);
複製代碼

隱藏PopupWindow

void dismiss ()
複製代碼

狀態

可被點擊

boolean isTouchable () // 判斷是否可被點擊
void setTouchable (boolean touchable) // 設置是否可被點擊
複製代碼

多點觸控

void setSplitTouchEnabled (boolean enabled)
boolean isSplitTouchEnabled ()
複製代碼

忽略CheekPress事件

當物體觸摸在屏幕上的尺寸超過手指尺寸範圍, 將被判定爲CheekPress事件(臉頰點擊).

void setIgnoreCheekPress () // 默認爲false, 即不忽略
複製代碼

外部被點擊取消

如果爲true點擊PopupWindow外部區域可以取消PopupWindow

void setOutsideTouchable (boolean touchable) // 設置外部是否可被點擊
boolean isOutsideTouchable () 
複製代碼

但是在android6.0以下還是無法點擊外部取消Popupwindow. 可以通過設置背景來解決這個Bug

mPopupWindow.setBackgroundDrawable(new BitmapDrawable());
複製代碼

解決NavigationBar重疊

這是Android5.0(API22)後添加的方法, 默認爲true. 爲true時將不會與導航欄重疊.

void setAttachedInDecor (boolean enabled)
複製代碼

可獲取焦點

一般控件都不需要焦點. 但是輸入框EditText需要先獲取焦點才能輸入. 最重要的是當PopupWindow可獲取焦點時按下手機返回鍵將不會銷燬當前Activity而是關閉當前PopupWindow. 所以我們一般還是設置爲true. 更加符合用戶操作邏輯. 該方法爲true時同時擁有setOutsideTouchable(true)的作用.

void setFocusable (boolean focusable)
boolean isFocusable ()
複製代碼

設置背景

void setBackgroundDrawable (Drawable background)
Drawable getBackground ()
複製代碼

陰影

該方法我測試無效

void setElevation (float elevation)
float getElevation ()
複製代碼

附着View位置

該方法只在showAsDropDown()方法執行後纔有效. 可以判斷PopupWindow和附着View anchor誰的Y軸座標小.

boolean isAboveAnchor ()
複製代碼

遮蓋附着View

void setOverlapAnchor (boolean overlapAnchor)
boolean getOverlapAnchor ()
複製代碼

可以從圖中看到對齊方式從View anchor的左下角變成了左上角了.

設置PopupWindow寬高

該方法在API23後被廢棄, 由setWidth(int) 和 setHeight(int)替代

void setWindowLayoutMode (int widthSpec, 
                int heightSpec)
複製代碼

窗口裁剪

PopupWindow默認是不會超出屏幕邊界的. 但是如果該方法爲false時會採用精準位置, 能超出屏幕範圍.

void setClippingEnabled (boolean enabled)
boolean isClippingEnabled ()
複製代碼

演示超出屏幕:

mPopupWindow.showAtLocation(mBtnOpenPopup, Gravity.BOTTOM, 0, -30);
複製代碼

動畫效果

設置動畫

可以設置popupWindow的顯示和隱藏動畫

void setAnimationStyle (int animationStyle)

int getAnimationStyle ()
複製代碼

可以看到方法是傳入一個Style的樣式id

示例:

  <style name="popupwindow_anim_style">
    <item name="android:windowEnterAnimation">@anim/dialog_bottom_enter</item>
    <item name="android:windowExitAnimation">@anim/dialog_bottom_exit</item>
  </style>
複製代碼

分別由兩個屬性組成. 兩個屬性各代表一個anim動畫文件.

進入和退出動畫

這是在Android6.0(API 23)後加入的方法. 配合Material Design的轉場動畫使用.

進入動畫

void setEnterTransition (Transition enterTransition)
Transition getEnterTransition ()
複製代碼

退出動畫

void setExitTransition (Transition exitTransition)
Transition getExitTransition ()
複製代碼

獲取

獲取最大高度

這是相當於傳入的View對象可顯示的最大高度. 即PopupWindow使用showAsDropDown()能夠顯示的最大高度

int getMaxAvailableHeight (View anchor)
  
int getMaxAvailableHeight (View anchor, 
                int yOffset) // 控件Y軸偏移後可顯示的最大高度
  
int getMaxAvailableHeight (View anchor,  // api24增加的方法, 由於我手上沒有7.0設備就不說了.
                int yOffset, 
                boolean ignoreBottomDecorations)
複製代碼

輸入模式

針對PopupWindow中包含EditText控件.

輸入模式

我使用該方法的三種模式我感覺並沒有什麼卵用

void setInputMethodMode (int mode)
int getInputMethodMode ()
複製代碼

支持三種模式

  1. INPUT_METHOD_FROM_FOCUSABLE 根據可否獲取焦點判斷是否可輸入. 感覺雞肋
  2. INPUT_METHOD_NEEDED 允許輸入
  3. INPUT_METHOD_NOT_NEEDED 不允許輸入

軟鍵盤模式

void setSoftInputMode (int mode) // mode爲WindowManager.LayoutParams的softInputMode常量
int getSoftInputMode ()
複製代碼

softInputMode

包含九種取值, 可組合使用,分爲兩類:

顯示狀態模式

  1. SOFT_INPUT_STATE_UNSPECIFIED 默認模式
  2. SOFT_INPUT_STATE_HIDDEN
  3. SOFT_INPUT_STATE_ALWAYS_HIDDEN 總是隱藏
  4. SOFT_INPUT_STATE_UNCHANGED
  5. SOFT_INPUT_STATE_VISIBLE
  6. SOFT_INPUT_STATE_ALWAYS_VISIBLE 自動彈出軟鍵盤

調整模式

  1. SOFT_INPUT_ADJUST_UNSPECIFIED 默認模式
  2. SOFT_INPUT_ADJUST_RESIZE 軟鍵盤彈出後PopupWindow會自動調整座標,不被遮擋
  3. SOFT_INPUT_ADJUST_PAN

監聽事件

隱藏事件監聽

即PopupWindow執行dismiss()後回調的方法.

void setOnDismissListener (PopupWindow.OnDismissListener onDismissListener)
複製代碼

觸摸事件攔截

void setTouchInterceptor (View.OnTouchListener l)
複製代碼

更新

以下的更新PopupWindow都必須在PopupWindow處於以及被顯示的狀態下才行. 且PopupWindow的寬高設置都必須大於等於0. 如果想忽略PopupWindow的寬高設置就設爲-1.

更新狀態

該方法不能更新PopupWindow的寬高, 只能更新PopupWindow的狀態. 例如更新FocusableOutsideTouchable

void update () 
複製代碼

更新尺寸

上面說過update()不能更新PopupWindow的寬高, 但是提供更新寬高的update方法

void update (int width, // 更新PopupWindow的寬高
                int height)
複製代碼

更新顯示位置

該方法是相當於重新showAsDropDown, 所以這是相對於控件的位置更新

void update (View anchor, // 更新顯示控件的位置
                int width, 
                int height)
                
void update (View anchor, 
                int xoff, // 相對於控件的偏移值
                int yoff, 
                int width, 
                int height)
複製代碼

相對位置更新

是相對於當前的位置進行偏移. 不同的顯示位置對於的相對原點也不同.

showAsDropDown的相對原點是整個屏幕左上角, 包括狀態欄. 所以由於包括狀態欄所以座標偏移的時候一定要y軸偏移大於60超出狀態欄的高度. 否則因爲遮擋狀態欄導致PopupWindow無法顯示.

mPopupWindow.update(50, 60, -1,-1); // x軸偏移50
複製代碼

showAtLocation的相對原點是自身位置.

void update (int x, // 座標偏移
                int y, 
                int width, // PopupWindow寬高
                int height)
  
void update (int x, 
                int y, 
                int width, 
                int height, 
                boolean force) // 可獲取焦點



轉載自:https://juejin.im/post/58ed82c3a22b9d0063469e98
 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章