官方文档对该控件的描述是:“一个弹出窗口控件,可以用来显示任意视图(View),而且会浮动在当前活动(activity)的顶部”。PopupWindow可以让我们实现多种自定义控件,例如:menu、alertdialog等弹窗似的View。
-
改变PopupWindow的视图内容
可以通过setContentView来改变popup的显示内容,也可以用来初始化PopupWindow的View,比如使用构造函数public PopupWindow (Context context)获得的Popupwindow就只能用setContentView来设置内容。
PopupWindow popupWindow = new PopupWindow(context);
popupWindow.setContentView(contentview);
- 获得PopupWindow的视图内容
public View getContentView()
-
显示PopupWindow:
- showAsDropDown(View anchor):相对某个控件的位置(正左下方),无偏移
- showAsDropDown(View anchor, int xoff, int yoff):相对某个控件的位置,有偏移
- showAtLocation(View parent, int gravity, int x, int y):相对于父控件的位置(例如正中央Gravity.CENTER,下方Gravity.BOTTOM等),可以设置偏移或无偏移
-
有两种方法设置PopupWindow的大小:
- 调用有宽高参数的构造函数:
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);
- 通过setWidth和setHeight设置
PopupWindow popupWindow = new PopupWindow(contentview);
popupWindow.setWidth(LayoutParams.WRAP_CONTENT);
popupWindow.setHeight(LayoutParams.WRAP_CONTENT);
PopUpWindow的焦点:
一般情况下setFocusable(true);
其他任何事件的响应都必须发生在PopupWindow消失之后, (home 等系统层面的事件除外)。比如这样一个PopupWindow出现的时候,按back键首先是让PopupWindow消失,第二次按才是退出activity,准确的说是想退出activity你得首先让PopupWindow消失,因为不并是任何情况下按back PopupWindow都会消失,必须在PopupWindow设置了背景的情况下 。点击空白处的时候让PopupWindow消失
要让点击PopupWindow之外的地方PopupWindow消失你需要调用setBackgroundDrawable(new BitmapDrawable());
设置背景,为了不影响样式,这个背景是空的。还可以这样写,觉得这样要保险些:
setBackgroundDrawable(new ColorDrawable(0x00000000));
背景不为空但是完全透明。如此设置还能让PopupWindow在点击back的时候消失。
示例:
弹出框布局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" //选中的时候背景图片
android:cacheColorHint="@android:color/transparent"> //去除listview的拖动背景色
</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>
写一个PopupWindow的派生类MyPopupWindow
public class MyPopupWindow extends PopupWindow {
/**
* 上下文对象
*/
private Context mContext;
/**
* 回调接口对象
*/
private OnPopupWindowClickListener listener;
/**
* ArrayAdapter对象
*/
private ArrayAdapter adapter;
/**
* ListView的数据源
*/
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);
// 设置MyPopupWindow的View
this.setContentView(popupView);
//设置宽度,若没有设置宽度为LayoutParams.WRAP_CONTENT
this.setWidth(250);
this.setHeight(LayoutParams.WRAP_CONTENT);
//设置动画
this.setAnimationStyle(R.style.popupwindow_animation);
//设置ListView点击响应
this.setFocusable(true);
// 实例化一个ColorDrawable颜色为半透明,点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的点击事件
listView.setOnItemClickListener(new OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view,
int position, long id) {
MyPopupWindow.this.dismiss(); //点击选项后,popupwindow消失
if(listener != null){
listener.onPopupWindowItemClick(position);
}
}
});
}
/**
* 为MyPopupWindow设置回调接口
* @param listener
*/
public void setOnPopupWindowClickListener(OnPopupWindowClickListener listener){
this.listener = listener;
}
/**
* 设置数据的方法,供外部调用
* @param mList
*/
public void changeData(List<String> mList) {
//这里用addAll也很重要,如果用this.list = mList,调用notifyDataSetChanged()无效
//notifyDataSetChanged()数据源发生改变的时候调用的,this.list = mList,list并没有发生改变
list.addAll(mList);
adapter.notifyDataSetChanged();
}
/**
* 回调接口.供外部调用
*/
public interface OnPopupWindowClickListener{
/**
* 当点击PopupWindow的ListView 的item的时候调用此方法,用回调方法的好处就是降低耦合性
* @param position 位置
*/
void onPopupWindowItemClick(int position);
}
}
用到了两个动画,在res文件夹下创建anim文件夹,里面创建两个动画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" //这两行是從右邊進
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>
调用MyPopupWindow
public class PopupActivity extends AppcompatActivity {
MyPopupWindow mPopupWindow;
String [] items = {"刷新列表", "修改密码", "系统设置", "添加用户", "关于"};
@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) {
//需要实现的功能
Toast.makeText(getApplication(), items[position], Toast.LENGTH_SHORT).show();
}
});
}
}
代码中的回调机制:
注:
android:fromXDelta="0" android:toXDelta="-100%p" 往左邊消失
android:fromXDelta="-100%p" android:toXDelta="0" 從左邊進
android:fromXDelta="0" android:toXDelta="100%p" 往右邊消失
android:fromXDelta="100%p" android:toXDelta="0" 從右邊進
fromXDelta,fromYDelta 起始时X,Y座标,屏幕右下角的座标是X:320,Y:480
toXDelta, toYDelta 动画结束时X,Y的座标
interpolator 指定动画插入器
常见的有加速减速插入器 accelerate_decelerate_interpolator
加速插入器 accelerate_interpolator,
减速插入器 decelerate_interpolator。
fromXScale,fromYScale, 动画开始前X,Y的缩放,0.0为不显示, 1.0为正常大小
toXScale,toYScale, 动画最终缩放的倍数, 1.0为正常大小,大于1.0放大
pivotX, pivotY 动画起始位置,相对于屏幕的百分比,两个都为50%表示动画从屏幕中间开始
startOffset, 动画多次执行的间隔时间,如果只执行一次,执行前会暂停这段时间,单位毫秒 duration,一次动画效果消耗的时间,单位毫秒,值越小动画速度越快 repeatCount,动画重复的计数,动画将会执行该值+1次
repeatMode,动画重复的模式,reverse为反向,当第偶次执行时,动画方向会相反。
restart为重新执行,方向不变
参考:
PopupWindow的使用以及ArrayAdatper.notifyDataSetChanged()无效详解
Android-自定义PopupWindow