Android WindowManger的层级分析详解

作者:原来是图哥 时间:2023-08-05 23:51:40 

一. Window 分类

  • 应用 WindowApplicationWindow: 对应一个 Acitivity
       

  • 子 Window    SubWindow:不能单独存在,需要依附在特定的父 Window 中,比如常见的一些 Dialog 就是一个子 Window
       

  • 系统 Window SystemWindow:需要声明权限才能创建的 Window,比如 Toast 和系统状态栏都是系统 Window

二. Window层级

Window 是分层的,每个 Window 都有对应的 z-ordered,层级大的会覆盖在层级小的 Window 上面,这和 HTML 中的 z-index 概念是完全一致的。

在三种 Window 中,每一种Window的层级范围也是不同的,如下:

应用Window    1~99

子Window        1000~1999

系统Window    2000~2999

这些层级范围对应着 WindowManager.LayoutParams type 参数,如果想要 Window 位于所有 Window 的最顶层,那么采用较大的层级即可,很显然系统 Window 的层级是最大的,当我们采用系统层级时,需要声明权限。

(1)应用程序窗口:


package android.view;
public interface WindowManager
       /**
        * Start of window types that represent normal application windows.
        */
       public static final int FIRST_APPLICATION_WINDOW = 1;

/**
        * Window type: an application window that serves as the "base" window
        * of the overall application; all other application windows will
        * appear on top of it.
        * In multiuser systems shows only on the owning user's window.
        */
       public static final int TYPE_BASE_APPLICATION   = 1;

/**
        * Window type: a normal application window.  The {@link #token} must be
        * an Activity token identifying who the window belongs to.
        * In multiuser systems shows only on the owning user's window.
        */
       public static final int TYPE_APPLICATION        = 2;

/**
        * Window type: special application window that is displayed while the
        * application is starting.  Not for use by applications themselves;
        * this is used by the system to display something until the
        * application can show its own windows.
        * In multiuser systems shows on all users' windows.
        */
       public static final int TYPE_APPLICATION_STARTING = 3;

/**
        * Window type: a variation on TYPE_APPLICATION that ensures the window
        * manager will wait for this window to be drawn before the app is shown.
        * In multiuser systems shows only on the owning user's window.
        */
       public static final int TYPE_DRAWN_APPLICATION = 4;

/**
        * End of types of application windows.
        */
       public static final int LAST_APPLICATION_WINDOW = 99;

(2)子窗口:


package android.view;
public interface WindowManager
       /**
        * Start of types of sub-windows.  The {@link #token} of these windows
        * must be set to the window they are attached to.  These types of
        * windows are kept next to their attached window in Z-order, and their
        * coordinate space is relative to their attached window.
        */
       public static final int FIRST_SUB_WINDOW = 1000;

/**
        * Window type: a panel on top of an application window.  These windows
        * appear on top of their attached window.
        */
       public static final int TYPE_APPLICATION_PANEL = FIRST_SUB_WINDOW;

/**
        * Window type: window for showing media (such as video).  These windows
        * are displayed behind their attached window.
        */
       public static final int TYPE_APPLICATION_MEDIA = FIRST_SUB_WINDOW + 1;

/**
        * Window type: a sub-panel on top of an application window.  These
        * windows are displayed on top their attached window and any
        * {@link #TYPE_APPLICATION_PANEL} panels.
        */
       public static final int TYPE_APPLICATION_SUB_PANEL = FIRST_SUB_WINDOW + 2;

/** Window type: like {@link #TYPE_APPLICATION_PANEL}, but layout
        * of the window happens as that of a top-level window, <em>not</em>
        * as a child of its container.
        */
       public static final int TYPE_APPLICATION_ATTACHED_DIALOG = FIRST_SUB_WINDOW + 3;

/**
        * Window type: window for showing overlays on top of media windows.
        * These windows are displayed between TYPE_APPLICATION_MEDIA and the
        * application window.  They should be translucent to be useful.  This
        * is a big ugly hack so:
        * @hide
        */
       @UnsupportedAppUsage
       public static final int TYPE_APPLICATION_MEDIA_OVERLAY  = FIRST_SUB_WINDOW + 4;

