官方文檔對(duì)該控件的描述是:“一個(gè)彈出窗口控件,可以用來(lái)顯示任意視圖(View),而且會(huì)浮動(dòng)在當(dāng)前活動(dòng)(activity)的頂部”。PopupWindow可以讓我們實(shí)現(xiàn)多種自定義控件,例如:menu、alertdialog等彈窗似的View。
-
改變PopupWindow的視圖內(nèi)容
可以通過(guò)setContentView來(lái)改變popup的顯示內(nèi)容,也可以用來(lái)初始化PopupWindow的View,比如使用構(gòu)造函數(shù)public PopupWindow (Context context)獲得的Popupwindow就只能用setContentView來(lái)設(shè)置內(nèi)容。
PopupWindow popupWindow = new PopupWindow(context);
popupWindow.setContentView(contentview);
- 獲得PopupWindow的視圖內(nèi)容
public View getContentView()
-
顯示PopupWindow:
- showAsDropDown(View anchor):相對(duì)某個(gè)控件的位置(正左下方),無(wú)偏移
- showAsDropDown(View anchor, int xoff, int yoff):相對(duì)某個(gè)控件的位置,有偏移
- showAtLocation(View parent, int gravity, int x, int y):相對(duì)于父控件的位置(例如正中央Gravity.CENTER,下方Gravity.BOTTOM等),可以設(shè)置偏移或無(wú)偏移
-
有兩種方法設(shè)置PopupWindow的大?。?/strong>
- 調(diào)用有寬高參數(shù)的構(gòu)造函數(shù):
LayoutInflater inflater = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View contentview = inflater.inflate(R.layout.popup_process, null);
PopupWindow popupWindow = new PopupWindow(contentview,LayoutParams.WRAP_CONTENT,LayoutParams.WRAP_CONTENT);
- 通過(guò)setWidth和setHeight設(shè)置
PopupWindow popupWindow = new PopupWindow(contentview);
popupWindow.setWidth(LayoutParams.WRAP_CONTENT);
popupWindow.setHeight(LayoutParams.WRAP_CONTENT);
PopUpWindow的焦點(diǎn):
一般情況下setFocusable(true);
其他任何事件的響應(yīng)都必須發(fā)生在PopupWindow消失之后, (home 等系統(tǒng)層面的事件除外)。比如這樣一個(gè)PopupWindow出現(xiàn)的時(shí)候,按back鍵首先是讓PopupWindow消失,第二次按才是退出activity,準(zhǔn)確的說(shuō)是想退出activity你得首先讓PopupWindow消失,因?yàn)椴徊⑹侨魏吻闆r下按back PopupWindow都會(huì)消失,必須在PopupWindow設(shè)置了背景的情況下 。點(diǎn)擊空白處的時(shí)候讓PopupWindow消失
要讓點(diǎn)擊PopupWindow之外的地方PopupWindow消失你需要調(diào)用setBackgroundDrawable(new BitmapDrawable());
設(shè)置背景,為了不影響樣式,這個(gè)背景是空的。還可以這樣寫,覺(jué)得這樣要保險(xiǎn)些:
setBackgroundDrawable(new ColorDrawable(0x00000000));
背景不為空但是完全透明。如此設(shè)置還能讓PopupWindow在點(diǎn)擊back的時(shí)候消失。
示例:
彈出框布局title_popupwindow.xml:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<ListView
android:id="@+id/popupwindow"
android:background="@drawable/title_background"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:divider="@drawable/title_background_line"
android:listSelector="@drawable/title_background_pressed" //選中的時(shí)候背景圖片
android:cacheColorHint="@android:color/transparent"> //去除listview的拖動(dòng)背景色
</ListView>
</RelativeLayout>
彈出框的item的布局popupwindow_item.xml
<?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="wrap_content"
android:padding="8.0dip" >
<TextView
android:id="@+id/popup_item"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textStyle="bold"
android:singleLine="true"
android:ellipsize="end"
android:textColor="#ffffffff"/>
</RelativeLayout>
寫一個(gè)PopupWindow的派生類MyPopupWindow
public class MyPopupWindow extends PopupWindow {
/**
* 上下文對(duì)象
*/
private Context mContext;
/**
* 回調(diào)接口對(duì)象
*/
private OnPopupWindowClickListener listener;
/**
* ArrayAdapter對(duì)象
*/
private ArrayAdapter adapter;
/**
* ListView的數(shù)據(jù)源
*/
private List<String> list = new ArrayList<String>();
/**
* PopupWindow的寬度
*/
private int width = 0;
public MyPopupWindow(Context context){
super(context);
mContext = context;
initView();
}
private void initView(){
LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View popupView = inflater.inflate(R.layout.title_popupwindow, null);
// 設(shè)置MyPopupWindow的View
this.setContentView(popupView);
//設(shè)置寬度,若沒(méi)有設(shè)置寬度為L(zhǎng)ayoutParams.WRAP_CONTENT
this.setWidth(250);
this.setHeight(LayoutParams.WRAP_CONTENT);
//設(shè)置動(dòng)畫
this.setAnimationStyle(R.style.popupwindow_animation);
//設(shè)置ListView點(diǎn)擊響應(yīng)
this.setFocusable(true);
// 實(shí)例化一個(gè)ColorDrawable顏色為半透明,點(diǎn)back鍵和其他地方使其消失
this.setBackgroundDrawable(new ColorDrawable(0x00000000));
this.setOutsideTouchable(true);
ListView listView = (ListView) popupView.findViewById(R.id.popupwindow);
adapter = new ArrayAdapter(mContext, R.layout.popupwindow_item, R.id.popup_item, list);
listView.setAdapter(adapter);
//ListView的點(diǎn)擊事件
listView.setOnItemClickListener(new OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view,
int position, long id) {
MyPopupWindow.this.dismiss(); //點(diǎn)擊選項(xiàng)后,popupwindow消失
if(listener != null){
listener.onPopupWindowItemClick(position);
}
}
});
}
/**
* 為MyPopupWindow設(shè)置回調(diào)接口
* @param listener
*/
public void setOnPopupWindowClickListener(OnPopupWindowClickListener listener){
this.listener = listener;
}
/**
* 設(shè)置數(shù)據(jù)的方法,供外部調(diào)用
* @param mList
*/
public void changeData(List<String> mList) {
//這里用addAll也很重要,如果用this.list = mList,調(diào)用notifyDataSetChanged()無(wú)效
//notifyDataSetChanged()數(shù)據(jù)源發(fā)生改變的時(shí)候調(diào)用的,this.list = mList,list并沒(méi)有發(fā)生改變
list.addAll(mList);
adapter.notifyDataSetChanged();
}
/**
* 回調(diào)接口.供外部調(diào)用
*/
public interface OnPopupWindowClickListener{
/**
* 當(dāng)點(diǎn)擊PopupWindow的ListView 的item的時(shí)候調(diào)用此方法,用回調(diào)方法的好處就是降低耦合性
* @param position 位置
*/
void onPopupWindowItemClick(int position);
}
}
用到了兩個(gè)動(dòng)畫,在res文件夾下創(chuàng)建anim文件夾,里面創(chuàng)建兩個(gè)動(dòng)畫xml
popupwindow_enter.xml
<?xml version="1.0" encoding="UTF-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate
android:fromXDelta="100%p"
android:toXDelta="0" //這兩行是從右邊進(jìn)
android:duration="500"/>
</set>
popupwindow_exit.xml
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate
android:fromXDelta="0"
android:toXDelta="100%p" //這兩行是往右邊消失
android:duration="500"/>
</set>
在styles.xml里添加
<style name="popupwindow_animation">
<item name="android:windowEnterAnimation">@anim/popupwindow_enter</item>
<item name="android:windowExitAnimation">@anim/popupwindow_exit</item>
</style>
調(diào)用MyPopupWindow
public class PopupActivity extends AppcompatActivity {
MyPopupWindow mPopupWindow;
String [] items = {"刷新列表", "修改密碼", "系統(tǒng)設(shè)置", "添加用戶", "關(guān)于"};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Button mButton = (Button) findViewById(R.id.button1);
mButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View view) {
mPopupWindow.showAsDropDown(view);
}
});
mPopupWindow= new MyPopupWindow(this);
mPopupWindow.changeData(Arrays.asList(items));
mPopupWindow.setOnPopupWindowClickListener(new OnPopupWindowClickListener() {
@Override
public void onPopupWindowItemClick(int position) {
//需要實(shí)現(xiàn)的功能
Toast.makeText(getApplication(), items[position], Toast.LENGTH_SHORT).show();
}
});
}
}
代碼中的回調(diào)機(jī)制:

