Activity
public class MainActivity extends ListActivity {
private PopupWindow pop;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
String[] array = { "在指定view的正左下方,无偏移", //
"相对指定view正左下方,有偏移",//
"Gravity.NO_GRAVITY:相对屏幕左上角,注意包含状态栏区域",//
"Gravity.TOP:相对屏幕正上方居中",//
"pop不会偏移出屏幕,偏移值过大时取临界值",//
"Gravity.BOTTOM:相对屏幕正下方居中,注意包含虚拟按键区域",//
"Gravity.BOTTOM:此时yoff为正时表示向上偏移(而非向下偏移)",//
"出现在View的任意位置", };
setListAdapter(new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, new ArrayList<String>(Arrays.asList(array))));
pop = new PopupWindow(this);
pop.setFocusable(true);//必备设置1
pop.setBackgroundDrawable(new ColorDrawable(0x00ff0000));//必备设置2
pop.setOutsideTouchable(true);//setFocusable(true)后这个设置就没用了
pop.setAnimationStyle(R.style.popAniStyle);//设置动画所对应的style
}
private boolean b;
@Override
protected void onListItemClick(ListView l, View v, int position, long id) {
b = !b;
if (b) pop.setContentView(LayoutInflater.from(this).inflate(R.layout.view1, null));
else pop.setContentView(LayoutInflater.from(this).inflate(R.layout.view2, null));
switch (position) {
case 0://在指定view的正左下方,无偏移
pop.setWidth(LinearLayout.LayoutParams.WRAP_CONTENT);//必须设置宽和高
pop.setHeight(LinearLayout.LayoutParams.WRAP_CONTENT);
pop.showAsDropDown(v);
break;
case 1://相对指定view正左下方的位置,有偏移
pop.setWidth(DensityUtils.getScreenWidth(this) - 20);
pop.setHeight(LinearLayout.LayoutParams.WRAP_CONTENT);
pop.showAsDropDown(v, 20, 10);
break;
case 2://相对于父控件的某个相对位置的偏移,默认的Gravity.NO_GRAVITY的参照物为【屏幕左上角】,注意包含状态栏区域
case 3://若偏移值大于pop偏出屏幕的临界值,将取临界值。也即pop不可能会偏移出屏幕
case 4://不管view设置的是哪一个,参照物都是整个屏幕的根布局
pop.setWidth(DensityUtils.getScreenWidth(this) - 20);
pop.setHeight(20);
if (position == 2) pop.showAtLocation(v, Gravity.NO_GRAVITY, 20, DensityUtils.getStatusBarHeight(this) + 10);//Gravity.NO_GRAVITY:相对屏幕左上角
else if (position == 3) pop.showAtLocation(v, Gravity.TOP, 10, DensityUtils.getStatusBarHeight(this) + 10);//Gravity.TOP:相对屏幕正上方居中
else pop.showAtLocation(v, Gravity.TOP, 100, DensityUtils.getStatusBarHeight(this));//临界值为 20/2=10,偏移值大于10时仅偏移10
break;
case 5://Gravity.BOTTOM:相对屏幕正下方居中,注意包含虚拟按键区域,并且此时yoff为正时表示向上偏移(而非向下偏移)
case 6://
pop.setWidth(DensityUtils.getScreenWidth(this) - 20);
pop.setHeight(LinearLayout.LayoutParams.WRAP_CONTENT);
if (position == 5) pop.showAtLocation(v, Gravity.BOTTOM, 0, DensityUtils.getBottomBarHeight(this));//Gravity.BOTTOM:相对屏幕正下方居中
else if (position == 6) pop.showAtLocation(v, Gravity.BOTTOM, -10, DensityUtils.getBottomBarHeight(this) + 10);//此时yoff为正时表示向上偏移
break;
case 7://
startActivity(new Intent(this, SecondActivity.class));
break;
}
}
}Activity2
public class SecondActivity extends Activity {
private int num = 0;
private PopupWindow pop;
private int[] location = new int[2];;
private View contentView;
@SuppressLint("InflateParams")
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.layout);
contentView = LayoutInflater.from(this).inflate(R.layout.view2, null);
pop = new PopupWindow(contentView, LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT);
pop.setFocusable(true);//必备设置1
pop.setBackgroundDrawable(new ColorDrawable(0x00ff0000));//必备设置2
pop.setOutsideTouchable(true);//setFocusable(true)后这个设置就没用了
pop.setAnimationStyle(R.style.popAniStyle);//设置动画所对应的style
}
public void onClick(View v) {
v.getLocationOnScreen(location);// 获取锚点View在屏幕上的左上角坐标位置
switch (num % 4) {
case 0://右下
pop.showAtLocation(v, Gravity.NO_GRAVITY, location[0] + v.getWidth(), location[1] + v.getHeight());
break;
case 1://右上
pop.showAtLocation(v, Gravity.NO_GRAVITY, location[0] + v.getWidth(), location[1] - contentView.getHeight());
break;
case 2://左上
pop.showAtLocation(v, Gravity.NO_GRAVITY, location[0] - contentView.getWidth(), location[1] - contentView.getHeight());
break;
default://左下
pop.showAtLocation(v, Gravity.NO_GRAVITY, location[0] - contentView.getWidth(), location[1] + v.getHeight());
break;
}
Toast.makeText(this, num % 4 + "", Toast.LENGTH_SHORT).show();
num++;
}
}工具类
public class DensityUtils {
//******************************************************************************************
// 单位转换
//******************************************************************************************
/**像素密度*/
public static float getDisplayMetrics(Context context) {
return context.getResources().getDisplayMetrics().density;
}
/** dp 转成为 px */
public static int dp2px(Context context, float dpValue) {
return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dpValue, context.getResources().getDisplayMetrics());
}
/** px 转成为 dp */
public static int px2dp(Context context, float pxValue) {
return (int) (pxValue / getDisplayMetrics(context) + 0.5f);
}
/** sp转px */
public static int sp2px(Context context, float spVal) {
return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, spVal, context.getResources().getDisplayMetrics());
}
/** px转sp */
public static float px2sp(Context context, float pxVal) {
return (pxVal / context.getResources().getDisplayMetrics().scaledDensity);
}
//******************************************************************************************
// 屏幕宽高
//******************************************************************************************
/** 获取屏幕宽 */
public static int getScreenWidth(Context context) {
DisplayMetrics metric = new DisplayMetrics();
((WindowManager) context.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay().getMetrics(metric);
return metric.widthPixels;
}
/** 获取屏幕高,包含状态栏,但不包含虚拟按键,如1920屏幕只有1794 */
public static int getScreenHeight(Context context) {
DisplayMetrics metric = new DisplayMetrics();
((WindowManager) context.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay().getMetrics(metric);
return metric.heightPixels;
}
/** 获取屏幕宽 */
public static int getScreenWidth2(Context context) {
Point point = new Point();
((WindowManager) context.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay().getSize(point);
return point.x;
}
/** 获取屏幕高,包含状态栏,但不包含某些手机最下面的【HOME键那一栏】,如1920屏幕只有1794 */
public static int getScreenHeight2(Context context) {
Point point = new Point();
((WindowManager) context.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay().getSize(point);
return point.y;
}
/** 获取屏幕原始尺寸高度,包括状态栏以及虚拟功能键高度 */
public static int getAllScreenHeight(Context context) {
Display display = ((WindowManager) context.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
try {
DisplayMetrics displayMetrics = new DisplayMetrics();
Method method = Class.forName("android.view.Display").getMethod("getRealMetrics", DisplayMetrics.class);
method.invoke(display, displayMetrics);
return displayMetrics.heightPixels;
} catch (Exception e) {
e.printStackTrace();
}
return 0;
}
//******************************************************************************************
// 状态栏、标题栏、虚拟按键
//******************************************************************************************
/** 状态栏高度,单位px,一般为25dp */
public static int getStatusBarHeight(Context context) {
int height = 0;
int resourceId = context.getResources().getIdentifier("status_bar_height", "dimen", "android");
if (resourceId > 0) {
height = context.getResources().getDimensionPixelSize(resourceId);
}
return height;
}
/** 状态栏高度,单位px,【注意】要在onWindowFocusChanged中获取才可以 */
public static int getStatusBarHeight2(Activity activity) {
Rect rect = new Rect();
//DecorView是Window中的最顶层view,可以从DecorView获取到程序显示的区域,包括标题栏,但不包括状态栏。所以状态栏的高度即为显示区域的top坐标值
activity.getWindow().getDecorView().getWindowVisibleDisplayFrame(rect);
return rect.top;
}
/**标题栏的高度,【注意】要在onWindowFocusChanged中获取才可以*/
public static int getTitleBarHeight(Activity activity) {
int contentTop = activity.getWindow().findViewById(Window.ID_ANDROID_CONTENT).getTop();
return contentTop - getStatusBarHeight(activity);
}
/**获取 虚拟按键的高度 */
public static int getBottomBarHeight(Context context) {
return getAllScreenHeight(context) - getScreenHeight(context);
}
}