/**
        * Window type: a above sub-panel on top of an application window and it's
        * sub-panel windows. These windows are displayed on top of their attached window
        * and any {@link #TYPE_APPLICATION_SUB_PANEL} panels.
        * @hide
        */
       public static final int TYPE_APPLICATION_ABOVE_SUB_PANEL = FIRST_SUB_WINDOW + 5;

/**
        * End of types of sub-windows.
        */
       public static final int LAST_SUB_WINDOW = 1999;

(3)系统窗口:


package android.view;
public interface WindowManager
       /**
        * Start of system-specific window types.  These are not normally
        * created by applications.
        */
       public static final int FIRST_SYSTEM_WINDOW     = 2000;

/**
        * Window type: the status bar.  There can be only one status bar
        * window; it is placed at the top of the screen, and all other
        * windows are shifted down so they are below it.
        * In multiuser systems shows on all users' windows.
        */
       public static final int TYPE_STATUS_BAR         = FIRST_SYSTEM_WINDOW;

/**
        * Window type: the search bar.  There can be only one search bar
        * window; it is placed at the top of the screen.
        * In multiuser systems shows on all users' windows.
        */
       public static final int TYPE_SEARCH_BAR         = FIRST_SYSTEM_WINDOW+1;

/**
        * Window type: phone.  These are non-application windows providing
        * user interaction with the phone (in particular incoming calls).
        * These windows are normally placed above all applications, but behind
        * the status bar.
        * In multiuser systems shows on all users' windows.
        * @deprecated for non-system apps. Use {@link #TYPE_APPLICATION_OVERLAY} instead.
        */
       @Deprecated
       public static final int TYPE_PHONE              = FIRST_SYSTEM_WINDOW+2;

/**
        * Window type: system window, such as low power alert. These windows
        * are always on top of application windows.
        * In multiuser systems shows only on the owning user's window.
        * @deprecated for non-system apps. Use {@link #TYPE_APPLICATION_OVERLAY} instead.
        */
       @Deprecated
       public static final int TYPE_SYSTEM_ALERT       = FIRST_SYSTEM_WINDOW+3;

/**
        * Window type: keyguard window.
        * In multiuser systems shows on all users' windows.
        * @removed
        */
       public static final int TYPE_KEYGUARD           = FIRST_SYSTEM_WINDOW+4;

/**
        * Window type: transient notifications.
        * In multiuser systems shows only on the owning user's window.
        * @deprecated for non-system apps. Use {@link #TYPE_APPLICATION_OVERLAY} instead.
        */
       @Deprecated
       public static final int TYPE_TOAST              = FIRST_SYSTEM_WINDOW+5;

/**
        * Window type: system overlay windows, which need to be displayed
        * on top of everything else.  These windows must not take input
        * focus, or they will interfere with the keyguard.
        * In multiuser systems shows only on the owning user's window.
        * @deprecated for non-system apps. Use {@link #TYPE_APPLICATION_OVERLAY} instead.
        */
       @Deprecated
       public static final int TYPE_SYSTEM_OVERLAY     = FIRST_SYSTEM_WINDOW+6;

/**
        * Window type: priority phone UI, which needs to be displayed even if
        * the keyguard is active.  These windows must not take input
        * focus, or they will interfere with the keyguard.
        * In multiuser systems shows on all users' windows.
        * @deprecated for non-system apps. Use {@link #TYPE_APPLICATION_OVERLAY} instead.
        */
       @Deprecated
       public static final int TYPE_PRIORITY_PHONE     = FIRST_SYSTEM_WINDOW+7;

/**
        * Window type: panel that slides out from the status bar
        * In multiuser systems shows on all users' windows.
        */
       public static final int TYPE_SYSTEM_DIALOG      = FIRST_SYSTEM_WINDOW+8;

/**
        * Window type: dialogs that the keyguard shows
        * In multiuser systems shows on all users' windows.
        */
       public static final int TYPE_KEYGUARD_DIALOG    = FIRST_SYSTEM_WINDOW+9;

/**
        * Window type: internal system error windows, appear on top of
        * everything they can.
        * In multiuser systems shows only on the owning user's window.
        * @deprecated for non-system apps. Use {@link #TYPE_APPLICATION_OVERLAY} instead.
        */
       @Deprecated
       public static final int TYPE_SYSTEM_ERROR       = FIRST_SYSTEM_WINDOW+10;