注:
android:fromXDelta="0" android:toXDelta="-100%p" 往左邊消失
android:fromXDelta="-100%p" android:toXDelta="0" 從左邊進(jìn)
android:fromXDelta="0" android:toXDelta="100%p" 往右邊消失
android:fromXDelta="100%p" android:toXDelta="0" 從右邊進(jìn)
fromXDelta,fromYDelta 起始時(shí)X,Y座標(biāo),屏幕右下角的座標(biāo)是X:320,Y:480
toXDelta, toYDelta 動(dòng)畫結(jié)束時(shí)X,Y的座標(biāo)
interpolator 指定動(dòng)畫插入器
常見(jiàn)的有加速減速插入器 accelerate_decelerate_interpolator
加速插入器 accelerate_interpolator,
減速插入器 decelerate_interpolator。
fromXScale,fromYScale, 動(dòng)畫開(kāi)始前X,Y的縮放,0.0為不顯示, 1.0為正常大小
toXScale,toYScale, 動(dòng)畫最終縮放的倍數(shù), 1.0為正常大小,大于1.0放大
pivotX, pivotY 動(dòng)畫起始位置,相對(duì)于屏幕的百分比,兩個(gè)都為50%表示動(dòng)畫從屏幕中間開(kāi)始
startOffset, 動(dòng)畫多次執(zhí)行的間隔時(shí)間,如果只執(zhí)行一次,執(zhí)行前會(huì)暫停這段時(shí)間,單位毫秒 duration,一次動(dòng)畫效果消耗的時(shí)間,單位毫秒,值越小動(dòng)畫速度越快 repeatCount,動(dòng)畫重復(fù)的計(jì)數(shù),動(dòng)畫將會(huì)執(zhí)行該值+1次
repeatMode,動(dòng)畫重復(fù)的模式,reverse為反向,當(dāng)?shù)谂即螆?zhí)行時(shí),動(dòng)畫方向會(huì)相反。
restart為重新執(zhí)行,方向不變
參考:
PopupWindow的使用以及ArrayAdatper.notifyDataSetChanged()無(wú)效詳解
Android-自定義PopupWindow