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:我上面的代码是部分源码,如果直接复制是无法运行的