PopupWindow有點類似於Dialog,相同點在於都是彈出窗口,並且都可以對其進行自定義顯示,並且里面的監聽組件,進行相應的操作,但它與Dialog又有很大的區別,PopupWindow只是彈出窗口,不會使宿主Activity組件失去焦點,也就是說PopupWindow彈出后,你仍可以與宿主Activity進行交互,Dialog卻不能做到這一點。
參考:http://blog.csdn.net/hlyjunhe/article/details/6572159
http://www.cnblogs.com/noTice520/archive/2011/08/16/2140356.html
http://www.2cto.com/kf/201108/100378.html
http://www.cnblogs.com/noTice520/archive/2011/02/15/1955541.html
使用PopupWindow可實現彈出窗口效果,,其實和AlertDialog一樣,也是一種對話框,兩者也經常混用,但是也各有特點。下面就看看使用方法。
首先初始化一個PopupWindow,指定窗口大小參數。
PopupWindow mPop = new PopupWindow(getLayoutInflater().inflate(R.layout.window, null),
LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
也可以分開寫:
LayoutInflater mLayoutInflater = (LayoutInflater) getSystemService(LAYOUT_INFLATER_SERVICE);
//自定義布局
ViewGroup menuView = (ViewGroup) mLayoutInflater.inflate(
R.layout.window, null, true);
PopupWindow mPop = new PopupWindow(menuView, LayoutParams.WRAP_CONTENT,
LayoutParams.WRAP_CONTENT, true);
當然也可以手動設置PopupWindow大小。
mPop.setContentView(menuView );//設置包含視圖
mPop.setWidth(int )
mPop.setHeight(int )//設置彈出框大小
設置進場動畫:
mPop.setAnimationStyle(R.style.AnimationPreview);//設置動畫樣式
mPop.setOutsideTouchable(true);//這里設置顯示 PopuWindow 之后在外面點擊是否有效。如果為 false 的話,那么點擊 PopuWindow 外面並不會關閉 PopuWindow 。當然這里很明顯只能在 Touchable 下才能使用。
當有mPop.setFocusable(false);的時候,說明PopuWindow不能獲得焦點,即使設置設置了背景不為空也不能點擊外面消失,只能由dismiss()消失,但是外面的View的事件還是可以觸發,back鍵也可以順利dismiss掉。當設置為popuWindow.setFocusable(true);的時候,加上下面兩行設置背景代碼,點擊外面和Back鍵才會消失。
mPop.setFocusable(true);需要順利讓 PopUpWindow dimiss (即點擊 PopuWindow 之外的地方此或者 back 鍵 PopuWindow 會消失); PopUpWindow 的背景不能為空。必須在 popuWindow.showAsDropDown(v); 或者其它的顯示 PopuWindow 方法之前設置它的背景不為空:
mPop.setBackgroundDrawable(new ColorDrawable(0));
mPop.showAsDropDown(anchor, 0, 0);//設置顯示PopupWindow的位置位於View的左下方,x,y表示坐標偏移量
mPop.showAtLocation(findViewById(R.id.parent), Gravity.LEFT, 0, -90);(以某個View為參考),表示彈出窗口以parent組件為參考,位於左側,偏移-90。
mPop.setOnDismissListenerd(new PopupWindow.OnDismissListener(){})//設置窗口消失事件注:window.xml為布局文件
總結:
1、為PopupWindow的view布局,通過LayoutInflator獲取布局的view.如:
LayoutInflater inflater =(LayoutInflater)
this.anchor.getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View textEntryView = inflater.inflate(R.layout.paopao_alert_dialog, null);
2、顯示位置,可以有很多方式設置顯示方式
pop.showAtLocation(findViewById(R.id.ll2), Gravity.LEFT, 0, -90);
或者
pop.showAsDropDown(View anchor, int xoff, int yoff)
3、進出場動畫
pop.setAnimationStyle(R.style.PopupAnimation);
4、點擊PopupWindow區域外部,PopupWindow消失
this.window = new PopupWindow(anchor.getContext());
this.window.setTouchInterceptor(new OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
if(event.getAction() ==MotionEvent.ACTION_OUTSIDE) {
BetterPopupWindow.this.window.dismiss();
return true;
}
return false;
}
});
例子
例一:
效果:
圖一:原來

點擊下拉列表中的項,例如鄭州大學南校門
效果圖2:

點擊圖片,圖片消失,重新回到圖1
代碼
private PopupWindow popupWindow;
。。。。。。
。。。。。。
list.setOnItemClickListener(new OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> arg0, View arg1, int arg2,
long arg3) {
openPopupwin(arg2);
}
});
。。。。。。
。。。。。。
//創建 彈出窗口
private void openPopupwin(int arg) {
LayoutInflater mLayoutInflater = (LayoutInflater) getSystemService(LAYOUT_INFLATER_SERVICE);
View menuView = (View) mLayoutInflater.inflate(
R.layout.pop_popwindow, null, true);
imgview = (ImageView) menuView.findViewById(R.id.pop_popwindowimage);
switch(arg)
{
case 0:
imgview.setBackgroundResource(R.drawable.p_overview_pop_image1);
break;
case 1:
imgview.setBackgroundResource(R.drawable.p_overview_pop_image2);
break;
case 2:
imgview.setBackgroundResource(R.drawable.p_overview_pop_image3);
break;
case 3:
imgview.setBackgroundResource(R.drawable.p_overview_pop_image4);
break;
case 4:
imgview.setBackgroundResource(R.drawable.p_overview_pop_image5);
break;
case 5:
imgview.setBackgroundResource(R.drawable.p_overview_pop_image6);
break;
}
imgview.requestFocus();
imgview.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {// 焦點到了gridview上,所以需要監聽此處的鍵盤事件。否則會出現不響應鍵盤事件的情況
if (popupWindow != null && popupWindow.isShowing()) {
popupWindow.dismiss();
}
}
});
popupWindow = new PopupWindow(menuView, LayoutParams.FILL_PARENT,
LayoutParams.FILL_PARENT, true);
popupWindow.setBackgroundDrawable(new BitmapDrawable());
popupWindow.setAnimationStyle(R.style.PopupAnimation);
popupWindow.showAtLocation(menuView, Gravity.CENTER
| Gravity.CENTER, 0, 0);
popupWindow.update();
}
pop_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="fill_parent" android:gravity="center" android:layout_height="fill_parent" android:layout_gravity="center" android:background="#b5555555" > <ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@drawable/logo" android:id="@+id/pop_popwindowimage" /> </LinearLayout>
例子:
先上圖







用的豌豆莢截圖,本來是個動畫的,每個過程都有幾張,大概就是要實現這個效果,初始狀態只有一個Button,當點擊show的時候,另外一個頁面從底部慢慢升起來,直到覆蓋到上一個頁面,注意這里不是啟用另一個Activity,是用的PopupWindow,當點擊dismiss的時候,又慢慢消失。。。這種效果看上去不錯,PopupWindow上面可以添加想要添加的控件,比如ListView(注意,如果添加ListView的話,當它彈出來之后,按back鍵不起作用,它獲取不了監聽,其余的非ListView控件可以,這里添加了個Button ),下面貼出代碼
這是主類MainActivity.java
package com.test.popupwindow;
import android.app.Activity;
import android.os.Bundle;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.LinearLayout.LayoutParams;
import android.widget.PopupWindow;
publicclass MainActivity extends Activity {
/** Called when the activity is first created. */
boolean flag =false;
PopupWindow popupWindow;
@Override
publicvoid onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
init();
}
publicvoid init() {
Button btn_show = (Button) findViewById(R.id.btn_show);
LayoutInflater inflater = LayoutInflater.from(this);
View layout = inflater.inflate(R.layout.popup, null);
popupWindow =new PopupWindow(layout, LayoutParams.FILL_PARENT,
LayoutParams.FILL_PARENT);
Button btn_dismiss = (Button) layout.findViewById(R.id.btn_dismiss);
btn_dismiss.setOnClickListener(new OnClickListener() {
@Override
publicvoid onClick(View v) {
// TODO Auto-generated method stub
openMenu();
}
});
btn_show.setOnClickListener(new OnClickListener() {
@Override
publicvoid onClick(View v) {
// TODO Auto-generated method stub
openMenu();
}
});
}
publicvoid btn_showOnClicked() {
openMenu();
}
publicvoid btn_dismissOnClicked() {
openMenu();
}
publicvoid openMenu() {
if (!flag) {
popupWindow.setAnimationStyle(R.style.PopupAnimation);
popupWindow.showAtLocation(findViewById(R.id.btn_show), Gravity.NO_GRAVITY, 0, 0);
popupWindow.setFocusable(true);
popupWindow.update();
flag =true;
} else {
popupWindow.dismiss();
popupWindow.setFocusable(false);
flag =false;
}
}
}
布局文件main.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:id="@+id/layout"
>
<Button
android:id="@+id/btn_show"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="show"
/>
</RelativeLayout>
布局文件popup.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="#cccccc"
>
<Button
android:id="@+id/btn_dismiss"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="dismiss"/>
</LinearLayout>
工程結構