/**
        * Window type: internal input methods windows, which appear above
        * the normal UI.  Application windows may be resized or panned to keep
        * the input focus visible while this window is displayed.
        * In multiuser systems shows only on the owning user's window.
        */
       public static final int TYPE_INPUT_METHOD       = FIRST_SYSTEM_WINDOW+11;

/**
        * Window type: internal input methods dialog windows, which appear above
        * the current input method window.
        * In multiuser systems shows only on the owning user's window.
        */
       public static final int TYPE_INPUT_METHOD_DIALOG= FIRST_SYSTEM_WINDOW+12;

/**
        * Window type: wallpaper window, placed behind any window that wants
        * to sit on top of the wallpaper.
        * In multiuser systems shows only on the owning user's window.
        */
       public static final int TYPE_WALLPAPER          = FIRST_SYSTEM_WINDOW+13;

/**
        * Window type: panel that slides out from over the status bar
        * In multiuser systems shows on all users' windows.
        */
       public static final int TYPE_STATUS_BAR_PANEL   = FIRST_SYSTEM_WINDOW+14;

/**
        * Window type: secure system overlay windows, which need to be displayed
        * on top of everything else.  These windows must not take input
        * focus, or they will interfere with the keyguard.
        *
        * This is exactly like {@link #TYPE_SYSTEM_OVERLAY} except that only the
        * system itself is allowed to create these overlays.  Applications cannot
        * obtain permission to create secure system overlays.
        *
        * In multiuser systems shows only on the owning user's window.
        * @hide
        */
       @UnsupportedAppUsage
       public static final int TYPE_SECURE_SYSTEM_OVERLAY = FIRST_SYSTEM_WINDOW+15;

/**
        * Window type: the drag-and-drop pseudowindow.  There is only one
        * drag layer (at most), and it is placed on top of all other windows.
        * In multiuser systems shows only on the owning user's window.
        * @hide
        */
       public static final int TYPE_DRAG               = FIRST_SYSTEM_WINDOW+16;

/**
        * Window type: panel that slides out from over the status bar
        * In multiuser systems shows on all users' windows. These windows
        * are displayed on top of the stauts bar and any {@link #TYPE_STATUS_BAR_PANEL}
        * windows.
        * @hide
        */
       public static final int TYPE_STATUS_BAR_SUB_PANEL = FIRST_SYSTEM_WINDOW+17;

/**
        * Window type: (mouse) pointer
        * In multiuser systems shows on all users' windows.
        * @hide
        */
       public static final int TYPE_POINTER = FIRST_SYSTEM_WINDOW+18;

/**
        * Window type: Navigation bar (when distinct from status bar)
        * In multiuser systems shows on all users' windows.
        * @hide
        */
       public static final int TYPE_NAVIGATION_BAR = FIRST_SYSTEM_WINDOW+19;

/**
        * Window type: The volume level overlay/dialog shown when the user
        * changes the system volume.
        * In multiuser systems shows on all users' windows.
        * @hide
        */
       public static final int TYPE_VOLUME_OVERLAY = FIRST_SYSTEM_WINDOW+20;

/**
        * Window type: The boot progress dialog, goes on top of everything
        * in the world.
        * In multiuser systems shows on all users' windows.
        * @hide
        */
       public static final int TYPE_BOOT_PROGRESS = FIRST_SYSTEM_WINDOW+21;

/**
        * Window type to consume input events when the systemUI bars are hidden.
        * In multiuser systems shows on all users' windows.
        * @hide
        */
       public static final int TYPE_INPUT_CONSUMER = FIRST_SYSTEM_WINDOW+22;

/**
        * Window type: Dreams (screen saver) window, just above keyguard.
        * In multiuser systems shows only on the owning user's window.
        * @hide
        */
       public static final int TYPE_DREAM = FIRST_SYSTEM_WINDOW+23;

/**
        * Window type: Navigation bar panel (when navigation bar is distinct from status bar)
        * In multiuser systems shows on all users' windows.
        * @hide
        */
       public static final int TYPE_NAVIGATION_BAR_PANEL = FIRST_SYSTEM_WINDOW+24;

/**
        * Window type: Display overlay window.  Used to simulate secondary display devices.
        * In multiuser systems shows on all users' windows.
        * @hide
        */
       @UnsupportedAppUsage
       public static final int TYPE_DISPLAY_OVERLAY = FIRST_SYSTEM_WINDOW+26;

