相關文章:
1、《PopUpWindow使用詳解(一)——基本使用》
2、《PopUpWindow使用詳解(二)——進階及答疑》
上篇為大家基本講述了有關PopupWindow的基本使用,但還有幾個相關函數還沒有講述,我們這篇將著重看看這幾個函數的用法并結合源碼來講講具體原因,最后是有關PopupWindow在使用時的疑問,給大家講解一下。
一、常用函數講解
這段將會給大家講下下面幾個函數的意義及用法,使用上篇那個帶背景的例子為基礎。
?
?
[java]?view plaincopy
public?void?setTouchable(boolean?touchable)??public?void?setFocusable(boolean?focusable)??public?void?setOutsideTouchable(boolean?touchable)??public?void?setBackgroundDrawable(Drawable?background)?? 1、setTouchable(boolean touchable)
設置PopupWindow是否響應touch事件,默認是true,如果設置為false,即會是下面這個結果:(所有touch事件無響應,包括點擊事件)
?
對應代碼:
?
[java]?view plaincopy
private?void?showPopupWindow()?{??????View?contentView?=?LayoutInflater.from(MainActivity.this).inflate(R.layout.popuplayout,?null);??????mPopWindow?=?new?PopupWindow(contentView);??????mPopWindow.setWidth(ViewGroup.LayoutParams.FILL_PARENT);??????mPopWindow.setHeight(ViewGroup.LayoutParams.FILL_PARENT);????????mPopWindow.setTouchable(false);????????………………??????mPopWindow.showAsDropDown(mMenuTv);??}?? 2、setFocusable(boolean focusable)
該函數的意義表示,PopupWindow是否具有獲取焦點的能力,默認為False。一般來講是沒有用的,因為普通的控件是不需要獲取焦點的,而對于EditText則不同,如果不能獲取焦點,那么EditText將是無法編輯的。
所以,我們在popuplayout.xml最底部添加一個EditText,分別演示兩段不同的代碼,即分別將setFocusable設置為false和設置為true;看看有什么不同:
(1)setFocusable(true)代碼如下:
?
?
[html]?view plaincopy
private?void?showPopupWindow()?{??????View?contentView?=?LayoutInflater.from(MainActivity.this).inflate(R.layout.popuplayout,?null);??????mPopWindow?=?new?PopupWindow(contentView);??????mPopWindow.setWidth(ViewGroup.LayoutParams.FILL_PARENT);??????mPopWindow.setHeight(ViewGroup.LayoutParams.FILL_PARENT);????????//是否具有獲取焦點的能力??????mPopWindow.setFocusable(true);???????…………//各item點擊響應??????????mPopWindow.showAsDropDown(mMenuTv);??}?? 明顯在點擊EditText的時候,會彈出編輯框。
?
(2)setFocusable(false)
同樣上面一段代碼,那我們將setFocusable設置為false,會是怎樣呢?
?
[java]?view plaincopy
private?void?showPopupWindow()?{??????View?contentView?=?LayoutInflater.from(MainActivity.this).inflate(R.layout.popuplayout,?null);??????mPopWindow?=?new?PopupWindow(contentView);??????mPopWindow.setWidth(ViewGroup.LayoutParams.FILL_PARENT);??????mPopWindow.setHeight(ViewGroup.LayoutParams.FILL_PARENT);????????????mPopWindow.setFocusable(false);???????…………????????mPopWindow.showAsDropDown(mMenuTv);??}?? 效果圖下:
可見,點擊EditText沒有出現任何反應!所以如果PopupWindow沒有獲取焦點的能力,那么它其中的EditText當然是沒辦法獲取焦點的,EditText無法獲取焦點,那對它而言整個EditText控件就是不可用的。
?
3、setOutsideTouchable(boolean touchable)
這個函數的意義,就是指,PopupWindow以外的區域是否可點擊,即如果點擊PopupWindow以外的區域,PopupWindow是否會消失。
下面這個是點擊會消息的效果圖:
看看它對應的代碼:
?
[java]?view plaincopy
private?void?showPopupWindow()?{??????View?contentView?=?LayoutInflater.from(MainActivity.this).inflate(R.layout.popuplayout,?null);??????mPopWindow?=?new?PopupWindow(contentView);??????mPopWindow.setWidth(ViewGroup.LayoutParams.FILL_PARENT);??????mPopWindow.setHeight(ViewGroup.LayoutParams.FILL_PARENT);????????????mPopWindow.setBackgroundDrawable(new?BitmapDrawable());??????mPopWindow.setOutsideTouchable(true);????????…………??????mPopWindow.showAsDropDown(mMenuTv);????}?? 這里要非常注意的一點:
[java]?view plaincopy
mPopWindow.setBackgroundDrawable(new?BitmapDrawable());??mPopWindow.setOutsideTouchable(true);?? 大家可能要疑問,為什么要加上mPopWindow.setBackgroundDrawable(new BitmapDrawable());這句呢,從代碼來看沒并沒有真正設置Bitmap,而只是new了一個空的bitmap,好像并沒起到什么作用。那如果我們把這句去掉會怎樣:
把代碼改成這樣子:(只使用setOutsideTouchable)
[java]?view plaincopy
private?void?showPopupWindow()?{??????View?contentView?=?LayoutInflater.from(MainActivity.this).inflate(R.layout.popuplayout,?null);??????mPopWindow?=?new?PopupWindow(contentView);??????mPopWindow.setWidth(ViewGroup.LayoutParams.FILL_PARENT);??????mPopWindow.setHeight(ViewGroup.LayoutParams.FILL_PARENT);????????????mPopWindow.setOutsideTouchable(true);????????…………??????mPopWindow.showAsDropDown(mMenuTv);??}?? 看到了沒,點擊外部沒反應………………這就有點坑了,至于原因,我們在setBackgroundDrawable()中講。
?
4、setBackgroundDrawable(Drawable background)
這個函數可是吊了,這個函數不只能設置背景……,因為你加上它之后,setOutsideTouchable()才會生效;
而且,只有加上它之后,PopupWindow才會對手機的返回按鈕有響應:即,點擊手機返回按鈕,可以關閉PopupWindow;如果不加setBackgroundDrawable()將關閉的PopupWindow所在的Activity.
這個函數要怎么用,這里應該就不用講了吧,可以填充進去各種Drawable,比如new BitmapDrawable(),new ColorDrawable(),等;
我們這里主要從源碼的角度來看看setBackgroundDrawable()后,PopupWindow都做了些什么。
首先看看setBackgroundDrawable(),將傳進去的background賦值給mBackground;
?
[java]?view plaincopy
void?setBackgroundDrawable(Drawable?background)?{??????mBackground?=?background;??}?? 然后再看看顯示showAsDropDown()顯示的時候,都做了些什么。代碼如下:
[java]?view plaincopy
public?void?showAsDropDown(View?anchor,?int?xoff,?int?yoff)?{??????…………??????????WindowManager.LayoutParams?p?=?createPopupLayout(anchor.getWindowToken());??????preparePopup(p);????????…………??????????invokePopup(p);??}?? 在這段代碼中,先是準備窗口用來顯示,然后再利用invokePopup()來顯示窗體。
我們看看在preparePopup(p)中是怎么準備窗體的:
[html]?view plaincopy
private?void?preparePopup(WindowManager.LayoutParams?p)?{??????if?(mBackground?!=?null)?{??????????final?ViewGroup.LayoutParams?layoutParams?=?mContentView.getLayoutParams();??????????int?height?=?ViewGroup.LayoutParams.MATCH_PARENT;??????????if?(layoutParams?!=?null?&&??????????????????layoutParams.height?==?ViewGroup.LayoutParams.WRAP_CONTENT)?{??????????????height?=?ViewGroup.LayoutParams.WRAP_CONTENT;??????????}????????????//?when?a?background?is?available,?we?embed?the?content?view??????????//?within?another?view?that?owns?the?background?drawable??????????PopupViewContainer?popupViewContainer?=?new?PopupViewContainer(mContext);??????????PopupViewContainer.LayoutParams?listParams?=?new?PopupViewContainer.LayoutParams(??????????????????ViewGroup.LayoutParams.MATCH_PARENT,?height??????????);??????????popupViewContainer.setBackgroundDrawable(mBackground);??????????popupViewContainer.addView(mContentView,?listParams);????????????mPopupView?=?popupViewContainer;??????}?else?{??????????mPopupView?=?mContentView;??????}??????mPopupWidth?=?p.width;??????mPopupHeight?=?p.height;??}?? 從上面可以看出,如果mBackground不這空,會首先生成一個PopupViewContainer的ViewContainer,然后把mContentView做為子布局add進去,然后把popupViewContainer做為PopupWindow做為根布局。
[html]?view plaincopy
popupViewContainer.addView(mContentView,?listParams);?? 那如果mBackground不為空,那就直接把mContentView做為View傳遞給PopupWindow窗體。
[java]?view plaincopy
mPopupView?=?mContentView?? 到此,我們知道,如果mBackground不為空,會在我們設置的contentView外再包一層布局。
那下面,我們再看看包的這層布局都干了什么:
先列出來完整的代碼,然后再分步講(已做精簡,如需知道更多,可參看源碼)
?
?
[java]?view plaincopy
private?class?PopupViewContainer?extends?FrameLayout?{??????private?static?final?String?TAG?=?"PopupWindow.PopupViewContainer";????????public?PopupViewContainer(Context?context)?{??????????super(context);??????}??????…………?????@Override?????public?boolean?dispatchKeyEvent(KeyEvent?event)?{?????????if?(event.getKeyCode()?==?KeyEvent.KEYCODE_BACK)?{?????????????if?(event.getAction()?==?KeyEvent.ACTION_DOWN?????????????????????&&?event.getRepeatCount()?==?0)?{?????????????????…………?????????????}?else?if?(event.getAction()?==?KeyEvent.ACTION_UP)?{?????????????????KeyEvent.DispatcherState?state?=?getKeyDispatcherState();?????????????????if?(state?!=?null?&&?state.isTracking(event)?&&?!event.isCanceled())?{?????????????????????dismiss();?????????????????????return?true;?????????????????}?????????????}?????????????return?super.dispatchKeyEvent(event);?????????}?else?{?????????????return?super.dispatchKeyEvent(event);?????????}?????}????????@Override??????public?boolean?onTouchEvent(MotionEvent?event)?{??????????final?int?x?=?(int)?event.getX();??????????final?int?y?=?(int)?event.getY();????????????????????if?((event.getAction()?==?MotionEvent.ACTION_DOWN)??????????????????&&?((x?<?0)?||?(x?>=?getWidth())?||?(y?<?0)?||?(y?>=?getHeight())))?{??????????????dismiss();??????????????return?true;??????????}?else?if?(event.getAction()?==?MotionEvent.ACTION_OUTSIDE)?{??????????????dismiss();??????????????return?true;??????????}?else?{??????????????return?super.onTouchEvent(event);??????????}??????}??????…………??}?? 這里總共需要注意三部分:
(1)、PopupViewContainer派生自FrameLayout從PopupViewContainer聲明上可以看到,PopupViewContainer派生自FrameLayout;所以,這也是它能將我們傳進來的contentView添加為自己的子布局的原因。
(2)、返回按鈕捕捉 [java]?view plaincopy
public?boolean?dispatchKeyEvent(KeyEvent?event)?{?????if?(event.getKeyCode()?==?KeyEvent.KEYCODE_BACK)?{?????????if?(event.getAction()?==?KeyEvent.ACTION_DOWN?????????????????&&?event.getRepeatCount()?==?0)?{?????????????…………?????????}?else?if?(event.getAction()?==?KeyEvent.ACTION_UP)?{????????????????????????KeyEvent.DispatcherState?state?=?getKeyDispatcherState();?????????????if?(state?!=?null?&&?state.isTracking(event)?&&?!event.isCanceled())?{????????????????????????????????dismiss();?????????????????return?true;?????????????}?????????}?????????return?super.dispatchKeyEvent(event);?????}?else?{?????????return?super.dispatchKeyEvent(event);?????}??}?? 從上面的代碼來看,PopupViewContainer捕捉了KeyEvent.KEYCODE_BACK事件,并且在用戶在點擊back按鈕,抬起手指的時候(event.getAction() == KeyEvent.ACTION_UP)將窗體隱藏掉。
所以,添加上mBackground以后,可以在用戶點擊返回按鈕時,隱藏窗體!
(3)、捕捉Touch事件——onTouchEvent [java]?view plaincopy
public?boolean?onTouchEvent(MotionEvent?event)?{??????final?int?x?=?(int)?event.getX();??????final?int?y?=?(int)?event.getY();????????????if?((event.getAction()?==?MotionEvent.ACTION_DOWN)??????????????&&?((x?<?0)?||?(x?>=?getWidth())?||?(y?<?0)?||?(y?>=?getHeight())))?{??????????dismiss();??????????return?true;??????}?else?if?(event.getAction()?==?MotionEvent.ACTION_OUTSIDE)?{??????????dismiss();??????????return?true;??????}?else?{??????????return?super.onTouchEvent(event);??????}??}?? 從這代碼來看,PopupViewContainer捕捉了兩種touch事件,MotionEvent.ACTION_DOWN和MotionEvent.ACTION_OUTSIDE;將接收到這兩個事件時,會將窗體隱藏掉。
MotionEvent.ACTION_DOWN的觸發很好理解,即當用戶點擊到PopupViewContainer事件時,就隱藏掉;
所以,下面的情況就來了:
假如有一個TextView,我們沒有對它設置點擊響應。那只要加了background,那點擊事件就會傳給下層的PopupViewContainer,從而使窗體消失。
那還有個問題,MotionEvent.ACTION_OUTSIDE是個什么鬼?它是怎么觸發的。我們在下面開一段細講。
(4)MotionEvent.ACTION_OUTSIDE與setOutsideTouchable(boolean touchable)可能把這兩個放在一塊,大家可能就恍然大悟了,表著急,一個個來看。
先看看setOutsideTouchable(boolean touchable)的代碼:
?
?
[java]?view plaincopy
public?void?setOutsideTouchable(boolean?touchable)?{?????mOutsideTouchable?=?touchable;??}?? 然后再看看mOutsideTouchable哪里會用到
下面代碼,我做了嚴重精減,等下會再完整再講這一塊
[java]?view plaincopy
private?int?computeFlags(int?curFlags)?{??????curFlags?&=?~(WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH);??????…………??????if?(mOutsideTouchable)?{??????????curFlags?|=?WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH;??????}??????…………??????return?curFlags;??}?? 這段代碼主要是用各種變量來設置window所使用的flag;
首先,將curFlags所在運算的各種Flag,全部置為False;代碼如下:
[java]?view plaincopy
curFlags?&=?~(WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH);?? 然后,再根據用戶設置的變量來開啟:
[java]?view plaincopy
if?(mOutsideTouchable)?{?????curFlags?|=?WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH;??}?? 既然講到FLAG_WATCH_OUTSIDE_TOUCH,那我們來看看FLAG_WATCH_OUTSIDE_TOUCH所代表的意義:
這段話的意思是說,如果窗體設置了FLAG_WATCH_OUTSIDE_TOUCH這個flag,那么 用戶點擊窗體以外的位置時,將會在窗體的MotionEvent中收到MotionEvetn.ACTION_OUTSIDE事件。
參見:《WindowManager.LayoutParams》
所以在PopupViewContainer中添加了對MotionEvent.ACTION_OUTSIDE的捕捉!當用戶點擊PopupViewContainer以外的區域時,將dismiss掉PopupWindow
?
[java]?view plaincopy
public?boolean?onTouchEvent(MotionEvent?event)?{??????final?int?x?=?(int)?event.getX();??????final?int?y?=?(int)?event.getY();????????????if?((event.getAction()?==?MotionEvent.ACTION_DOWN)??????????????&&?((x?<?0)?||?(x?>=?getWidth())?||?(y?<?0)?||?(y?>=?getHeight())))?{??????????dismiss();??????????return?true;??????}?else?if?(event.getAction()?==?MotionEvent.ACTION_OUTSIDE)?{??????????dismiss();??????????return?true;??????}?else?{??????????return?super.onTouchEvent(event);??????}??}?? (5)重看PopupWindow的computeFlags(int curFlags)函數完整的computeFlags()函數如下:
[java]?view plaincopy
private?int?computeFlags(int?curFlags)?{??????curFlags?&=?~(??????????????WindowManager.LayoutParams.FLAG_IGNORE_CHEEK_PRESSES?|??????????????WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE?|??????????????WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE?|??????????????WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH?|??????????????WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS?|??????????????WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM?|??????????????WindowManager.LayoutParams.FLAG_SPLIT_TOUCH);??????if(mIgnoreCheekPress)?{??????????curFlags?|=?WindowManager.LayoutParams.FLAG_IGNORE_CHEEK_PRESSES;??????}??????if?(!mFocusable)?{??????????curFlags?|=?WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;??????????if?(mInputMethodMode?==?INPUT_METHOD_NEEDED)?{??????????????curFlags?|=?WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;??????????}??????}?else?if?(mInputMethodMode?==?INPUT_METHOD_NOT_NEEDED)?{??????????curFlags?|=?WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;??????}??????if?(!mTouchable)?{??????????curFlags?|=?WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;??????}??????if?(mOutsideTouchable)?{??????????curFlags?|=?WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH;??????}??????if?(!mClippingEnabled)?{??????????curFlags?|=?WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS;??????}??????if?(isSplitTouchEnabled())?{??????????curFlags?|=?WindowManager.LayoutParams.FLAG_SPLIT_TOUCH;??????}??????if?(mLayoutInScreen)?{??????????curFlags?|=?WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;??????}??????if?(mLayoutInsetDecor)?{??????????curFlags?|=?WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR;??????}??????if?(mNotTouchModal)?{??????????curFlags?|=?WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;??????}??????return?curFlags;??}?? 這段代碼同樣是分兩段:
第一段:將所有要計算的FLAG,全部在結果curFlags中置為FALSE;
[java]?view plaincopy
curFlags?&=?~(??????????WindowManager.LayoutParams.FLAG_IGNORE_CHEEK_PRESSES?|??????????WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE?|??????????WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE?|??????????WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH?|??????????WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS?|??????????WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM?|??????????WindowManager.LayoutParams.FLAG_SPLIT_TOUCH);?? 第二段:然后根據用戶設置的變量,逐個判斷是否打開。比如下面這個:
[java]?view plaincopy
if?(!mTouchable)?{??????curFlags?|=?WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;??}?? 好了,結合源碼就給大家講到這里了。最后總結一下:
**如果我們給PopupWindow添加了mBackground,那它將會:**- setOutsideTouchable(true)將生效,具有外部點擊隱藏窗體的功能
- 手機上的返回鍵將可以使窗體消失
- 對于PopupWindow上層沒有捕捉的點擊事件,點擊之后,仍然能使窗體消失。
源碼在文章底部給出 二、為什么要強制代碼設置PopupWindow的Height、Width
?
在上篇,我們留了這么個疑問,設置contentView很容易理解,但width和height為什么要強制設置呢?我們在布局代碼中不是已經寫的很清楚了么?比如我們的popuplayout.xml的根布局:
?
[html]?view plaincopy
<RelativeLayout??????????xmlns:android="http://schemas.android.com/apk/res/android"??????????android:layout_width="fill_parent"??????????android:layout_height="fill_parent"??????????android:background="#66000000">??????????…………??</RelativeLayout>????? 從根布局中,我們明明可以看到layout_width我們設置為了"fill_parent",layout_height設置為了“fill_parent”;為什么非要我們在代碼中還要再設置一遍:
[java]?view plaincopy
View?contentView?=?LayoutInflater.from(MainActivity.this).inflate(R.layout.popuplayout,?null);??mPopWindow?=?new?PopupWindow(contentView);??mPopWindow.setWidth(ViewGroup.LayoutParams.FILL_PARENT);??mPopWindow.setHeight(ViewGroup.LayoutParams.FILL_PARENT);?? 帶著這個疑問,我們從兩個角度來分析,”源碼角度”看看就好,關鍵的解答在第二部分:布局角度;
1、源碼角度
首先,我們從源碼我角度來分析為什么要設置Width和Height;我們就以setWidth()為例來追根尋底下
先看下setWidth():
[java]?view plaincopy
public?void?setWidth(int?width)?{??????mWidth?=?width;??}?? 然后再看看mWidth在哪里用到:
[java]?view plaincopy
private?WindowManager.LayoutParams?createPopupLayout(IBinder?token)?{??????????????WindowManager.LayoutParams?p?=?new?WindowManager.LayoutParams();??????????????????????p.gravity?=?Gravity.LEFT?|?Gravity.TOP;??????p.width?=?mLastWidth?=?mWidth;??????p.height?=?mLastHeight?=?mHeight;??????if?(mBackground?!=?null)?{??????????p.format?=?mBackground.getOpacity();??????}?else?{??????????p.format?=?PixelFormat.TRANSLUCENT;??????}??????p.flags?=?computeFlags(p.flags);??????p.type?=?mWindowLayoutType;??????p.token?=?token;??????p.softInputMode?=?mSoftInputMode;??????p.setTitle("PopupWindow:"?+?Integer.toHexString(hashCode()));????????return?p;??}?? 上面是createPopupLayout的完整代碼,我們提取一下:
[java]?view plaincopy
private?WindowManager.LayoutParams?createPopupLayout(IBinder?token)?{??????…………??????p.width?=?mLastWidth?=?mWidth;??????p.height?=?mLastHeight?=?mHeight;??????…………??????return?p;??}?? 從這里便可以清晰的看到窗體的寬度和高度都是通過mWidth和mHeight來設置的。
那問題來了,mWidth在哪里能設置呢:
通篇代碼中,總共只有三個函數能設置mWidth,分別如下:
除了setWidth()函數本身,就只有PopupWindow()的兩個構造函數了;
[java]?view plaincopy
public?void?setWidth(int?width)?{??????mWidth?=?width;??}??public?PopupWindow(View?contentView,?int?width,?int?height)?{??????this(contentView,?width,?height,?false);??}??public?PopupWindow(View?contentView,?int?width,?int?height,?boolean?focusable)?{?????if?(contentView?!=?null)?{?????????mContext?=?contentView.getContext();?????????mWindowManager?=?(WindowManager)?mContext.getSystemService(Context.WINDOW_SERVICE);?????}?????setContentView(contentView);?????setWidth(width);?????setHeight(height);?????setFocusable(focusable);??}?? 那么問題來了,如果我們沒有設置width和height那結果會如何呢?
如果我們沒有設置width和height,那mWidth和mHeight將會取默認值0!!!!所以當我們沒有設置width和height時,并不是我們的窗體沒有彈出來,而是因為他們的width和height都是0了!!!!
**那么問題又來了:Google那幫老頭,不能從我們contentView的根布局中取參數嗎,非要我們自己設?**
當然不是那幫老頭的代碼有問題,因為這牽涉了更深層次的內容:布局參數的設定問題!我們在下一部分,布局角度來解答。
2、布局角度
這部分我們著重講一個問題:控件的布局參數從哪里來?
我們看下面這段XML:
?
?
[html]?view plaincopy
<?xml?version="1.0"?encoding="utf-8"?>??<RelativeLayout??????????xmlns:android="http://schemas.android.com/apk/res/android"??????????android:layout_width="fill_parent"??????????android:layout_height="fill_parent">??????<LinearLayout??????????????android:layout_width="match_parent"??????????????android:layout_height="wrap_content"??????????????android:background="@drawable/pop_bg"??????????????android:orientation="vertical"??????????????android:paddingBottom="2dp"??????????????android:layout_alignParentRight="true">????????????<TextView??????????????????android:id="@+id/pop_computer"??????????????????android:layout_width="wrap_content"??????????????????android:layout_height="wrap_content"??????????????????style="@style/pop_text_style"??????????????????android:text="計算機"/>??????</LinearLayout>??</RelativeLayout>?? 很明顯,這段代碼是個三層結構,TextView是最終的子控件。
那我現在要問了:TextView的顯示大小是由誰來決定的?
是由它自己的布局layout_width="wrap_content"、layout_height="wrap_content"來決定的嗎?
當然不是!!!!它的大小,應該是在它父控件的基礎上決定的。即LinearLayout的顯示大小確定了以后,才能確定TextView的大小。
這好比,如果LinearLayout的大小是全屏的,那TextView的大小就由它自己來決定了,那如果LinearLayout的大小只有一像素呢?那TextView的所顯示的大小無論它自己怎么設置,最大也就顯示一像素!
所以我們的結論來了:控件的大小,是建立在父控件大小確定的基礎上的。
那同樣:LinearLayout的大小確定是要靠RelativeLayout來決定。
那問題來了:RelativeLayout的大小靠誰決定呢?
當然是它的父控件了。
我們以前講過ViewTree的概念,即在android中任何一個APP都會有一個根結點,然后它所有的Activity和Fragmentr所對應的布局都會加入到這個ViewTree中;在ViewTree中每一個控件是一個結點:
比如下面這個ViewTree(畫的很爛……)
?
從上面的ViewTree中可以看到,每一個結點都是有父結點的(除了根結點,根結點不是應用的根結點,與我們應用無關),所以每一個控件都是可以找到父控件的的布局大小的。
但我們的contentView是怎么來的呢?
?
[java]?view plaincopy
View?contentView?=?LayoutInflater.from(MainActivity.this).inflate(R.layout.popuplayout,?null);?? 直接inflate出來的,我們對它沒有設置根結點!
那問題來了?它的大小由誰來解決呢?
好像沒有誰能決定了,因為他沒有父結點。那它到底是多大呢?未知!
所以只有通過代碼讓用戶去手動設置了!所以這就是為什么非要用戶設置width和height的原因了。
好了,到這里,有關PopupWIndow的東東也就講完了,希望大家能學到東西。
?
如果本文有幫到你,記得加關注哦
源碼下載地址:http://download.csdn.net/detail/harvic880925/9197073
請大家尊重原創者版權,轉載請標明出處:http://blog.csdn.net/harvic880925/article/details/49278705?謝謝
?
- 上一篇PopUpWindow使用詳解(一)——基本使用
- 下一篇支付寶集成過程詳解——運行DEMO
-
?
轉載于:https://www.cnblogs.com/xgjblog/p/7688153.html
總結
以上是生活随笔為你收集整理的PopUpWindow使用详解(二)——进阶及答疑的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。