0
点赞
收藏
分享

微信扫一扫

PopupWindow的一些干货

还有其他关于PopupWindow的文章:
​【达内课程】PopupWindow

文章目录

  • ​​一、 概述​​
  • ​​1、PopupWindow与AlertDialog的区别​​
  • ​​2、PopupWindow的相关函数​​
  • ​​二、简单示例(showAtLocation显示窗体)​​
  • ​​三、简单示例(showAsDropDown显示窗体)​​
  • ​​四、为菜单添加阴影​​
  • ​​五、为PopupWindow添加动画​​
  • ​​六、弹出时屏幕背景变暗​​
  • ​​七、使用总结​​
  • ​​八、常见函数讲解​​
  • ​​1、setTouchable(boolean touchable)​​
  • ​​2、setFocusable(boolean focusable)​​
  • ​​3、setOutsideTouchable(boolean touchable)​​
  • ​​九、为什么要强制代码设置PopupWindow的Height、Width​​
  • ​​1、源码角度​​
  • ​​2、布局角度​​
  • ​​十、一些问题​​
  • ​​Popupwindow showAsDropDown全面屏显示异常​​

一、 概述

1、PopupWindow与AlertDialog的区别

最关键的区别是AlertDialog不能指定显示位置,只能默认显示在屏幕最中间(当然也可以通过设置WindowManager参数来改变位置)。而PopupWindow是可以指定显示位置的,随便哪个位置都可以,更加灵活

相同点
这两个都是弹窗

不同点

  1. popupwindow在显示之前一定要设置宽高,Dialog不用
  2. popupwindow默认不会响应物理键盘的返回键,只有设置了popup.setfocusable(true)时才会响应,Dialog会响应物理键盘
  3. Popupwindow不会给页面其他的部分添加蒙层,而Dialog会
  4. Popupwindow没有标题,Dialog默认有标题,可以通过dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);取消标题
  5. 二者显示的时候都要设置Gravity。如果不设置,Dialog默认是Gravity.CENTER
  6. 二者都有默认的背景,都可以通过setBackgroundDrawable(new ColorDrawable(android.R.color.transparent));去掉
  7. AlertDialog是非阻塞式对话框:AlertDialog弹出时,后台还可以做事情;而PopupWindow是阻塞式对话框:PopupWindow弹出时,程序会等待,在PopupWindow退出前,程序一直等待,只有当我们调用了dismiss方法的后,PopupWindow退出,程序才会向下执行
    (这两种表现最直接的解释方式:AlertDialog弹出时背景是黑的,当我们点击背景时AlertDialog会消失,这证明了程序不仅响应会AlertDialog,还会响应其他操作,这证明AlertDialog是非阻塞式对话框;popupwindow弹出时背景没什么变化,当我们点击背景时程序没有响应,只允许我们操作popupwindow,其他操作被阻塞)

2、PopupWindow的相关函数

(1)构造函数

//方法一:  
public PopupWindow (Context context);
//方法二:
public PopupWindow(View contentView);
//方法三:
public PopupWindow(View contentView, int width, int height);
//方法四:
public PopupWindow(View contentView, int width, int height, boolean focusable);

看这里有四个构造函数,但要生成一个PopupWindow最基本的三个条件是一定要设置的:View contentView,int width, int height

所以,如果使用方法一来构造PopupWindow,那完整的构造代码应该是这样的:

View contentView = LayoutInflater.from(MainActivity.this).inflate(R.layout.popuplayout, null);  
PopupWindwo popWnd = PopupWindow (context);
popWnd.setContentView(contentView);
popWnd.setWidth(ViewGroup.LayoutParams.WRAP_CONTENT);
popWnd.setHeight(ViewGroup.LayoutParams.WRAP_CONTENT);

(2)显示函数

//相对某个控件的位置(正左下方),无偏移  
showAsDropDown(View anchor):
//相对某个控件的位置,有偏移;xoff表示x轴的偏移,正值表示向左,负值表示向右;yoff表示相对y轴的偏移,正值是向下,负值是向上;
showAsDropDown(View anchor, int xoff, int yoff):
//相对于父控件的位置(例如正中央Gravity.CENTER,下方Gravity.BOTTOM等),可以设置偏移或无偏移
showAtLocation(View parent, int gravity, int x, int y):

这里有两种显示方式:
1、显示在某个指定控件的下方
showAsDropDown(View anchor):
showAsDropDown(View anchor, int xoff, int yoff);
2、指定父视图,显示在父控件的某个位置(Gravity.TOP,Gravity.RIGHT等)
showAtLocation(View parent, int gravity, int x, int y);