/**
        * Window type: Magnification overlay window. Used to highlight the magnified
        * portion of a display when accessibility magnification is enabled.
        * In multiuser systems shows on all users' windows.
        * @hide
        */
       public static final int TYPE_MAGNIFICATION_OVERLAY = FIRST_SYSTEM_WINDOW+27;

/**
        * Window type: Window for Presentation on top of private
        * virtual display.
        */
       public static final int TYPE_PRIVATE_PRESENTATION = FIRST_SYSTEM_WINDOW+30;

/**
        * Window type: Windows in the voice interaction layer.
        * @hide
        */
       public static final int TYPE_VOICE_INTERACTION = FIRST_SYSTEM_WINDOW+31;

/**
        * Window type: Windows that are overlaid <em>only</em> by a connected {@link
        * android.accessibilityservice.AccessibilityService} for interception of
        * user interactions without changing the windows an accessibility service
        * can introspect. In particular, an accessibility service can introspect
        * only windows that a sighted user can interact with which is they can touch
        * these windows or can type into these windows. For example, if there
        * is a full screen accessibility overlay that is touchable, the windows
        * below it will be introspectable by an accessibility service even though
        * they are covered by a touchable window.
        */
       public static final int TYPE_ACCESSIBILITY_OVERLAY = FIRST_SYSTEM_WINDOW+32;

/**
        * Window type: Starting window for voice interaction layer.
        * @hide
        */
       public static final int TYPE_VOICE_INTERACTION_STARTING = FIRST_SYSTEM_WINDOW+33;

/**
        * Window for displaying a handle used for resizing docked stacks. This window is owned
        * by the system process.
        * @hide
        */
       public static final int TYPE_DOCK_DIVIDER = FIRST_SYSTEM_WINDOW+34;

/**
        * Window type: like {@link #TYPE_APPLICATION_ATTACHED_DIALOG}, but used
        * by Quick Settings Tiles.
        * @hide
        */
       public static final int TYPE_QS_DIALOG = FIRST_SYSTEM_WINDOW+35;

/**
        * Window type: shares similar characteristics with {@link #TYPE_DREAM}. The layer is
        * reserved for screenshot region selection. These windows must not take input focus.
        * @hide
        */
       public static final int TYPE_SCREENSHOT = FIRST_SYSTEM_WINDOW + 36;

/**
        * Window type: Window for Presentation on an external display.
        * @see android.app.Presentation
        * @hide
        */
       public static final int TYPE_PRESENTATION = FIRST_SYSTEM_WINDOW + 37;

/**
        * Window type: Application overlay windows are displayed above all activity windows
        * (types between {@link #FIRST_APPLICATION_WINDOW} and {@link #LAST_APPLICATION_WINDOW})
        * but below critical system windows like the status bar or IME.
        * <p>
        * The system may change the position, size, or visibility of these windows at anytime
        * to reduce visual clutter to the user and also manage resources.
        * <p>
        * Requires {@link android.Manifest.permission#SYSTEM_ALERT_WINDOW} permission.
        * <p>
        * The system will adjust the importance of processes with this window type to reduce the
        * chance of the low-memory-killer killing them.
        * <p>
        * In multi-user systems shows only on the owning user's screen.
        */
       public static final int TYPE_APPLICATION_OVERLAY = FIRST_SYSTEM_WINDOW + 38;

/**
        * End of types of system windows.
        */
       public static final int LAST_SYSTEM_WINDOW      = 2999;

 窗口显示顺序:
Type 值越大层级越高,Type 值大的覆盖 Type 值小的,这只是一般规律。

(三)如何真正查看 Window 的优先级


