(Transfer) Android encapsulates a general Dialog based on DialogFragment

Original address: https://blog.csdn.net/u013700502/article/details/82777402#_55

 

Article Directory
1. Background
2. Renderings
3. Why choose DialogFragment?
4. UML diagram
5. Using documents
1. Using built-in dialog:
2. Using custom layout style:
3. Unified management of multiple Dialogs popping up in sequence
6. Source code address
7. Update
1. Background
Dialog is the most commonly used one in the project One of the functions, when I took over the project, I found that a dialog was encapsulated in the project, but I found that it was encapsulated with a singleton, roughly as follows:

    private MyDialog() {
     }

    public static MyDialog getInstance() {
        return DialogHolder.instance;
    }

    private static class DialogHolder {
        private static MyDialog instance = new MyDialog();
    }
   
   public void show(){}
   public void dismiss(){}


In addition to the possibility of memory leaks when using a singleton, a problem is also found during use: dialogs on different pages can affect each other, which is right when you think about it, because there is only one dialog globally. There is a scenario in the project: page A jumps to B Page, when you enter the onCreate() of page B, you need to pop up a dialog, but you can’t pop up every time. Debugging found that the dismiss() method was called in the onStop() method of page A, and page A skipped the life cycle of page B. The way to go is:

 A页面:   onPause()
 B页面:    onCreate()
 B页面:    onStart()
 B页面:    onResume()
 A页面:    onStop()


So the reason is also found. Every time show() is called in B's onCreate(), and then dismiss() in A's onStop() is called to turn it off. It is obviously not suitable to use the singleton method. . Taking advantage of the major revision of the version, it took me a while to make a new one. According to our project needs, after research, it probably needs to meet the following scenarios:
1. No need to provide layout, the default style is commonly used in built-in projects
2. Support custom complex layout, animation, dialog box size, background color and other settings
3. Manage multiple dialogs in a unified manner and pop them up sequentially

The first point: In most cases, the style of the dialog box is consistent, so the default dialog style is built in, which can avoid the caller from looking for the layout file every time, and simplify the call as much as possible. ps: The built-in dialog style can be modified according to the needs.
The second point: If you need to customize complex layouts, you need to support the creation of layout sub-Views and a series of interactive events.
The third point: There is a requirement in the project that multiple dialogs may be generated at one time, and the dialogs need to be popped up one by one.

Based on the above requirements, use DialogFragment to encapsulate a general Dialog——SYDialog, first look at the final rendering

2. Rendering

The gif image is blurry, just scan the QR code to download the APK!

3. Why choose DialogFragment?
DialogFragment inherits from Fragment, that is, Fragment can be used to display Dialog. Compared with AlertDialog or Dialog, DialogFragment has more advantages:

DialogFragment can manage its own life cycle when the mobile phone configuration changes and the Activity is rebuilt (such as rotating the screen) or when the physical back button is clicked. DialogFragment
inherits from Fragment, so DialogFragment can also be used as an embedded component, so DialogFragment has more Good reusability
4. UML diagram
Use a UML diagram to roughly express the relationship between classes:


5. Use the document
1. Use the built-in dialog:
a built-in Button style:

  new SYDialog.Builder(this)
           .setTitle("我是标题")
          .setContent("您好,我们将在30分钟处理,稍后通知您订单结果!")
          .setPositiveButton(new IDialog.OnClickListener() {
               @Override
               public void onClick(IDialog dialog) {
                   dialog.dismiss();
               }
           })
           .show();


Renderings:


Built-in two Button styles:

  new SYDialog.Builder(this)
           .setTitle("我是标题")
          .setContent("您好,我们将在30分钟处理,稍后通知您订单结果!")
          .setPositiveButton(new IDialog.OnClickListener() {
               @Override
               public void onClick(IDialog dialog) {
                   dialog.dismiss();
               }
           })
          .setNegativeButton(new IDialog.OnClickListener() {
               @Override
               public void onClick(IDialog dialog) {
                   dialog.dismiss();
               }
            })
           .show();


Renderings:


2. Use the style of the custom layout:

  new SYDialog.Builder(this)
           .setDialogView(R.layout.layout_dialog)//设置dialog布局
           .setAnimStyle(R.style.translate_style)//设置动画 默认没有动画
           .setScreenWidthP(0.85f) //设置屏幕宽度比例 0.0f-1.0f
           .setGravity(Gravity.CENTER)//设置Gravity
           .setWindowBackgroundP(0.2f)//设置背景透明度 0.0f-1.0f 1.0f完全不透明
           .setCancelable(true)//设置是否屏蔽物理返回键 true不屏蔽  false屏蔽
           .setCancelableOutSide(true)//设置dialog外点击是否可以让dialog消失
           .setBuildChildListener(new IDialog.OnBuildListener() {
                    //设置子View
                    @Override
                    public void onBuildChildView(final IDialog dialog, View view, int layoutRes) {
                        //dialog: IDialog
                        //view: DialogView
                        //layoutRes :Dialog的资源文件 如果一个Activity里有多个dialog 可以通过layoutRes来区分
                        final EditText editText = view.findViewById(R.id.et_content);
                        Button btn_ok = view.findViewById(R.id.btn_ok);
                        btn_ok.setOnClickListener(new View.OnClickListener() {
                            @Override
                            public void onClick(View v) {
                                String editTextStr = null;
                                if (!TextUtils.isEmpty(editText.getText())) {
                                    editTextStr = editText.getText().toString();
                                }
                                dialog.dismiss();
                                Toast.makeText(MyApplication.getApplication(), editTextStr, Toast.LENGTH_SHORT).show();
                            }
                        });
                    }
              }).show();


The comments in the code are very detailed. If it is a custom layout and needs to handle interactive events, you can set setBuildChildListener and implement its callback, and create a child View in the callback interface and handle interactive events. It is still very convenient to use.

3. Unified management of multiple Dialog pop-ups in sequence

SYDialog.Builder builder1 = new SYDialog.Builder(this);
SYDialog.Builder builder2 = new SYDialog.Builder(this)
//添加第一个Dialog
SYDialogsManager.getInstance().requestShow(new DialogWrapper(builder1));
//添加第二个Dialog
SYDialogsManager.getInstance().requestShow(new DialogWrapper(builder2));


DialogWrapper is used to wrap a layer of Dialog to facilitate subsequent addition of data information. SYDialogsManager is implemented through a single instance to ensure that there is only one instance. There is a container queue ConcurrentLinkedQueue inside to store multiple Dialogs. The requestShow() method will first determine whether there is a pop-up window currently being displayed. If so, it will wait in the queue. Otherwise, remove and display the data from the queue, and clear the data in the queue. When a Dialog is displayed, it will continue to try to remove the Dialog from the queue and display it until the queue is empty.

6. Source code address
The source code of the above example: https://github.com/crazyqiang/AndroidStudy

引用:
【1】https://developer.android.com/reference/android/app/DialogFragment
【2】https://blog.csdn.net/lmj623565791/article/details/37815413

7. Update 1. During the use of the 2018/10/27 update, I found a problem. There is a problem when setting the screen height through setScreenHeightP(1.0f). The bottom layout will be squeezed out. First look at the code for calculating the screen
height
:

  private static Point point = new Point();
  public static int getScreenHeight(Activity activity) {
        Display display = activity.getWindowManager().getDefaultDisplay();
        if (display != null) {
            display.getSize(point);
            return point.y ;
        }
        return 0;
    }


It can be seen that we calculate the height of the screen including the height of the statusBar, but the layout of our dialog is under the statusBar, so of course the height of the statusBar must be subtracted, the code is as follows:

   private static Point point = new Point();
   public static int getScreenHeight(Activity activity) {
        Display display = activity.getWindowManager().getDefaultDisplay();
        if (display != null) {
            display.getSize(point);
            return point.y - getStatusBarHeight(activity);
        }
        return 0;
    }
    /**
     * 计算statusBar高度
     *
     * @param activity Activity
     * @return statusBar高度
     */
    public static int getStatusBarHeight(Activity activity) {
        Resources resources = activity.getResources();
        int resourceId = resources.getIdentifier("status_bar_height", "dimen", "android");
        return resources.getDimensionPixelSize(resourceId);
    }


Use point.y - getStatusBarHeight(activity) to get the height of the dialog when it is full screen, then there is another problem, since the height of the statusBar needs to be subtracted, do you need to subtract the height of the navigationBar, because if the navigationBar is visible, the dialog is also not It will be drawn on the navigationBar, and the conclusion is: no subtraction! Why not subtract it? Look at the display.getSize(point) we use to calculate the height of the screen, and the display is obtained through the windowManager. Then the height of the navigationBar has been subtracted when calculating the height; if you use display.getRealSize(point), Then you get the height of the navigationBar of the virtual keyboard, and you need to subtract the height of the navigationBar at this time.

2. 2018/10/27 Add the callback when the dialog disappears, the code is as follows:

setOnDismissListener(new IDialog.OnDismissListener() {
                    @Override
                    public void onDismiss(IDialog dialog) {
                        //监听dialog dismiss的回调
                        toast("dismiss回调");
                    }
                })


This callback is received when the dialog disappears.

Guess you like

Origin blog.csdn.net/duyiqun/article/details/88558393