Android PopupWindow with ListView的一些問題
最近開發使用PopupWindow彈框顯示ListView,開始使用的固定寬度和高度顯示,由於資料量不固定,資料少時會有空白顯示,於是改成使用wrap_content,發現了一些之前沒注意到的問題,記錄下來:
1、必須設定PopupWindow的Height、Width
不設定的話預設都為0,什麼都不會顯示。
在Android中,控制元件的大小,都是根據父控制元件大小確定的。給PopupWindow設定的contentView一般都是inflate得到的,且root為null,沒有父佈局所以無法計算大小,因此必須設定width和height。
LayoutInflater inflater = LayoutInflater.from (this);
View view = inflater.inflate(R.layout.popwindow, null);
PopupWindow popupWindow = new PopupWindow(view,
LayoutParams.WRAP_CONTENT,
LayoutParams.WRAP_CONTENT);
popwindow.xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android ="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<ListView
android:id="@+id/listview"
android:layout_width="match_parent"
android:layout_height="match_parent" >
</ListView>
</LinearLayout>
由於LinearLayout 沒有父佈局,因此設定margin是沒有用的。
2、PopupWindow寬度設定為WRAP_CONTENT,而其中的ListView寬度為MATCH_PARENT,因此ListView寬度也是WRAP_CONTENT,但是是不起作用的,可以看
http://stackoverflow.com/questions/11295080/android-wrap-content-is-not-working-with-listview
(As Romain Guy (Google Engineer works on UI toolkit) Said in his post
By setting the width to wrap_contentyou are telling ListView to be as wide as the widest of its children. ListView must therefore measure its items and to get the items it has to call getView() on the Adapter. This may happen several times depending on the number of layout passes, the behavior of the parent layout, etc.
So if you set the layout width or layout height of your ListView to wrap_content the ListView will try to measure every single view that is attached to it - which is definitely not what you want.
Keep in mind: avoid setting wrap_content for ListViews or GridViews at all times, for more details see this Google I/O video talking about the world of listview)
3、給PopupWindow添加了mBackground後setOutsideTouchable(true)才會生效,具有外部點選window消失的功能,手機上的返回鍵將可以使window消失
看原始碼:
private void preparePopup(WindowManager.LayoutParams p) {
。。。。。。
// When a background is available, we embed the content view within
// another view that owns the background drawable.
if (mBackground != null) {
mBackgroundView = createBackgroundView(mContentView);
mBackgroundView.setBackground(mBackground);
} else {
mBackgroundView = mContentView;
}
。。。。。。
}
private PopupBackgroundView createBackgroundView(View contentView) {
final ViewGroup.LayoutParams layoutParams = mContentView.getLayoutParams();
final int height;
if (layoutParams != null && layoutParams.height == ViewGroup.LayoutParams.WRAP_CONTENT) {
height = ViewGroup.LayoutParams.WRAP_CONTENT;
} else {
height = ViewGroup.LayoutParams.MATCH_PARENT;
}
final PopupBackgroundView backgroundView = new PopupBackgroundView(mContext);
final PopupBackgroundView.LayoutParams listParams = new PopupBackgroundView.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT, height);
backgroundView.addView(contentView, listParams);
return backgroundView;
}
如果mBackground不為空,會在contentView外再包一層佈局,這層佈局派生自FrameLayout,同時處理了Touch事件和返回按鈕事件。
4、popupwindow佈局檔案的第一層Layout設定margin不起作用,可以設定padding,或者在第二層佈局中設定margin,但是這部分間距仍是popupwindow內的一部分,點選這部分並不能使window消失
如圖list周圍的一圈空白仍是popupwindow內的佈局
解決方法:view.setOnTouchListener
final PopupWindow popupWindow = new PopupWindow(view,
LayoutParams.MATCH_PARENT,
LayoutParams.WRAP_CONTENT);
view.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
popupWindow.dismiss();
return false;
}
});