(3)其它函数

//用于不需要的时候,将窗体隐藏掉
public void dismiss()
public void setFocusable(boolean focusable)
public void setTouchable(boolean touchable)
public void setOutsideTouchable(boolean touchable)
public void setBackgroundDrawable(Drawable background)

二、简单示例(showAtLocation显示窗体)

PopupWindow的一些干货_android

1、popupwindow布局(popuplayout1.xml)

<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:background="#e5e5e5"
android:orientation="vertical">

<TextView
android:id="@+id/pop_computer"
android:layout_width="match_parent"
android:layout_height="30dp"
android:text="计算机"
android:gravity="center"/>

<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="#000"/>

<TextView
android:id="@+id/pop_financial"
android:layout_width="match_parent"
android:layout_height="30dp"
android:text="金融"
android:gravity="center"/>

<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="#000"/>

<TextView
android:id="@+id/pop_manage"
android:layout_width="match_parent"
android:layout_height="30dp"
android:text="管理"
android:gravity="center"/>

<View
android:layout_width="match_parent"
android:layout_height="1dp"/>

</LinearLayout>

2、MainActivity关键代码

@Override
public void onClick(View view) {
switch (view.getId()){
case R.id.btn1:
showPopupWindow1();
break;
case R.id.pop_computer:
case R.id.pop_financial:
case R.id.pop_manage:
Toast.makeText(this,"Hello Popupwindow",Toast.LENGTH_SHORT).show();
break;
}
}

private void showPopupWindow1() {
//利用LayoutInflater获取R.layout.popuplayout1对应的View,然后利用我们上面所讲的构造函数三来生成mPopWindow
View contentView = LayoutInflater.from(MainActivity.this).inflate(R.layout.popuplayout1, null);
//如果在代码中重新设置了popupWindow的宽和高,那就以代码中所设置为准。
PopupWindow mPopWindow = new PopupWindow(contentView, LinearLayoutCompat.LayoutParams.MATCH_PARENT,
LinearLayoutCompat.LayoutParams.WRAP_CONTENT, true);
mPopWindow.setContentView(contentView);
//设置各个控件的点击响应
TextView tv1 = contentView.findViewById(R.id.pop_computer);
TextView tv2 = contentView.findViewById(R.id.pop_financial);
TextView tv3 = contentView.findViewById(R.id.pop_manage);
tv1.setOnClickListener(this);
tv2.setOnClickListener(this);
tv3.setOnClickListener(this);
//我们将R.layout.main做为它的父容器。将其显示在BOTTOM的位置
View rootview = LayoutInflater.from(MainActivity.this).inflate(R.layout.activity_main,
null);
mPopWindow.showAtLocation(rootview, Gravity.BOTTOM, 0, 0);
}

三、简单示例(showAsDropDown显示窗体)

PopupWindow的一些干货_xml_02

1、popupwindow布局(popuplayout2.xml)

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/pop_bg">

<LinearLayout
android:layout_width="150dp"
android:layout_height="wrap_content"
android:orientation="vertical">

<TextView
android:layout_width="match_parent"
android:layout_height="30dp"
android:gravity="center"
android:text="计算机" />

<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="#ccc" />

<TextView
android:layout_width="match_parent"
android:layout_height="30dp"
android:gravity="center"
android:text="金融" />

<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="#ccc" />

<TextView
android:layout_width="match_parent"
android:layout_height="30dp"
android:gravity="center"
android:text="管理" />

<View
android:layout_width="match_parent"
android:layout_height="1dp" />

</LinearLayout>
</LinearLayout>

其中pop_bug是.9图

PopupWindow的一些干货_ide_03

2、MainActivity关键代码

这里在右上角添加了菜单按钮,点击按钮显示popupwindow在其下方

public class MainActivity extends AppCompatActivity implements View.OnClickListener {
......

@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu_option,menu);
return true;
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()){
case R.id.btn2:
showPopupWindow2();
break;
}
return super.onOptionsItemSelected(item);
}

private void showPopupWindow2() {
//使用的构造方法二来生成的PopupWindow实例
View contentView = LayoutInflater.from(MainActivity.this).inflate(R.layout.popuplayout2, null);
PopupWindow mPopWindow = new PopupWindow(contentView);
mPopWindow.setWidth(ViewGroup.LayoutParams.WRAP_CONTENT);
mPopWindow.setHeight(ViewGroup.LayoutParams.WRAP_CONTENT);
mPopWindow.setFocusable(true);
//使用showAsDropDown()显示PopupWindow
mPopWindow.showAsDropDown(findViewById(R.id.btn2));
}
}