注意看在res文件夾下面新建了一個anim文件夾,里面要實現的動畫頁面,比如從哪個坐標移動到哪個坐標之類的,當然還可以定義其它的,這里只實現了Y坐標的移動
在anim文件夾下面建兩個文件,一個是in.xml,另外一個是out.xml,意思一看就明白
in.xml
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="@android:anim/decelerate_interpolator">
<translate
android:fromYDelta="854"
android:toYDelta="0"
android:duration="1000"/>
</set>
它表示Y的坐標從854移動到0,時間為1秒
out.xml
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate android:interpolator="@android:anim/decelerate_interpolator"
android:fromYDelta="0"
android:toYDelta="854"
android:duration="10000"
/>
</set>
這個不解釋了。。。
另一個例子:http://blog.csdn.net/longhushi/article/details/6923001
這幾天說是要在Android的平板電腦上(其實不是平板電腦,是中興的一款超大手機,7寸屏)改一個應用的主界面,原本功能菜單是通過點擊手機上的Menu鍵實現的,但是貌似客戶不滿意,說是要做成類似於windows系統開始菜單的樣子,一點擊菜單按鈕(一個Button),就彈出一個菜單窗口供選擇,上網查了下,發現PopupWindow可以實現該功能。
一開始覺得挺容易,不就是建一個菜單布局文件和item布局文件,然后在程序用引用么,但是真正一做才發現了問題:
起初,我用的是listView實現的菜單
menu_layout.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:background="@drawable/menu">
<ListView
android:id="@+id/menulist"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
>
</ListView>
</LinearLayout>
menu_item.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content">
<TextView
android:id="@+id/menuitem"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="15dp"
android:textSize="20sp"
android:textColor="#000000"
/>
</LinearLayout>
然后在MainActivity.java中使用:
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
HashMap<String,String> map = new HashMap<String,String>();
map.put("menuItemName", "信息展示");
list.add(map);
HashMap<String,String> map2 = new HashMap<String,String>();
map2.put("menuItemName", "系統設置");
list.add(map2);
HashMap<String,String> map3 = new HashMap<String,String>();
map3.put("menuItemName", "自助更新");
list.add(map3);
HashMap<String,String> map4 = new HashMap<String,String>();
map4.put("menuItemName", "關於");
list.add(map4);
HashMap<String,String> map5 = new HashMap<String,String>();
map5.put("menuItemName", "搜索");
list.add(map5);
HashMap<String,String> map6 = new HashMap<String,String>();
map6.put("menuItemName", "退出");
list.add(map6);
HashMap<String,String> map7 = new HashMap<String,String>();
map7.put("menuItemName", "返回");
list.add(map7);
myButton = (Button)findViewById(R.id.myButton);
myButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
if(state == 1) {
state = 0;
pop.dismiss();
}
else if(state == 0) {
// 彈出自定義的菜單
layout = getLayoutInflater().inflate(R.layout.menu_layout, null);
menulist = (ListView)layout.findViewById(R.id.menulist);
SimpleAdapter listAdapter = new SimpleAdapter(MainActivity.this,list,R.layout.menu_item,new String[]{"menuItemName"},new int[]{R.id.menuitem});
menulist.setAdapter(listAdapter);
pop = new PopupWindow(layout, myButton.getWidth(),getWindowManager().getDefaultDisplay().getHeight()/3+40);
pop.update();
//pop.setInputMethodMode(PopupWindow.INPUT_METHOD_NEEDED);
pop.setTouchable(true);
pop.setOutsideTouchable(true);
pop.setFocusable(true);
pop.showAtLocation(layout, (Gravity.BOTTOM-myButton.getHeight())|Gravity.LEFT, 0, 2*myButton.getHeight());
state = 1;
pop.setTouchInterceptor(new OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
if(event.getAction() == MotionEvent.ACTION_OUTSIDE) {
pop.dismiss();
return true;
}
return false;
}
});
menulist.setOnItemClickListener(new OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> arg0, View arg1,
int arg2, long arg3) {
// TODO Auto-generated method stub
switch(arg2) {
case 0:
Toast.makeText(getApplicationContext(), "信息展示", Toast.LENGTH_SHORT).show();
pop.dismiss();
break;
case 1:
Toast.makeText(getApplicationContext(), "系統設置", Toast.LENGTH_SHORT).show();
pop.dismiss();
break;
case 2:
Toast.makeText(getApplicationContext(), "自動更新", Toast.LENGTH_SHORT).show();
pop.dismiss();
break;
case 3:
Toast.makeText(getApplicationContext(), "關於", Toast.LENGTH_SHORT).show();
pop.dismiss();
break;
case 4:
Toast.makeText(getApplicationContext(), "搜索", Toast.LENGTH_SHORT).show();
pop.dismiss();
break;
case 5:
Toast.makeText(getApplicationContext(), "退出", Toast.LENGTH_SHORT).show();
pop.dismiss();
break;
case 6:
Toast.makeText(getApplicationContext(), "返回", Toast.LENGTH_SHORT).show();
pop.dismiss();
break;
}
}
});
}
}
});
}