/frameworks/base/services/core/java/com/android/server/policy/WindowManagerPolicy.java
   default int getWindowLayerFromTypeLw(int type, boolean canAddInternalSystemWindow) {
       if (type >= FIRST_APPLICATION_WINDOW && type <= LAST_APPLICATION_WINDOW) {
           return APPLICATION_LAYER;
       }
       switch (type) {
           case TYPE_WALLPAPER:
               // wallpaper is at the bottom, though the window manager may move it.
               return  1;
           case TYPE_PRESENTATION:
           case TYPE_PRIVATE_PRESENTATION:
               return  APPLICATION_LAYER;
           case TYPE_DOCK_DIVIDER:
               return  APPLICATION_LAYER;
           case TYPE_QS_DIALOG:
               return  APPLICATION_LAYER;
           case TYPE_PHONE:
               return  3;
           case TYPE_SEARCH_BAR:
           case TYPE_VOICE_INTERACTION_STARTING:
               return  4;
           case TYPE_VOICE_INTERACTION:
               // voice interaction layer is almost immediately above apps.
               return  5;
           case TYPE_INPUT_CONSUMER:
               return  6;
           case TYPE_SYSTEM_DIALOG:
               return  7;
           case TYPE_TOAST:
               // toasts and the plugged-in battery thing
               return  8;
           case TYPE_PRIORITY_PHONE:
               // SIM errors and unlock.  Not sure if this really should be in a high layer.
               return  9;
           case TYPE_SYSTEM_ALERT:
               // like the ANR / app crashed dialogs
               return  canAddInternalSystemWindow ? 11 : 10;
           case TYPE_APPLICATION_OVERLAY:
               return  12;
           case TYPE_DREAM:
               // used for Dreams (screensavers with TYPE_DREAM windows)
               return  13;
           case TYPE_INPUT_METHOD:
               // on-screen keyboards and other such input method user interfaces go here.
               return  14;
           case TYPE_INPUT_METHOD_DIALOG:
               // on-screen keyboards and other such input method user interfaces go here.
               return  15;
           case TYPE_STATUS_BAR:
               return  17;
           case TYPE_STATUS_BAR_PANEL:
               return  18;
           case TYPE_STATUS_BAR_SUB_PANEL:
               return  19;
           case TYPE_KEYGUARD_DIALOG:
               return  20;
           case TYPE_VOLUME_OVERLAY:
               // the on-screen volume indicator and controller shown when the user
               // changes the device volume
               return  21;
           case TYPE_SYSTEM_OVERLAY:
               // the on-screen volume indicator and controller shown when the user
               // changes the device volume
               return  canAddInternalSystemWindow ? 22 : 11;
           case TYPE_NAVIGATION_BAR:
               // the navigation bar, if available, shows atop most things
               return  23;
           case TYPE_NAVIGATION_BAR_PANEL:
               // some panels (e.g. search) need to show on top of the navigation bar
               return  24;
           case TYPE_SCREENSHOT:
               // screenshot selection layer shouldn't go above system error, but it should cover
               // navigation bars at the very least.
               return  25;
           case TYPE_SYSTEM_ERROR:
               // system-level error dialogs
               return  canAddInternalSystemWindow ? 26 : 10;
           case TYPE_MAGNIFICATION_OVERLAY:
               // used to highlight the magnified portion of a display
               return  27;
           case TYPE_DISPLAY_OVERLAY:
               // used to simulate secondary display devices
               return  28;
           case TYPE_DRAG:
               // the drag layer: input for drag-and-drop is associated with this window,
               // which sits above all other focusable windows
               return  29;
           case TYPE_ACCESSIBILITY_OVERLAY:
               // overlay put by accessibility services to intercept user interaction
               return  30;
           case TYPE_SECURE_SYSTEM_OVERLAY:
               return  31;
           case TYPE_BOOT_PROGRESS:
               return  32;
           case TYPE_POINTER:
               // the (mouse) pointer layer
               return  33;
           default:
               Slog.e("WindowManager", "Unknown window type: " + type);
               return APPLICATION_LAYER;
       }
   }

 以上返回的是除 Application 外的 Window 的层级,在开发系统应用时可以选择一种开发自己的 Window.

(四) 层级高低具体分析(对比Toast以及软键盘)