四、为菜单添加阴影

Android 6.0显示效果如下:
PopupWindow的一些干货_ide_04
1、popupwindow布局(popuplayout3.xml)

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#66000000">

<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/pop_bg"
android:orientation="vertical"
android:layout_alignParentRight="true"
>

<TextView
android:id="@+id/pop_computer"
style="@style/pop_text_style"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="计算机"/>

<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="#ccc"/>

<TextView
android:id="@+id/pop_financial"
style="@style/pop_text_style"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="金融"/>

<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="#ccc"/>

<TextView
android:id="@+id/pop_manage"
style="@style/pop_text_style"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="管理"/>

<View
android:layout_width="match_parent"
android:layout_height="1dp"/>

</LinearLayout>
</RelativeLayout>

2、MainActivity代码

private void showPopupWindow3() {
View contentView = LayoutInflater.from(MainActivity.this).inflate(R.layout.popuplayout3, null);
View relativelayout = contentView.findViewById(R.id.relativelayout);
final PopupWindow mPopWindow = new PopupWindow(contentView);
mPopWindow.setWidth(ViewGroup.LayoutParams.MATCH_PARENT);
mPopWindow.setHeight(ViewGroup.LayoutParams.MATCH_PARENT);
mPopWindow.showAsDropDown(findViewById(R.id.btn2));
relativelayout.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
mPopWindow.dismiss();
}
});
}

五、为PopupWindow添加动画

PopupWindow的一些干货_ide_05

1、进入时的动画:(popup_enter.xml)

<?xml version="1.0" encoding="utf-8"?>  
<set xmlns:android="http://schemas.android.com/apk/res/android">
<scale
android:duration="240"
android:fromXScale="0.0"
android:fromYScale="0.0"
android:pivotX="100%"
android:pivotY="0%"
android:toXScale="1.0"
android:toYScale="1.0" />
<alpha
android:duration="240"
android:fromAlpha="0.0"
android:toAlpha="1.0" />
</set>

2、退出时动画(popup_exit.xml)

<?xml version="1.0" encoding="utf-8"?>  
<set xmlns:android="http://schemas.android.com/apk/res/android">
<scale
android:duration="300"
android:fromXScale="1.0"
android:fromYScale="1.0"
android:pivotX="100%"
android:pivotY="0%"
android:toXScale="0.0"
android:toYScale="0.0" />
<alpha
android:duration="300"
android:fromAlpha="1.0"
android:toAlpha="0.0" />
</set>

3、生成对应的style

    <style name="popupwindow_style">
<item name="android:windowEnterAnimation">@anim/popup_enter</item>
<item name="android:windowExitAnimation">@anim/popup_exit</item>
</style>

4、使用AnimationStyle

mPopWindow.setAnimationStyle(R.style.popupwindow_style);  

六、弹出时屏幕背景变暗

PopupWindow的一些干货_popupwindow_06
MainActivity关键代码

//弹出时屏幕变暗
private void showPopupWindow4() {
View contentView = LayoutInflater.from(MainActivity.this).inflate(R.layout.popuplayout2, null);
final PopupWindow mPopWindow = new PopupWindow(contentView);
mPopWindow.setWidth(ViewGroup.LayoutParams.WRAP_CONTENT);
mPopWindow.setHeight(ViewGroup.LayoutParams.WRAP_CONTENT);
mPopWindow.setFocusable(true);
mPopWindow.showAsDropDown(findViewById(R.id.btn2));

backgroundAlpha(0.75f);
mPopWindow.setOnDismissListener(new PopupWindow.OnDismissListener() {
@Override
public void onDismiss() {
backgroundAlpha(1f);
}
});
}

// 设置屏幕透明度
public void backgroundAlpha(float bgAlpha) {
WindowManager.LayoutParams lp = getWindow().getAttributes();
lp.alpha = bgAlpha; // 0.0~1.0
getWindow().setAttributes(lp);
}

七、使用总结

一个常规Popupwindow的使用,代码如下:

PopupWindow popupWindow = new PopupWindow();

popupWindow.setWidth(ViewGroup.LayoutParams.WRAP_CONTENT);
popupWindow.setHeight(ViewGroup.LayoutParams.WRAP_CONTENT);
popupWindow.setContentView(View.inflate(this, R.layout.layout_popup, null));