但是這樣就帶來一個問題,關鍵在於pop.setFocusable(true);這句話,一旦設置popupwindow獲得了焦點,那么在點擊界面中的其它元素都會沒有響應,就是手機的按鈕也一樣(除了那個home按鍵),也就是說如果點開了這個菜單就關不上了,除非在點擊響應Item的時候dismiss掉這個popupwindow,但是如果用戶一個按鈕都不點擊呢?好比我們點擊windows的開始菜單后,可能一個菜單項都沒選,繼續點擊下開始按鈕,這個菜單又會消失,可是在這里,如果設置popupwindow獲得了焦點的話是不可能再響應Button的onclick事件的。之前在網上搜的時候也用朋友說,沒必要設置pop.setFocusable(true),popupwindow上的東西本來就可以響應,我實踐了發現,這句話對於普通的控件是對的,但是對於listView這種控件,則必須得到焦點才能使用。但是這句話讓我想到了,可不可以不用listview來顯示呢?我又看了下UCWEB的菜單,人家也是用popupwindow來實現的,可是他們在popupwindow上面排放的都是小圖片,由此我想到的第二種方法:直接用TextView
不但簡便,而且可以實現菜單功能:
menu_layout.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:background="@drawable/menu1"
android:orientation="vertical">
<TextView
android:id="@+id/information"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="15dp"
android:layout_marginTop="5dp"
android:text="信息展示"
android:textSize="20sp"
android:textColor="#000000"
/>
<TextView
android:id="@+id/system"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="15dp"
android:layout_marginTop="8dp"
android:text="系統設置"
android:textSize="20sp"
android:textColor="#000000"
/>
<TextView
android:id="@+id/autoupdate"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="15dp"
android:layout_marginTop="6dp"
android:text="自動更新"
android:textSize="20sp"
android:textColor="#000000"
/>
<TextView
android:id="@+id/about"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="15dp"
android:layout_marginTop="6dp"
android:text="關於 "
android:textSize="20sp"
android:textColor="#000000"
/>
<TextView
android:id="@+id/search"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="15dp"
android:layout_marginTop="6dp"
android:text="搜索 "
android:textSize="20sp"
android:textColor="#000000"
/>
<TextView
android:id="@+id/exit"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="15dp"
android:layout_marginTop="6dp"
android:text="退出 "
android:textSize="20sp"
android:textColor="#000000"
/>
</LinearLayout>
MainActivity.java:
myButton = (Button)findViewById(R.id.myButton);
myButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
if(state == 1) {
state = 0;
pop.dismiss();
}
else if(state == 0) {
// 彈出自定義的菜單
layout = getLayoutInflater().inflate(R.layout.menu_layout, null);
pop = new PopupWindow(layout, myButton.getWidth(),getWindowManager().getDefaultDisplay().getHeight()/3+40);
pop.showAtLocation(layout, (Gravity.BOTTOM-myButton.getHeight())|Gravity.LEFT, 0, 2*myButton.getHeight());
state = 1;
tv1 = (TextView)layout.findViewById(R.id.information);
tv2 = (TextView)layout.findViewById(R.id.system);
tv3 = (TextView)layout.findViewById(R.id.autoupdate);
tv4 = (TextView)layout.findViewById(R.id.about);
tv5 = (TextView)layout.findViewById(R.id.search);
tv6 = (TextView)layout.findViewById(R.id.exit);
tv1.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
Toast.makeText(getApplicationContext(), "信息展示", Toast.LENGTH_SHORT).show();
state = 0;
pop.dismiss();
}
});
tv2.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
Toast.makeText(getApplicationContext(), "系統設置", Toast.LENGTH_SHORT).show();
state = 0;
pop.dismiss();
}
});
tv3.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
Toast.makeText(getApplicationContext(), "自動更新", Toast.LENGTH_SHORT).show();
state = 0;
pop.dismiss();
}
});
tv4.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
Toast.makeText(getApplicationContext(), "關於", Toast.LENGTH_SHORT).show();
state = 0;
pop.dismiss();
}
});
tv5.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
Toast.makeText(getApplicationContext(), "搜索", Toast.LENGTH_SHORT).show();
state = 0;
pop.dismiss();
}
});
tv6.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
Toast.makeText(getApplicationContext(), "退出", Toast.LENGTH_SHORT).show();
state = 0;
pop.dismiss();
}
});
}
}
});

不過我這種在布局文件中就設定TextView個數的情況,僅限於菜單項是固定的,如果不固定就不能這么用了(不過貌似手機上的菜單基本就那么幾個)
PS:我上面的代碼是部分源碼,如果直接復制是無法運行的
