preface

Other than activities, Dialog, PopupWindow, and Toast are probably the most commonly used display pages. The purpose of this article is to clarify the relationship between the three, clarify their strengths and weaknesses, and discuss when to use them. This article covers WindowManager knowledge, if you need to go to: Window/WindowManager must know

Through this article, you will learn:

Dialog/PopupWindow/Toast

Dialog/PopupWindow/Toast life cycle

As mentioned in the previous article, any View needs to be added to the Window before it can be displayed. This process is roughly divided into four steps:

1, the target structure shows the View 2, 3 for WindowManager instance, structural constraints, the Window of the WindowManager. LayoutParams. 4, WindowManager addView (View, LayoutParams)

Dialog/PopupWindow/Toast encapsulates the above four steps and provides further functionality and richer interface usage, which we’ll look at step by step.

Dialog life cycle

So let’s look at a simple demo

// View MyGroup MyGroup = new MyGroup(v.goetContext ()); Dialog Dialog = new Dialog(v.goetContext ()); // Add View dialog.setContentView(myGroup); // Finally show dialog.show();Copy the code

First look at the Dialog constructor:

Dialog(@NonNull Context context, @StyleRes int themeResId, Boolean createContextThemeWrapper) {/ / themeResId specified Dialog style if (createContextThemeWrapper) {if (themeResId = = Resources.id_null) {// If not specified, the default style final TypedValue outValue = new TypedValue(); context.getTheme().resolveAttribute(R.attr.dialogTheme, outValue, true); themeResId = outValue.resourceId; } mContext = new ContextThemeWrapper(context, themeResId); } else { mContext = context; } // Get WindowManager, context is an Activity type, So the WindowManager // is the Activity's WindowManager. MWindowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); Final Window w = new PhoneWindow(mContext); mWindow = w; W.setcallback (this); // omit w.setwindowManager (mWindowManager, null, null); //Window default CENTER w.setgravity (Gravity.CENTER); }Copy the code

When constructing a Window object:

# Window. Java / / construct LayoutParams private final WindowManager. LayoutParams mWindowAttributes = new WindowManager.LayoutParams(); //WindowManager.java public static final int TYPE_APPLICATION = 2; public LayoutParams() { super(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT); type = TYPE_APPLICATION; format = PixelFormat.OPAQUE; }Copy the code

As you can see, the Dialog constructor does two main things:

1, construct the WindowManager 2, tectonic Window object, at the same time in the Window will initialize the WindowManager. LayoutParams variables

Complete the four steps of the second, three steps: tectonic WindowManager/LayoutParams object.

Look at the setContentView (XX)

# Dialog. Java public void the setContentView (@ android. The annotation. NonNull View View) {/ / Window method, Example PhoneWindow mWindow.setContentView(View); } #PhoneWindow.java public void setContentView(View view) { setContentView(view, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT)); } @Override public void setContentView(View view, Viewgroup.layoutparams params) {if (mContentParent == null) {// Construct DecorView installDecor(); } else if (! hasFeature(FEATURE_CONTENT_TRANSITIONS)) { mContentParent.removeAllViews(); } if (hasFeature(FEATURE_CONTENT_TRANSITIONS) {// omit} else {//mContentParent is a DecorView child // Add a custom View to the mContentParent Tree and hang it in the DecorView Tree. } // omit}Copy the code

Android DecorView DecorView ()

SetContentView (XX) constructs the DecorView and adds the custom View to the DecorView

Finally, dialog.show()

Public void show() {if (mShowing) {//Dialog is showing, return; } if (! MCreated) {// Call onCreate(xx) dispatchOnCreate(null); } else {// omit} onStart(); // getDecorView, DecorView mDecor = mwindow.getdecorview () was constructed at setContentView(XX); / / has been built when creating the Window WindowManager. LayoutParams. L = mWindow getAttributes (); // Add DecorView mWindowManager.addView(mDecor, L); mShowing = true; }Copy the code

Dialog.show () completes the last of the four steps: addView(xx) At this point, the dialog is created and displayed.

How to close Dialog

Windowmanager.removeview (xx) is also called to close the Dialog. Here is called WindowManager. RemoveViewImmediate (xx), said the destroy action immediately.

# dialou.java.override public void dismiss() {if (looper.mylooper () == mhandler.getLooper ()) dismissDialog(); } else {// The child thread moves to the main thread and executes mDismissAction (mDismissAction); } } @UnsupportedAppUsage void dismissDialog() { if (mDecor == null || ! mShowing) { return; } the try {/ / remove DecorView mWindowManager. RemoveViewImmediate (mDecor); } finally {// call onStop onStop(); mShowing = false; sendDismissMessage(); }}Copy the code

The Dialog lifecycle is as follows:

PopupWindow life cycle

Same simple demo

//PopupWindow width, height PopupWindow = new PopupWindow(400, 400); MyGroup myGroup = new MyGroup(v.getContext()); popupWindow.setContentView(myGroup); / / display popupWindow popupWindow. ShowAsDropDown (button).Copy the code

PopupWindow is created like a Dialog.

Let’s look at the constructor first:

public PopupWindow(View contentView, int width, int height, Boolean focusable) {//contentView for custom View if (contentView! = null) { mContext = contentView.getContext(); // Get WindowManager mContext which is of type Activity. WindowManager is an Activity WindowManager mWindowManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE); } // set mContentView = contentView; setContentView(contentView); // Set Window width and height setWidth(width); setHeight(height); SetFocusable (focusable); }Copy the code

Note that PopupWindow defaults to 0 width and height, so you need to set the width and height externally

setContentView(XX)

public void setContentView(View contentView) { if (isShowing()) { return; } // assign mContentView = contentView; if (mContext == null && mContentView ! = null) {// getContext mContext = McOntentview.getcontext (); } if (mWindowManager == null && mContentView ! = null) {/ / according to the Context for WindowManager mWindowManager = (WindowManager) mContext. GetSystemService (Context. WINDOW_SERVICE);  }}Copy the code

popupWindow.showAsDropDown(View anchor)

View anchor refers to first anchoring a View, PopupWindow determines its position according to the position of this View.

public void showAsDropDown(View anchor, int xoff, int yoff, int gravity) { if (isShowing() || ! HasContentView ()) {// Return is displayed; } // View attachToAnchor(Anchor, xoff, yoff, gravity); // Construct LayoutParams, And set some parameters of the final WindowManager. LayoutParams p = createPopupLayoutParams (anchor) getApplicationWindowToken ()); ! [image.png](https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/73a79144d01a4d46b95e799b145a7e46~tplv-k3u1fbpfcp-watermark // Construct a "DecorView", which is not our usual DecorView, but an inner class in PopupWindow. PreparePopup (p); Final Boolean aboveAnchor = findDropDownPosition(Anchor, p, xoff, yoff, p.home, p.eight, gravity, mAllowScrollingAnchorParent); updateAboveAnchor(aboveAnchor); // Add to Window. WindowManager.addView(xx) invokePopup(p); }Copy the code

At this point, PopupWindow is created, and you can see that the above steps include the four steps displayed for Window.

How do I close PopupWindow

Like Dialog, PopupWindow has a method:

public void dismiss();
Copy the code

Finally the method invoked the WindowManager. RemoveViewImmediate (xx) method to remove the Window.

Toast Life Cycle

Again, a small demo:

Toast.makeText(App.getApplication(), "hello toast", Toast.LENGTH_LONG).show();
Copy the code

MakeText (XX) is a static method:

public static Toast makeText(@android.annotation.NonNull Context context, @android.annotation.Nullable Looper looper, @ android. The annotation. NonNull CharSequence text, @ Duration int Duration) {/ / constructs Toast Toast result = new Toast (context, looper); LayoutInflater inflate = (LayoutInflater) context.getSystemService(context.layout_inflater_service); View v = inflate.inflate(com.android.internal.R.layout.transient_notification, null); TextView tv = (TextView)v.findViewById(com.android.internal.R.id.message); Tv.settext (text); // TV is a child of v that sets the content to be displayed. Result. mNextView = v; result.mDuration = duration; return result; }Copy the code

Toast. The show () method

public void show() { INotificationManager service = getService(); String pkg = mContext.getOpPackageName(); TN TN = mTN; tn.mNextView = mNextView; final int displayId = mContext.getDisplayId(); Try {// Join queue service.enqueueToast(PKG, TN, mDuration, displayId); } catch (RemoteException e) { // Empty } }Copy the code

At this point, the Toast is created and displayed, but we don’t see the familiar WindowManager.addView(xx), so keep looking. The show() method constructs the TN object, which is added to the INotificationManager. This is the underlying service class, its implementation class is: NotificationManagerService. Java. Class TN: < span style = “font-size: 14px; line-height: 20px;

public void show(IBinder windowToken) { if (localLOGV) Log.v(TAG, "SHOW: " + this); // Send to handler with mhandler.obtainMessage (SHOW, windowToken).sendtoTarget (); } public void handleShow(IBinder windowToken) { if (mView ! = mNextView) { // remove the old view if necessary handleHide(); mView = mNextView; Context context = mView.getContext().getApplicationContext(); String packageName = mView.getContext().getOpPackageName(); if (context == null) { context = mView.getContext(); } // Get the WindowManager object mWM = (WindowManager)context.getSystemService(context.window_service); final Configuration config = mView.getContext().getResources().getConfiguration(); final int gravity = Gravity.getAbsoluteGravity(mGravity, config.getLayoutDirection()); //WindowManager.LayoutParams mParams = new WindowManager.LayoutParams(); mParams.gravity = gravity; If ((gravity & gravity.HORIZONTAL_GRAVITY_MASK) == gravity.FILL_HORIZONTAL) {mparams.horizontalweight = 1.0f; } if ((gravity & gravity.VERTICAL_GRAVITY_MASK) == gravity.FILL_VERTICAL) {mparams.verticalweight = 1.0f; } // set Toast coordinates and other attributes mparams.x = mX; mParams.y = mY; mParams.verticalMargin = mVerticalMargin; mParams.horizontalMargin = mHorizontalMargin; mParams.packageName = packageName; mParams.hideTimeoutMilliseconds = mDuration == Toast.LENGTH_LONG ? LONG_DURATION_TIMEOUT : SHORT_DURATION_TIMEOUT; mParams.token = windowToken; if (mView.getParent() ! = null) { if (localLOGV) Log.v(TAG, "REMOVE! " + mView + " in " + this); mWM.removeView(mView); } try {// Add to Window mwm. addView(mView, mParams); trySendAccessibilityEvent(); } catch (WindowManager.BadTokenException e) { /* ignore */ } } }Copy the code

You see the familiar addView(xx) process again. To sum up:

The make() method constructs the Toast show() method and adds the contents that will be displayed to the Service. The service notifies the UI of the display by handler based on the length of time

How to close Toast

Since the Toast display strategy is done in the service, the service notifies the upper layer to destroy the Window when the time is up by making the Toast disappear

public void cancel() { if (localLOGV) Log.v(TAG, "CANCEL: " + this); mHandler.obtainMessage(CANCEL).sendToTarget(); } public void handleHide() { if (mView ! = null) { if (mView.getParent() ! = null) {// Destroy Window mwm. removeViewImmediate(mView); } try { getService().finishToken(mPackageName, this); } catch (RemoteException e) { } mView = null; }}Copy the code

Dialog/PopupWindow/Toast

From the above analysis of the life cycle of the three, we know that they all addView to Window through addView(xx) to display, so what are their characteristics and focus? So let’s do the analysis. When we run the above three demos separately, we see that: Dialog behaves like:

Center display, external mask, click the out-of-screen Dialog disappears, click the return key Dialog disappears, Dialog intercepts all touch/key events on the screen. A Dialog needs a Context of type Activity to start. With animation.

PopupWindow performance

Can be offset at any distance based on an anchor display. Clicking an off-screen PopupWindow does not disappear, PopupWindow only blocks touch/key events in its area.

PopupWindow needs a Context of type Activity to start. With animation.

Toast performance

Toast pops up a text at the bottom of the screen that disappears after being displayed for a specified time. Toast does not force the Activity type Context to start. With animation.

Let’s look at the reasons for these differences:

Window location determination

WindowManager. LayoutParams. Gravity specified Window orientation, such as the center, left, right, in the top and bottom.

WindowManager.LayoutParams.x

WindowManager.LayoutParams.y

These parameters determine the offset of the Window from the specified orientation of “gravity”. For example, when gravity= gravity.LEFT then layoutparams. x = 200 (positive number), indicating the X-axis offset to the right, negative number vice versa. When gravity= gravity.RIGHT then layoutparams. x = 200, indicating the left offset of the X-axis, and vice versa. And the same thing goes for the vertical direction. So the Window position is determined using a combination of gravity and x/y attributes. Dialog position determination

Dialog(@android.annotation.NonNull Context context, @StyleRes int themeResId, Boolean createContextThemeWrapper) {/ / omit the final Window w = new PhoneWindow (mContext); // Set gravity w.setgravity (gravity.CENTER); }Copy the code

The Dialog constructor centers the Window, so the Dialog shown in the demo is centered. So change the default value of “gravity” :

dialog.getWindow().getAttributes().gravity = Gravity.XX

PopupWindow is located

Public void showAsDropDown(View anchor, int xoff, int yoff, int gravity) {// ellipsis... / / determine the layoutParams. X/layoutParams. Y / / xoff yoff represents the window offset from the anchor of anchor points, the default is the lower left corner of the anchor / / gravity refers to the window and the alignment of the anchor, // When xoff/yoff and Gravity are set at the same time, first offset xoff/yoff according to the lower left corner of anchor. It is concluded that the current layoutParams. X/layoutParams. / / y value is adjusted according to the gravity again layoutParams. X/layoutParams. Y value final Boolean aboveAnchor = findDropDownPosition(anchor, p, xoff, yoff, p.width, p.height, gravity, mAllowScrollingAnchorParent); / / to omit... }Copy the code

FindDropDownPosition (xx). This method determines the PopupWindow WindowManager LayoutParams. X/WindowManager. LayoutParams. The y value. Take a look at WindowManager. LayoutParams. How do you determine the gravity of:

protected final WindowManager.LayoutParams createPopupLayoutParams(IBinder token) { final WindowManager.LayoutParams p =  new WindowManager.LayoutParams(); Gravity p.gravivity = computeGravity(); // omit return p; } private int computeGravity() {private int computeGravity = mGravity == gravity.NO_GRAVITY? Gravity.START | Gravity.TOP : mGravity; if (mIsDropdown && (mClipToScreen || mClippingEnabled)) { gravity |= Gravity.DISPLAY_CLIP_VERTICAL; } return gravity; }Copy the code

MGravity can be set externally:

public void showAtLocation(View parent, int gravity, int x, int y) {d mParentRootView = new WeakReference<>(parent.getRootView()); showAtLocation(parent.getWindowToken(), gravity, x, y); } public void showAtLocation(token, int gravity, int x, int y) {// omit... mGravity = gravity; / / omit}Copy the code

Therefore, PopupWindow Gravity can be set via showAtLocation(xx). Gravity in the showAsDropDown(xx) argument refers to how the PopupWindow is aligned with the anchor View. Gravity in the showAtLocation(xx) argument is the PopupWindow gravity.

The Toast position determines that the Toast defaults to a horizontal center at the bottom. In the toast. TN class, call the handleShow(xx) method when the Toast is presented:

Public void handleShow(IBinder windowToken) {// omit if (mView! = mNextView) {/ / government / / by calculating final mGravity int gravity = gravity. GetAbsoluteGravity (mGravity, config.getLayoutDirection()); mParams.gravity = gravity; // mparams. x = mX; mParams.y = mY; }}Copy the code

MGravity, mX, and mY can be set externally:

    public void setGravity(int gravity, int xOffset, int yOffset) {
        mTN.mGravity = gravity;
        mTN.mX = xOffset;
        mTN.mY = yOffset;
    }
Copy the code

So a call to setGravity(xx) can change the position of the Toast display

The outer area of the Window is darkened

The outer area of the Dialog is darkened when it pops up, and the effect is controlled by the following fields

WindowManager. LayoutParams. DimAmount a float value range of [0, 1] is said the opacity and the higher the 0 indicates the same dark, 1 is completely dark This value needs to take effect, need to cooperate with the other fields use: layoutParams.flags |= WindowManager.LayoutParams.FLAG_DIM_BEHIND;

Dialog outside darkens

protected ViewGroup generateLayout(DecorView decor) { if (a.getBoolean(R.styleable.Window_backgroundDimEnabled, MIsFloating)) {if ((getForcedWindowFlags () & WindowManager. LayoutParams. FLAG_DIM_BEHIND) = = 0) {/ / tag set, Support dimming params. Flags. | = WindowManager LayoutParams. FLAG_DIM_BEHIND; } if (! HaveDimAmount ()) {/ / set the specific value of the dim params. DimAmount = al-qeada etFloat (android. R.s tyleable. Window_backgroundDimAmount, 0.5 f); }}}Copy the code

As you can see, the Dialog dimAmount value is fetched from the style, where the default value is 0.6. Of course we can modify the dimAmount value externally.

dialog.setContentView(myGroup); Dialog. GetWindow (). The getAttributes () dimAmount = 0.3 f; dialog.show();Copy the code

Note that dimAmount assignment must take place after setContentView(xx), otherwise the value will be reset by setContentView(xx).

PopupWindow and Toast do not set a value for this, so there is no argument for darkening the outer area.

The Window touch/key event

The Dialog event receives a click outside the Dialog (touch) and the Dialog disappears. When the physical return key is clicked, the Dialog disappears. Therefore, we can guess that the Dialog received the Touch /key event and decide to close the Dialog if the touch event is outside the Window. There are two steps involved:

1, can receive external touch/key event 2, the corresponding event processing (whether to close Dialog)

Window receives touch/key events by default. Dialog does not change this default value to receive touch/key events. Dialog implements the window. Callback interface and overwrites the touch function

# Dialog. Java public Boolean dispatchTouchEvent (@ android. The annotation. NonNull MotionEvent ev) {/ / to deal with if the Dialog is visible area (mWindow.superDispatchTouchEvent(ev)) { return true; } return onTouchEvent(ev); } public boolean onTouchEvent(@android.annotation.NonNull MotionEvent event) { //shouldCloseOnTouch(xx) // This method checks whether it is an up event and whether it is clicked on the outer area of the Dialog and whether it is set to close the Dialog. Returns true if (mCancelable && mShowing && mWindow. ShouldCloseOnTouch (mContext, event)) {/ / accords with a condition, then close the Dialog cancel (); return true; } return false; }Copy the code

Similarly, Dialog implements keyevent.callback, the override method that handles key events

#Dialog.java public boolean dispatchKeyEvent(@android.annotation.NonNull KeyEvent event) { if ((mOnKeyListener ! = null) && (mOnKeyListener.onKey(this, event.getKeyCode(), event))) { return true; } / / visible area for processing the if (mWindow. SuperDispatchKeyEvent (event)) {return true; } // Continue to send return event.dispatch(this, mDecor! = null ? mDecor.getKeyDispatcherState() : null, this); } public boolean onKeyUp(int keyCode, @android.annotation.NonNull KeyEvent event) { if ((keyCode == KeyEvent.KEYCODE_BACK || keyCode == KeyEvent.KEYCODE_ESCAPE) && event.isTracking() && ! event.isCanceled()) { onBackPressed(); return true; } return false; } public void onBackPressed() {// remove Dialog if (mCancelable) {cancel(); }}Copy the code

As can be seen from the above, two conditions need to be met at the same time for the Dialog to click on the outside and click on the physical return key to disappear. The Dialog actually sets the flag bit based on the second condition, which has been encapsulated for us: click outside and do not disappear:

dialog.setCanceledOnTouchOutside(false);

Clicking the physics back button does not disappear:

dialog.setCancelable(false);

Note that the Dialog still receives the event after calling the above method, but does not close the Dialog. The event is not distributed to its underlying Window.

The PopupWindow event is received like a Dialog to see if two conditions are met. Let’s start with the PopupWindow call stack:

showAsDropDown(xx)->createPopupLayoutParams(xx)->computeFlags(xx)

# popupwindow.java private int computeFlags(int curFlags) {// omit if (! MFocusable) {// If focusable is not enabled, FLAG_NOT_FOCUSABLE Window does not receive the outer area of the touch events / / don't receive the key curFlags | = WindowManager. LayoutParams. FLAG_NOT_FOCUSABLE; If (mInputMethodMode = = INPUT_METHOD_NEEDED) {/ / keyboard related curFlags | = WindowManager. LayoutParams. FLAG_ALT_FOCUSABLE_IM; } } else if (mInputMethodMode == INPUT_METHOD_NOT_NEEDED) { curFlags |= WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM; } // omit}Copy the code

ComputeFlags (xx) WindowManager. LayoutParams. The value of flags. Whether PopupWindow receives events depends on the “mFocusable” value, which is not set in our demo. The default value is false, so PopupWindow cannot receive external click events and key events, and of course cannot handle the logic of whether to close PopupWindow. The assignment to the “mFocusable” field can be specified or called in the PopupWindow constructor

public void setFocusable(boolean focusable)

When focusable=true is specified, PopupWindow receives the touch/key event, and PopupDecorView receives the event:

@override public Boolean dispatchTouchEvent(MotionEvent ev) {if (mTouchInterceptor! = null && mTouchInterceptor.onTouch(this, ev)) { return true; } return super.dispatchTouchEvent(ev); } @Override public boolean onTouchEvent(MotionEvent event) { final int x = (int) event.getX(); final int y = (int) event.getY(); / / receive the Down event closed the if ((event. The getAction () = = MotionEvent. ACTION_DOWN) && ((x < 0) | | (x > = getWidth () | | (y < 0) | | (y > = getHeight()))) { dismiss(); return true; } else if (event.getAction() == motionEvent.action_outside) {// Another kind of event is dismissed (); return true; } else { return super.onTouchEvent(event); }}Copy the code

The key event is similar, which is skipped here. To sum up:

Set focusable to true and click on the external PopupWindow, otherwise it does not disappear

Some articles on the web say that PopupWindow blocks, which is wrong. In fact, the Window(Activity) at the next level did not receive the event and of course did not do anything

The Toast event is usually used to display a text periodically, so there is no need to receive the event. In Toast constructor, will construct TN object, the object initialization WindowManager. LayoutParams. Flags parameters:

TN(String packageName, @android.annotation.Nullable Looper looper) { final WindowManager.LayoutParams params = mParams; / / omit params. SetTitle (" Toast "); / / set will not receive the touch events and key events from the external params. Flags = WindowManager. LayoutParams. FLAG_KEEP_SCREEN_ON | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE; / / omit}Copy the code

For details about the Window Touch /key event fields, go to:Windows /WindowManager is a must-knowThis article only explains which parameters are set.

Context restrictions required to start Dialog/PopupWindow/Toast

[Android Context] (juejin.cn/post/701596…)

The Window animation

The fields that control the Window animation are:

WindowManager.LayoutParams.windowAnimations

Dialog default animation:

    <style name="Animation.Dialog">
        <item name="windowEnterAnimation">@anim/dialog_enter</item>
        <item name="windowExitAnimation">@anim/dialog_exit</item>
    </style>
Copy the code

Replace the Dialog default animation and define the Style

    <style name="myAnim">
        <item name="android:windowEnterAnimation">@anim/myanim</item>
    </style>

    <style name="myDialog" parent="myTheme">
        <item name="android:windowAnimationStyle">@style/myAnim</item>
    </style>
Copy the code

The Dialog constructor references this Style. It can also be set separately

dialog.getWindow().getAttributes().windowAnimations = R.style.myAnim;

PopupWindow has no animation by default.

createPopupLayoutParams(xx)->computeAnimationResource(xx)

Specify its animation externally:

    public void setAnimationStyle(int animationStyle) {
        mAnimationStyle = animationStyle;
    }
Copy the code

popupWindow.setAnimationStyle(R.style.myAnim);

In the toast. TN constructor, there is a default animation:

params.windowAnimations = com.android.internal.R.style.Animation_Toast;
Copy the code
    <style name="Animation.Toast">
        <item name="windowEnterAnimation">@anim/toast_enter</item>
        <item name="windowExitAnimation">@anim/toast_exit</item>
    </style>
Copy the code

Toast does not provide an external interface to set Window animation.

Dialog/PopupWindow/Toast

Can be seen from the above analysis, the Windows performance differences are actually WindowManager. LayoutParams parameter difference. So the key is whether we can get a WindowManager. LayoutParams object. In the Dialog:

Can use dialog. GetWindow (). The getAttributes () to obtain WindowManager. LayoutParams object, capturing the object then inside the various parameters can be set up. Note that setContentView(xx) may reset some of the LayoutParams parameters, so it is usually best to change LayoutParams parameters after setContentView(xx).

For PopupWindow/Toast both does not provide a method to obtain WindowManager. LayoutParams object, just provide some way WindowManager alone setting. The LayoutParams object variables. Such as setting the location of the Window, setting the touch/key event reception, animation, etc.

Use advice

Dialog is recommended for those who want to set a background mask. PopupWindow/Toast does not provide a method to set this parameter. 2. Dialog/Toast can also be used to specify the location, but PopupWindow has already wrapped this, so you don’t need to repeat the wheel. Dialog overrides touch/key conveniently. 4. For those who want simple pop-up prompts and sometimes long limits, Toast is recommended.

If Dialog/PopupWindow/Toast doesn’t solve your needs, then it’s even easier. These three are the encapsulation of WindowManager operations, we directly use the native WindowManager, can get all the parameters, what effect we want to set.

Styleable /style/attr = styleable/style/attr = styleable/style/attr Cut the most in-depth Android/Attr/Styleable/Style/Theme TypedArray clear

This article source based on Android 10.0