低于toast--->盖不住toast
低于软键盘--->盖不住软键盘
依附Activity使用--->is your activity running?
public static int getWindowType(int num) {
       switch (num) {
           case 1:
               return WindowManager.LayoutParams.TYPE_PHONE;//低于toast  低于软键盘
           case 2:
               return WindowManager.LayoutParams.TYPE_SEARCH_BAR;//低于toast  低于软键盘
           case 3:
               return WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG;//低于toast  低于软键盘
           case 4:
               return WindowManager.LayoutParams.TYPE_PRIORITY_PHONE;//高于toast  低于软键盘
           case 5:
               return WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;//高于toast  低于软键盘
           case 6:
               return WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG;//高于toast  盖住键盘
           case 7:
               return WindowManager.LayoutParams.TYPE_SYSTEM_ERROR;//高于toast    低于软键盘
           case 8:
               return WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG;//高于toast  低于软键盘
           case 9:
               return WindowManager.LayoutParams.TYPE_SYSTEM_ALERT;//高于toast  高于软键盘
           case 10:
               return WindowManager.LayoutParams.TYPE_STATUS_BAR;//高于toast  高于软键盘(键盘会把透明view顶起)
           case 11:
               return WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL;//高于toast  高于软键盘(键盘会把透明view顶起)
           case 12:
               return WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY;//低于下级页面
           case 13:
               return WindowManager.LayoutParams.TYPE_ACCESSIBILITY_OVERLAY;//is your activity running?
           case 14:
               return WindowManager.LayoutParams.TYPE_BASE_APPLICATION;// is your activity running?
           case 15:
               return WindowManager.LayoutParams.TYPE_APPLICATION;// is your activity running?
           case 16:
               return WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;// is your activity running?
           case 17:
               return WindowManager.LayoutParams.TYPE_DRAWN_APPLICATION;// is your activity running?
           case 18:
               return WindowManager.LayoutParams.TYPE_APPLICATION_PANEL;// is your activity running?
           case 19:
               return WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA;// is your activity running?
           case 20:
               return WindowManager.LayoutParams.TYPE_APPLICATION_SUB_PANEL;// is your activity running?
           case 21:
               return WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG;// is your activity running?
           case 22:
               return WindowManager.LayoutParams.TYPE_WALLPAPER;// is your activity running?
           case 23:
               return WindowManager.LayoutParams.TYPE_TOAST;// is your activity running?
           case 24:
               return WindowManager.LayoutParams.TYPE_INPUT_METHOD;//is your activity running?
           case 25:
               return WindowManager.LayoutParams.TYPE_PRIVATE_PRESENTATION;//permission denied for window type 2030
           default:
               return 0;
       }
   }

(五)如何定制系统层级

改变层级关系需要改写 getWindowLayerFromTypeLw 的 switch 顺序结构和返回值
如果需要更改一些 Window 的行为,需要修改
/frameworks/base/services/core/java/com/android/server/policy/PhoneWindowManager.java

来源:https://blog.csdn.net/JiYaRuo/article/details/120180339

标签:Android,WindowManger
0
投稿

猜你喜欢

  • C#实现FFT(递归法)的示例代码

    2022-12-30 05:21:06
  • 一个进程间通讯同步的C#框架引荐

    2023-01-18 17:55:03
  • ADO.NET实体数据模型详细介绍

    2023-10-16 12:15:41
  • Android实现APP秒表功能

    2022-11-13 13:58:26
  • C#双缓冲技术实例详解

    2023-02-02 15:56:37
  • Android ViewPager中显示图片与播放视频的填坑记录

    2023-12-23 14:28:40
  • 详解Java中的时区类TimeZone的用法

    2023-11-29 02:03:09
  • C#操作ini文件的帮助类

    2022-12-26 17:11:09
  • java多线程的同步方法实例代码

    2022-02-16 19:30:47
  • Android Build Variants 为项目设置变种版本的方法

    2023-04-26 10:29:07
  • 如何利用泛型封装通用的service层

    2023-05-15 04:55:43
  • 解决MyEclipse中Maven设置jdk版本jdk1.8报错问题

    2022-04-20 18:19:04
  • SSH框架网上商城项目第24战之Struts2中处理多个Model请求的方法

    2023-02-14 20:49:21
  • android中实现背景图片颜色渐变方法

    2021-12-26 04:55:40
  • C#编程实现四舍五入、向上及下取整的方法

    2023-10-25 07:59:38
  • C#实现图书管理系统

    2023-03-24 04:30:35
  • Spring Cloud Gateway 服务网关快速实现解析

    2023-12-19 04:28:33
  • SpringBoot中自定义注解实现参数非空校验的示例

    2022-04-12 10:55:55
  • Android中使用CircleImageView和Cardview制作圆形头像的方法

    2022-04-19 05:41:35
  • Android圆形头像拍照后“无法加载此图片”的问题解决方法(适配Android7.0)

    2023-11-18 23:26:56
  • asp之家 软件编程 m.aspxhome.com