• 从底部弹出的选择框
  • 使用popupWindow完成:
    • 定义popupWindow类
    • 自定义Style
    • 定义进入和退出的动画:
  • 使用Dialog完成:
    • 定义style
    • 动画: 和popupwindow一致
    • 自定义Dialog:
    • 在Activity中调用:
  • 详细的区别

    从底部弹出的选择框

    popupwindow

    dialog

    使用popupWindow完成:

    定义popupWindow类

    1. /**
    2. * 选择照片的PopupWindow
    3. * Created by chenlijin on 2016/4/12.
    4. */
    5. public class SelectPicPopupWindow extends PopupWindow implements View.OnTouchListener, View.OnKeyListener {
    6. private Context mContext;
    7. private View rootView;
    8. public SelectPicPopupWindow(Context context) {
    9. mContext = context;
    10. LayoutInflater inflater = LayoutInflater.from(context);
    11. rootView = inflater.inflate(R.layout.popupwindow_selectpic, null);
    12. setContentView(rootView);
    13. ButterKnife.bind(this, rootView);
    14. //设置高度和宽度。
    15. this.setHeight(ViewGroup.LayoutParams.WRAP_CONTENT);
    16. this.setWidth(ViewGroup.LayoutParams.MATCH_PARENT);
    17. this.setFocusable(true);
    18. //设置动画效果
    19. this.setAnimationStyle(R.style.mypopwindow_anim_style);
    20. //当单击Back键或者其他地方使其消失、需要设置这个属性。
    21. rootView.setOnTouchListener(this);
    22. rootView.setOnKeyListener(this);
    23. rootView.setFocusable(true);
    24. rootView.setFocusableInTouchMode(true);
    25. //实例化一个ColorDrawable颜色为半透明
    26. ColorDrawable dw = new ColorDrawable(0xb0000000);
    27. //设置SelectPicPopupWindow弹出窗体的背景
    28. this.setBackgroundDrawable(dw);
    29. }
    30. //点击外部popup消失
    31. @Override
    32. public boolean onTouch(View v, MotionEvent event) {
    33. int height = rootView.findViewById(R.id.linearlayout_window).getTop();
    34. int y = (int) event.getY();
    35. if (event.getAction() == MotionEvent.ACTION_UP) {
    36. if (y < height) {
    37. dismiss();
    38. }
    39. }
    40. return true;
    41. }
    42. //点back键消失
    43. @Override
    44. public boolean onKey(View v, int keyCode, KeyEvent event) {
    45. if (keyCode == KeyEvent.KEYCODE_BACK && this.isShowing()) {
    46. this.dismiss();
    47. return true;
    48. }
    49. return false;
    50. }
    51. @OnClick({R.id.button_take_photo, R.id.button_select_pic, R.id.button_cancal})
    52. public void onClick(View view) {
    53. switch (view.getId()) {
    54. case R.id.button_take_photo:
    55. listener.onClickTakePhoto();
    56. this.dismiss();
    57. break;
    58. case R.id.button_select_pic:
    59. listener.onClickSelectPic();
    60. this.dismiss();
    61. break;
    62. case R.id.button_cancal:
    63. this.dismiss();
    64. break;
    65. }
    66. }
    67. private OnWindowItemClickListener listener;
    68. public void setOnWindowItemClickListener(OnWindowItemClickListener listener) {
    69. this.listener = listener;
    70. }
    71. public interface OnWindowItemClickListener {
    72. void onClickTakePhoto();
    73. void onClickSelectPic();
    74. }
    75. }

    自定义Style

    1. <style name="MyPopup" parent="android:style/Theme.Dialog">
    2. <item name="android:windowFrame">@null</item>
    3. <item name="android:windowNoTitle">true</item>
    4. <item name="android:windowBackground">@color/popup</item>
    5. <item name="android:windowIsFloating">true</item>
    6. <item name="android:windowContentOverlay">@null</item>
    7. </style>

    定义进入和退出的动画:

    1. 进入:
    2. <?xml version="1.0" encoding="utf-8"?>
    3. <set xmlns:android="http://schemas.android.com/apk/res/android">
    4. <translate
    5. android:duration="200"
    6. android:fromYDelta="100.0%"
    7. android:toYDelta="0.0"/>
    8. </set>
    9. 退出
    10. <?xml version="1.0" encoding="utf-8"?>
    11. <set xmlns:android="http://schemas.android.com/apk/res/android">
    12. <translate
    13. android:duration="200"
    14. android:fromYDelta="0.0"
    15. android:toYDelta="100.0%"/>
    16. </set>
    17. 动画的style
    18. <style name="mypopwindow_anim_style">
    19. <item name="android:windowEnterAnimation">@anim/popup_in</item>
    20. <!-- 指定显示的动画xml -->
    21. <item name="android:windowExitAnimation">@anim/popup_out</item>
    22. <!-- 指定消失的动画xml -->
    23. </style>

    在指定的位置显示

    1. //显示窗口
    2. window.showAtLocation(MainActivity.this.findViewById(R.id.main), Gravity.BOTTOM|Gravity.CENTER_HORIZONTAL, 0, 0); //设置layout在PopupWindow中显示的位置

    使用Dialog完成:

    定义style

    1. <!--自定义布局的dialog-->
    2. <style name="MyDialog" parent="android:style/Theme.Dialog">
    3. <!-- 背景颜色及透明程度 -->
    4. <item name="android:windowBackground">@android:color/transparent</item>
    5. <!-- 是否有标题 -->
    6. <item name="android:windowNoTitle">true</item>
    7. <!-- 是否浮现在activity之上,会造成macth_parent失效-->
    8. <item name="android:windowIsFloating">false</item>
    9. <!-- 是否模糊 -->
    10. <item name="android:backgroundDimEnabled">true</item>
    11. <item name="android:windowFrame">@null</item>
    12. </style>

    动画: 和popupwindow一致

    自定义Dialog:

    1. /**
    2. * 选择图片对话框
    3. * Created by chenlijin on 2016/4/12.
    4. */
    5. public class SelectPicDialog extends Dialog {
    6. public SelectPicDialog(Context context, int themeResId) {
    7. super(context, themeResId);
    8. }
    9. @Override
    10. protected void onCreate(Bundle savedInstanceState) {
    11. super.onCreate(savedInstanceState);
    12. setContentView(R.layout.dialog_select_pic);
    13. ButterKnife.bind(this);
    14. }
    15. @OnClick({R.id.linearlayout_out,R.id.textview_take_photo, R.id.textview_select_photo, R.id.textview_cancal})
    16. public void onClick(View view) {
    17. switch (view.getId()) {
    18. case R.id.textview_take_photo:
    19. if(listener!=null){
    20. listener.onClickTakePhoto();
    21. }
    22. this.cancel();
    23. break;
    24. case R.id.textview_select_photo:
    25. if(listener!=null){
    26. listener.onClickSelectPic();
    27. }
    28. this.cancel();
    29. break;
    30. case R.id.linearlayout_out:
    31. case R.id.textview_cancal:
    32. this.cancel();
    33. break;
    34. }
    35. }
    36. private OnWindowItemClickListener listener;
    37. public void setOnWindowItemClickListener(OnWindowItemClickListener listener) {
    38. this.listener = listener;
    39. }
    40. public interface OnWindowItemClickListener {
    41. void onClickTakePhoto();
    42. void onClickSelectPic();
    43. }
    44. }

    在Activity中调用:

    1. SelectPicDialog dialog = new SelectPicDialog(mContext,R.style.MyDialog);
    2. Window window = dialog.getWindow();
    3. window.setGravity(Gravity.BOTTOM); //此处可以设置dialog显示的位置
    4. window.setWindowAnimations(R.style.mypopwindow_anim_style); //添加动画
    5. dialog.show();
    6. dialog.setOnWindowItemClickListener(new SelectPicDialog.OnWindowItemClickListener(){
    7. @Override
    8. public void onClickTakePhoto() {
    9. startActivityForResult(createCameraIntent(), CREATE_CAMERA); //选择拍照
    10. }
    11. @Override
    12. public void onClickSelectPic() {
    13. startActivityForResult(createPickIntent(), CREATE_PICK); //选择启用系统的选择图片
    14. }
    15. });

    详细的区别

    (1)Popupwindow在显示之前一定要设置宽高,Dialog无此限制。

    (2)Popupwindow默认不会响应物理键盘的back,除非显示设置了popup.setFocusable(true);而在点击back的时候,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));去掉。

    其中最本质的差别就是:AlertDialog是非阻塞式对话框:AlertDialog弹出时,后台还可以做事情;而PopupWindow是阻塞式对话框:PopupWindow弹出时,程序会等待,在PopupWindow退出前,程序一直等待,只有当我们调用了dismiss方法的后,PopupWindow退出,程序才会向下执行。这两种区别的表现是:AlertDialog弹出时,背景是黑色的,但是当我们点击背景,AlertDialog会消失,证明程序不仅响应AlertDialog的操作,还响应其他操作,其他程序没有被阻塞,这说明了AlertDialog是非阻塞式对话框;PopupWindow弹出时,背景没有什么变化,但是当我们点击背景的时候,程序没有响应,只允许我们操作PopupWindow,其他操作被阻塞。

    注意: 这里讲的阻塞并非线程阻塞,而是阻塞了其他UI操作,详情见:PopupWindow的”阻塞”问题