popupWindow.setBackgroundDrawable(new ColorDrawable(0x00000000));
popupWindow.setFocusable(true);
popupWindow.setOutsideTouchable(false);

popupWindow.setAnimationStyle(R.style.anim_menu_bottombar);

popupWindow.showAsDropDown(bt_popup, 0, 0);

首先肯定是创建一个PopupWindow对象了,当然,它肯定还有许多带参数的构造方法
然后就是设置三连,设置宽高,设置布局View。 如果想要显示一个弹窗, 这三句话是必须的
然后​​​popupWindow.setBackgroundDrawable(new ColorDrawable(0x00000000));​​​这个很有意思。在高版本的android中(比如8.0),可以不写。但是低版本就不行了(比如4.1), 低版本不写的话, 会导致点击返回或者是屏幕其它地方无法取消弹窗。所以稳妥起见还是加上,并设置一个透明色
​​​popupWindow.setFocusable(true);​​​是比较重要的,一般都为true,也就是弹窗之后,焦点就到了弹窗,你再点击其它地方,弹窗失去焦点就会消失
​​​popupWindow.setOutsideTouchable(false);​​​这句在之前那句为true的前提下, true 和 false效果几乎一样
再往下是添加一个动画效果,你可以用默认的,或者自定义
最后一句显示弹窗,默认对齐左下,后面两个参数是偏移值

八、常见函数讲解

1、setTouchable(boolean touchable)

设置PopupWindow是否响应touch事件,默认是true,如果设置为false,所有touch事件无响应,包括点击事件

2、setFocusable(boolean focusable)

该函数的意义表示,PopupWindow是否具有获取焦点的能力,默认为False。一般来讲是没有用的,因为普通的控件是不需要获取焦点的,而对于EditText则不同,如果不能获取焦点,那么EditText将是无法编辑的

mPopWindow.setFocusable(true);  

在点击EditText的时候,会弹出编辑框。

mPopWindow.setFocusable(false);  

点击EditText没有出现任何反应

3、setOutsideTouchable(boolean touchable)

这个函数的意义,就是指,PopupWindow以外的区域是否可点击,即如果点击PopupWindow以外的区域,PopupWindow是否会消失。

mPopWindow.setOutsideTouchable(true); 

九、为什么要强制代码设置PopupWindow的Height、Width

1、源码角度

我们明明可以看到 layout_width 我们设置为了"fill_parent",layout_height设置为了“fill_parent”;为什么非要我们在代码中还要再设置一遍。如果我们没有设置 width 和 height,那 mWidth 和 mHeight 将会取默认值0!!!!所以当我们没有设置 width 和 height 时,并不是我们的窗体没有弹出来,而是因为他们的 width 和 height 都是0了

2、布局角度

<RelativeLayout  
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/pop_bg"
android:orientation="vertical"
android:paddingBottom="2dp"
android:layout_alignParentRight="true">

<TextView
android:id="@+id/pop_computer"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
style="@style/pop_text_style"
android:text="计算机"/>
</LinearLayout>
</RelativeLayout>

TextView的显示大小是由谁来决定的?
是由它自己的布局 layout_width=“wrap_content”、layout_height="wrap_content"来决定的吗?
当然不是!它的大小,应该是在它父控件的基础上决定的。即 LinearLayout 的显示大小确定了以后,才能确定TextView的大小
这好比,如果 LinearLayout 的大小是全屏的,那 TextView 的大小就由它自己来决定了,那如果 LinearLayout 的大小只有一像素呢?那 TextView 的所显示的大小无论它自己怎么设置,最大也就显示一像素
所以我们的结论来了:控件的大小,是建立在父控件大小确定的基础上的
那同样:LinearLayout 的大小确定是要靠 RelativeLayout 来决定
那问题来了:RelativeLayout的大小靠谁决定呢?
当然是它的父控件了

我们的contentView是怎么来的呢?

View contentView = LayoutInflater.from(MainActivity.this).inflate(R.layout.popuplayout, null);  

直接inflate出来的,我们对它没有设置根结点
那问题来了?它的大小由谁来解决呢?
好像没有谁能决定了,因为他没有父结点。那它到底是多大呢?未知…
所以只有通过代码让用户去手动设置了!所以这就是为什么非要用户设置 width 和 height 的原因了

十、一些问题

Popupwindow showAsDropDown全面屏显示异常

Popupwindow showAsDropDown全面屏显示异常

​ https://github.com/zaaach/TopRightMenu​

​ https://www.imooc.com/article/67949

举报

相关推荐

0 条评论