Android window属性全解析

作者:solo_99日期:2026/7/16

Android Theme XML 属性如何影响 PhoneWindow:从 TypedArray 到 LayoutParams 的完整链路

每天写布局、配主题,但你有没有想过——android:windowIsTranslucent="true" 这行 XML 到底是怎么一路传递,最终影响了 Window 的像素格式?为什么 statusBarColor 有时候怎么设都不生效?FLAG_LAYOUT_IN_SCREEN 到底是干什么的?本文将带你深入 Android Framework 源码,逐属性、逐 Flag 拆解这条完整链路。


目录

  1. 架构概览:Theme → PhoneWindow 的数据流
  2. 属性的定义:R.styleable.Window
  3. PhoneWindow 读取属性的两个入口
  4. 深入理解 WindowManager.LayoutParams 的核心 Flags
    • 4.1 什么是 Flags?
    • 4.2 布局相关 Flags(Layout Flags)
    • 4.3 触摸与焦点 Flags(Input Flags)
    • 4.4 系统栏相关 Flags(System Bar Flags)
    • 4.5 安全与显示 Flags(Security & Display Flags)
    • 4.6 锁屏相关 Flags(Keyguard Flags)
    • 4.7 Flags 组合使用矩阵
  5. Theme 属性分类详解
    • 5.1 窗口 Flags 类
    • 5.2 窗口 Type 类
    • 5.3 尺寸与布局类
    • 5.4 背景与样式类
    • 5.5 系统状态栏/导航栏类
    • 5.6 软键盘(SoftInput)类
    • 5.7 转场动画类
    • 5.8 像素格式与绘制类
    • 5.9 FitSystemWindows 与 Edge-to-Edge 类
    • 5.10 其他行为属性
  6. 完整映射表速查
  7. 实战场景
    • 7.1 全屏 Activity
    • 7.2 透明背景 Activity / Dialog 样式 Activity
    • 7.3 自定义状态栏颜色(Material 风格)
    • 7.4 图片查看器(沉浸式)
    • 7.5 锁屏上显示窗口
    • 7.6 禁止截屏的敏感页面
    • 7.7 软键盘适配表单页面
  8. 最佳实践与常见陷阱
  9. 总结

1. 架构概览:Theme → PhoneWindow 的数据流

先上一张整体数据流图,建立心智模型:

1AndroidManifest.xml 中指定的 Theme / setTheme()
2        
3        
4   Resources.Theme (持有所有属性的键值对)
5        
6          context.obtainStyledAttributes(R.styleable.Window)
7        
8   TypedArray (内存中的属性值集合,按索引访问)
9        
10        ├──▶ PhoneWindow() 构造函数  ──▶  读取约 15 个属性
11                                        ├── mIsFloating
12                                        ├── 部分 flags (windowNoDisplay, windowSecure…)
13                                        └── 初始 LayoutParams 设置
14        
15        └──▶ PhoneWindow.generateLayout()  ──▶  读取约 80+ 个属性(核心分发)
16                  
17                  ├──▶ requestFeature()       ──▶ FEATURE_NO_TITLE, FEATURE_ACTION_BAR 
18                  ├──▶ addFlags() / setFlags()──▶ WindowManager.LayoutParams.flags
19                  ├──▶ setBackgroundDrawable()──▶ DecorView 背景
20                  ├──▶ setStatusBarColor()    ──▶ 通过 InsetsController 控制 SystemUI
21                  ├──▶ setNavigationBarColor()──▶ 同上
22                  ├──▶ setSoftInputMode()     ──▶ WindowManager.LayoutParams.softInputMode
23                  ├──▶ setElevation()         ──▶ WindowManager.LayoutParams.elevation
24                  ├──▶ getAttributes()        ──▶ 直接修改 WindowManager.LayoutParams 字段:
25                         ├── width / height / minWidth / minHeight
26                         ├── format (OPAQUE / TRANSLUCENT)
27                         ├── windowAnimations
28                         ├── layoutInDisplayCutoutMode
29                         └── 
30                  
31                  └──▶ 构建 DecorView 布局 ──▶ 决定 mContentParent 的结构
32                              
33                              
34                    最终通过 WindowManager.addView()
35                     LayoutParams 传递给 WMS (WindowManagerService)
36                              
37                              
38                    WMS 根据 LayoutParams 决定:
39                    - Z-order(层级顺序)
40                    - 窗口尺寸与位置
41                    - Surface 像素格式
42                    - 输入事件分发策略
43                    - 系统栏行为
44                    - 转场动画
45

关键类说明:

角色所在进程
Window (android.view.Window)抽象基类,定义 flags、type、softInputMode、features 等抽象方法App 进程
PhoneWindow (com.android.internal.policy.PhoneWindow)唯一的 Window 实现(系统进程外),所有 Activity/Dialog 的 Window 都是它App 进程
WindowManager.LayoutParams描述 Window 的布局参数的结构体,约 80+ 字段App 进程创建,IPC 传递
WindowManagerService (WMS)系统服务,管理所有窗口的 Z-order、尺寸、输入事件分发system_server 进程
SurfaceFlinger系统服务,消费 WMS 创建的 Surface,做 GPU 合成surfaceflinger 进程

关键认知:Theme 属性 → PhoneWindow → LayoutParams → WMS 这条链路中,真正的"消费者"是 WMS。你在 Theme 里设置的属性,本质是在向 WMS 描述"我希望我的窗口在系统中如何表现",而 PhoneWindow 是中间的翻译官。


2. 属性的定义:R.styleable.Window

所有 Window 相关的 theme 属性定义在 AOSP 的 frameworks/base/core/res/res/values/attrs.xml 中,属于 <declare-styleable name="Window">。截至 Android 14 (API 34),这个 styleable 包含约 120+ 个属性

1<!-- frameworks/base/core/res/res/values/attrs.xml -->
2<declare-styleable name="Window">
3    <!-- Flags  -->
4    <attr name="windowNoDisplay" format="boolean" />
5    <attr name="windowDisablePreview" format="boolean" />
6    <attr name="windowEnableSplitTouch" format="boolean" />
7    <attr name="windowShowWallpaper" format="boolean" />
8    <attr name="windowBlurBehind" format="boolean" />
9    <attr name="windowSecure" format="boolean" />
10    <attr name="windowNotTouchable" format="boolean" />
11
12    <!-- 系统栏类 -->
13    <attr name="windowTranslucentStatus" format="boolean" />
14    <attr name="windowTranslucentNavigation" format="boolean" />
15    <attr name="windowDrawsSystemBarBackgrounds" format="boolean" />
16    <attr name="statusBarColor" format="color" />
17    <attr name="navigationBarColor" format="color" />
18    <attr name="windowLightStatusBar" format="boolean" />
19    <attr name="windowLightNavigationBar" format="boolean" />
20
21    <!-- 尺寸类 -->
22    <attr name="windowFixedWidth" format="dimension" />
23    <attr name="windowFixedHeight" format="dimension" />
24    <attr name="windowMinWidthMajor" format="dimension" />
25    <attr name="windowMinWidthMinor" format="dimension" />
26    <attr name="windowElevation" format="dimension" />
27
28    <!-- 样式/背景类 -->
29    <attr name="windowBackground" format="reference|color" />
30    <attr name="windowIsTranslucent" format="boolean" />
31    <attr name="windowIsFloating" format="boolean" />
32    <attr name="windowNoTitle" format="boolean" />
33    <attr name="windowFullscreen" format="boolean" />
34    <attr name="windowTitleSize" format="dimension" />
35
36    <!-- 软键盘 -->
37    <attr name="windowSoftInputMode" />
38
39    <!-- 转场动画 -->
40    <attr name="windowActivityTransitions" format="boolean" />
41    <attr name="windowEnterTransition" format="reference" />
42    <attr name="windowExitTransition" format="reference" />
43    <!-- …还有 100+  -->
44</declare-styleable>
45

这些属性被 Android 系统的预置 Theme(Theme.Material3.*Theme.Material.*Theme.Holo.* 等)设置了默认值,应用层通过自定义 Theme 覆写。

默认值的来源链(以 Theme.Material3.DayNight.NoActionBar 为例):

1Theme.Material3.DayNight.NoActionBar
2  └─ parent: Theme.Material3.DayNight
3       └─ parent: Theme.Material3.Light
4            └─ parent: Theme.Material3 (或 Theme.Material)
5                 └─ parent: Theme.Overlay.Material3 (部分属性)
6                      └─ parent: Platform (系统内置,android: 前缀的属性在这里)
7

在你的 Theme 中设置的属性,会逐级向上覆盖父 Theme 的同名属性。


3. PhoneWindow 读取属性的两个入口

PhoneWindow 在两个时机读取 Window styleable:

入口一:构造函数

1// frameworks/base/core/java/com/android/internal/policy/PhoneWindow.java
2public PhoneWindow(Context context, Window preservedWindow,
3                   ActivityConfigCallback activityConfigCallback) {
4    super(context);
5    mLayoutInflater = LayoutInflater.from(context);
6
7    //  第一次读取 Window styleable
8    TypedArray a = context.obtainStyledAttributes(
9        null,                                    // 不传 AttributeSet(不从 XML layout 读)
10        R.styleable.Window,                      // 目标 styleable
11        0,                                       // defStyleAttr=0,不设中间层
12        R.style.PhoneWindow);                    // defStyleRes:兜底默认样式
13

关键参数解读:

  • set = null:不从 XML layout 节点读取属性,只从 Theme 读取(这正是我们关心的)
  • defStyleAttr = 0:没有中间层默认 attr。如果传了(比如 R.attr.windowStyle),系统会先从 Theme 中取这个 attr 指向的 style 作为默认值
  • defStyleRes = R.style.PhoneWindow:如果 Theme 完全没设置某属性,回退到 PhoneWindow 这个 style 取值

构造阶段消费的属性(约 15 个):

属性消费方式
windowNoDisplay直接 setFlags
windowDisablePreview直接 addFlags
windowEnableSplitTouch直接 addFlags
windowShowWallpaper直接 addFlags
windowBlurBehind直接 addFlags
windowSecure直接 addFlags + 设置输入特性
windowIsFloating存入 mIsFloating,延后到 generateLayout 使用
windowIsTranslucent存入标记,延后到 generateLayout 设置 format
windowSwipeToDismiss设置 dismiss 监听器
windowBackgroundBlurRadius存入标记

入口二:generateLayout()

1// PhoneWindow.java
2protected ViewGroup generateLayout(DecorView decor) {
3    //  第二次读取 Window styleable
4    TypedArray a = getWindowStyle();
5
6    // ...  80+ 个属性的读取和应用 ...
7}
8

generateLayout()核心分发函数,大部分属性在这里被消费。为什么分两次?

因为在 generateLayout() 之前,以下 API 可能已被调用:

1// Activity.onCreate() 中很常见的代码:
2getWindow().requestFeature(Window.FEATURE_NO_TITLE);
3getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
4getWindow().setSoftInputMode();
5

generateLayout() 的策略是:如果某个状态已经被代码显式设置了,就不再被 Theme 覆盖;如果没被设置,就用 Theme 的值作为默认值。

实现方式是"标记位"模式:

1// Window.java 基类中的标记
2protected boolean mHasSoftInputMode = false;   // 代码调过 setSoftInputMode()?
3protected boolean mIsFloating = false;          // Theme 或代码设了浮动窗口?
4
5// generateLayout() 中:
6if (!mHasSoftInputMode) {
7    // 代码没设过   Theme 读取默认值
8    final int softInputMode = a.getInt(R.styleable.Window_windowSoftInputMode, 0);
9    if (softInputMode != 0) {
10        getAttributes().softInputMode = softInputMode;
11    }
12}
13

4. 深入理解 WindowManager.LayoutParams 的核心 Flags

在具体拆解每个 Theme 属性之前,我们必须先彻底理解它们最终写入的目标——LayoutParams.flags不理解 flags 的含义,就无法理解这些 Theme 属性到底做了什么。

4.1 什么是 Flags?

WindowManager.LayoutParams.flags 是一个 int 类型的位掩码(bitmask)。每个 bit 代表一个独立的行为开关。WMS 在收到 addView() 请求时读取这些 flags,决定窗口的布局方式、输入事件分发策略、系统栏行为等。

目前定义了约 40+ 个 flags,按功能可以分为几类:

1flags 字段 (32-bit int)
2├── bit 0-7:   布局相关 (LAYOUT_*)
3├── bit 8-15:  输入/触摸相关 (NOT_TOUCHABLE, NOT_FOCUSABLE, WATCH_OUTSIDE_TOUCH…)
4├── bit 16-23: 系统栏相关 (FULLSCREEN, TRANSLUCENT_*, DRAWS_SYSTEM_BAR_BACKGROUNDS…)
5├── bit 24-27: 显示/安全 (SECURE, SHOW_WALLPAPER, DIM_BEHIND…)
6└── bit 28-31: 锁屏/屏幕 (SHOW_WHEN_LOCKED, KEEP_SCREEN_ON, TURN_SCREEN_ON…)
7

4.2 布局相关 Flags(Layout Flags)

这些 flags 控制窗口内容的布局边界——你的 View 能画到屏幕的哪个区域

FLAG_LAYOUT_IN_SCREEN (0x00000100)

作用:允许窗口内容延伸到整个屏幕(包括状态栏和导航栏后面的区域)。

WMS 的效果

  • 正常窗口的 content 区域被限制在 (0, statusBarHeight, screenWidth, screenHeight - navBarHeight) 范围内
  • 设置此 flag 后,content 区域变为 (0, 0, screenWidth, screenHeight)——即全屏幕
  • 但不改变状态栏/导航栏的可见性——系统栏仍然是可见的,只是窗口内容可以画到它们后面
  • WMS 仍然会通过 WindowInsets 告知应用系统栏的位置,由应用自行决定是否避开

使用场景

  • 需要在状态栏后面绘制背景(Material Design 的 AppBar 延伸到状态栏后面的效果)
  • 配合 FLAG_TRANSLUCENT_STATUS 使用,让内容延伸到透明的状态栏后面
  • 全屏视频播放器,视频画面覆盖整个屏幕但保留状态栏可见

FLAG_LAYOUT_NO_LIMITS 的区别

FLAG_LAYOUT_IN_SCREENFLAG_LAYOUT_NO_LIMITS
布局边界屏幕物理边界内允许超出屏幕(用于 overscan 等场景)
状态栏可延伸到状态栏后面可延伸到状态栏后面
超出屏幕不允许允许
常用程度⭐⭐⭐⭐⭐⭐(已废弃)
FLAG_LAYOUT_NO_LIMITS (0x00000200)

作用:允许窗口布局超出屏幕物理边界。

WMS 的效果

  • 窗口的 content 区域不再被限制在屏幕边界内
  • 主要用于旧的 overscan 机制(CRT 电视时代的过扫描概念,Android 早期用于处理不同 TV 的过扫描差异)
  • API 18-30 期间配合 FLAG_LAYOUT_IN_OVERSCAN 使用,现已基本废弃

FLAG_LAYOUT_IN_SCREEN 的关系

  • FLAG_LAYOUT_IN_SCREEN 通常会被 WMS 自动附加FLAG_LAYOUT_NO_LIMITS 上,因为超出屏幕必然要先允许覆盖全屏
  • windowClipToOutline=true 场景下也会隐式设置此 flag
FLAG_LAYOUT_IN_OVERSCAN (0x00080000)

作用:允许窗口内容延伸到屏幕的 overscan 区域(已废弃,API 30+ 无效)。

这是 Android TV 时代的遗留物。老式电视机有 5-10% 的画面区域不可见(过扫描),Android 通过 overscan insets 来处理。现代显示器(LCD/OLED)没有过扫描概念,所以 API 30 起已废弃。

FLAG_LAYOUT_ATTACHED_IN_DECOR (0x40000000)

作用:内部使用的标志,表示 LayoutParams 已被附加到 DecorView。

这是一个平台内部标志,不应由应用设置。当 WindowManager.addView() 被调用时自动添加,用于防止同一个 LayoutParams 被复用。


4.3 触摸与焦点 Flags(Input Flags)

这些 flags 控制窗口是否接收/如何处理输入事件。

FLAG_NOT_TOUCHABLE (0x00000010)

作用:窗口不接收任何触摸事件,所有触摸事件直接穿透到下层窗口。

WMS 的效果

  • 在 WMS 的输入事件分发中,该窗口被标记为 "untouchable"
  • InputDispatcher 跳过该窗口,将触摸事件发给 Z-order 中下一个可触摸的窗口
  • 即使窗口可见,用户也无法与之交互

使用场景

  • 悬浮窗 + 穿透:如悬浮歌词、悬浮球在不可交互状态时
  • Loading 遮罩:显示一个全屏的半透明遮罩阻止用户操作(需要设置该 flag 配合 FLAG_NOT_FOCUSABLE
  • Starting Window(启动窗口):系统在真正 Activity 启动前显示的预览窗口,不应接收触摸
  • Toast / 短暂提示:不应拦截触摸事件

FLAG_NOT_FOCUSABLE 的组合关系

FLAG_NOT_TOUCHABLEFLAG_NOT_FOCUSABLE效果
窗口完全透明于人机交互——不可触摸、不可获焦
窗口不可触摸但可以获焦(少见,通常无实际意义)
窗口可触摸,但不能成为输入焦点窗口(常用——如输入法窗口上面的工具栏)
正常窗口,可触摸、可获焦
FLAG_NOT_FOCUSABLE (0x00000008)

作用:窗口不能成为输入焦点窗口(即键盘事件的目标窗口)。

WMS 的效果

  • 该窗口不会接收 KeyEvent(按键事件)
  • InputDispatcher 不会将焦点设给该窗口
  • 如果同时设置了 FLAG_NOT_TOUCHABLE,相当于该窗口对输入系统完全不可见

使用场景

  • 系统级悬浮窗(如 Chat Heads、悬浮球):可见、可点击但不能抢键盘焦点
  • 输入法窗口:IME 自身不应该是焦点窗口,但它上面的 EditText 所在的窗口是
  • Toast / 短暂提示:不需要焦点
  • 窗口管理器中的非交互式 Layer:如壁纸窗口

注意:如果窗口需要接收 KeyEvent(如返回键、音量键等),必须取消此 flag。

FLAG_WATCH_OUTSIDE_TOUCH (0x00040000)

作用:当用户触摸窗口外部(在窗口边界之外)时,WMS 向该窗口发送 ACTION_OUTSIDE 事件。

WMS 的效果

  • 正常情况下,窗口外部的触摸事件不会发送给该窗口(只发给被触摸到的下层窗口)
  • 设置该 flag 后,WMS 会将外部触摸事件打包成一个特殊的 MotionEvent.ACTION_OUTSIDE 发给该窗口
  • 该 flag 必须配合 FLAG_NOT_TOUCH_MODAL 使用

使用场景

  • Dialog 点击外部关闭:这是 windowCloseOnTouchOutside 的底层实现机制
  • PopupWindow 点击外部关闭
  • 下拉菜单 / 上下文菜单:点击菜单外部区域关闭菜单
FLAG_NOT_TOUCH_MODAL (0x00000020)

作用:允许触摸事件穿透到该窗口后面的窗口(即 WMS 不会因为该窗口存在而阻止下层窗口接收触摸)。

WMS 的效果

  • 正常情况下(不设此 flag),即使窗口 B 在窗口 A 上面且窗口 B 较小,窗口 A 中未被遮挡的区域也不能接收触摸——因为窗口 B 是 "touch modal" 的
  • "touch modal" = 该窗口的 "触摸区域" 是整个屏幕,即使窗口本身很小
  • 设置该 flag 后,窗口 B 外的触摸事件会传给下层窗口 A

使用场景

  • 系统级悬浮窗:悬浮球在屏幕上,但下面的 App 仍然可以正常操作
  • 输入法窗口:键盘弹出时,键盘上面的内容区域仍可滑动
  • Side Bar / Edge Panel:侧边栏出现时,其余区域仍可操作

典型的触摸行为矩阵

1┌──────────────────────────┐
2  Window A (全屏 App)      
3                          
4     ┌──────────┐         
5      Window B             一个 300dp×200dp  Dialog
6     └──────────┘         
7                          
8   用户点击这个区域         Dialog 外部、App 内部
9└──────────────────────────┘
10
11不设 FLAG_NOT_TOUCH_MODAL:事件发给 Window B(ACTION_OUTSIDE),App A 收不到
12设置 FLAG_NOT_TOUCH_MODAL:事件发给 Window A(正常处理),同时给 B  ACTION_OUTSIDE
13
FLAG_SPLIT_TOUCH (0x00800000)

作用:允许多个手指的触摸事件分别发送给不同的窗口。

WMS 的效果

  • 如果没有此 flag,多点触摸的第二根手指不会触发新的窗口命中测试
  • 设置后,每个手指的 DOWN 事件都独立进行窗口命中,可以分发到不同的窗口

使用场景

  • 多窗口 / 分屏模式:用户可以同时用两根手指操作两个窗口
  • 系统任务栏 + 应用:一根手指滑动任务栏,另一根手指操作应用
  • 游戏手柄映射窗口:虚拟按键和游戏画面需要同时响应不同的触摸

4.4 系统栏相关 Flags(System Bar Flags)

这些 flags 是日常开发中最常用的,控制状态栏和导航栏的外观。

FLAG_FULLSCREEN (0x00000400)

作用:隐藏系统状态栏和导航栏,窗口占据全部屏幕空间。

WMS 的效果

  • WMS 通知 SystemUI 隐藏状态栏和导航栏
  • 屏幕只显示该窗口的内容(完全的"全屏模式")
  • FLAG_LAYOUT_IN_SCREEN 的区别:后者只改变布局边界但不隐藏系统栏

使用场景

  • 视频播放器全屏模式
  • 游戏(几乎所有手游都是全屏的)
  • 图片浏览器全屏
  • 演示 / 幻灯片模式

FLAG_FORCE_NOT_FULLSCREEN 的关系

1// Window.java 中定义 FULLSCREEN:
2// 设置此 flag 实际上 = 设置 FLAG_FULLSCREEN + 清除 FLAG_FORCE_NOT_FULLSCREEN
3public static final int FLAG_FULLSCREEN = 0x00000400;
4// FLAG_FORCE_NOT_FULLSCREEN 是内部标志,表示"有东西强制非全屏",
5// 系统用来平衡多个全屏请求
6
FLAG_TRANSLUCENT_STATUS (0x04000000)

作用:状态栏变为半透明/透明,窗口内容可以延伸到状态栏后面。

WMS 的效果

  • SystemUI 绘制状态栏时使用半透明混合(而非完全不透明)
  • WMS 隐式添加 FLAG_LAYOUT_IN_SCREEN + FLAG_LAYOUT_NO_LIMITS,使窗口布局延伸到状态栏后面
  • 状态栏仍占据空间,但下方的窗口内容透过它可见
  • 此 flag 自动暗示 SYSTEM_UI_FLAG_LAYOUT_STABLESYSTEM_UI_FLAG_LAYOUT_FULLSCREEN

重要:单独设置此 flag 只会让状态栏半透明(约 40% 不透明度的黑色 scrim)。如果你想要完全自定义状态栏颜色,必须同时设置:

1FLAG_TRANSLUCENT_STATUS      状态栏透明
2  +
3FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS   由窗口负责绘制状态栏背景色
4  +
5statusBarColor               你自定义的颜色
6

三者缺一不可。

使用场景

  • Material Design 彩色状态栏:让状态栏颜色与 ActionBar 统一
  • 图片延伸到状态栏:如个人主页的头部大图
  • 地图 / 相机等全屏应用:地图内容充满整个屏幕,状态栏浮在地图上方
  • Edge-to-Edge 设计:Android 15+ 的默认行为

历史变更

  • API 19 (KitKat):引入 FLAG_TRANSLUCENT_STATUS,但 window 可获得半透明的渐变状态栏
  • API 21 (Lollipop):引入 FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDSstatusBarColor,实现真正的自定义颜色
  • API 23 (Marshmallow):引入 SYSTEM_UI_FLAG_LIGHT_STATUS_BAR(Android 30+ 改用 WindowInsetsController),浅色状态栏图标
  • API 35 (Android 15):强制 Edge-to-Edge(自动设置这些 flags),除非显式 opt-out
FLAG_TRANSLUCENT_NAVIGATION (0x08000000)

作用:与 FLAG_TRANSLUCENT_STATUS 完全对称,作用于导航栏。

所有关于状态栏的讨论同样适用于导航栏。唯一需要注意的是:导航栏通常是屏幕底部(手势导航条区域),在全面屏设备上可能非常窄(甚至与内容重叠)。

FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS (0x80000000)

作用:声明"系统栏的背景由本窗口负责绘制",WMS 不再绘制默认的黑色半透明 scrim。

WMS 的效果

  • 只有此 flag 存在时,statusBarColornavigationBarColor 才会生效
  • WMS 在绘制系统栏时采用该窗口指定的颜色(通过 WindowInsetsController 传递)
  • 此 flag 必须配合 FLAG_TRANSLUCENT_STATUS / FLAG_TRANSLUCENT_NAVIGATION 使用

底层原理

1没有 FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS 时:
2┌────────────────────────────┐
3  statusBarColor (不生效)     
4├────────────────────────────┤   这里还是黑色 scrim(WMS 自行绘制)
5                            
6  窗口内容                    
7                            
8└────────────────────────────┘
9
10 FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS 时:
11┌────────────────────────────┐
12  statusBarColor = #2196F3     这里是你设的颜色
13├────────────────────────────┤
14                            
15  窗口内容                    
16                            
17└────────────────────────────┘
18
FLAG_LAYOUT_HIDE_NAV (deprecated)

此 flag 是旧式全屏 API 的残留,功能已被 FLAG_TRANSLUCENT_STATUS / FLAG_TRANSLUCENT_NAVIGATION 替代。


4.5 安全与显示 Flags(Security & Display Flags)

FLAG_SECURE (0x00002000)

作用:窗口内容被视为"安全内容"——禁止截屏、录屏,且禁止在非安全显示器上显示。

WMS 的效果

  • WMS 标记该窗口所在的 Surface 为 "secure"
  • SurfaceFlinger 拒绝在截图/录屏中包含该 Surface 的像素
  • 如果设备连接了非安全的虚拟显示器(如录屏软件创建的虚拟屏),该窗口的内容不渲染到虚拟显示器,在录屏中显示为黑屏
  • 注意:这不影响物理屏幕上的显示——用户在设备上仍然能看到正常内容

使用场景

  • 银行 App / 支付页面
  • 密码输入 / 设置页面
  • 企业内部敏感信息页面
  • DRM 保护的视频播放(如 Netflix 的截屏保护)

限制

  • Android 截图 API 被阻止(MediaProjection 的截图中该窗口为黑色)
  • ADB screencap / screenrecord 中该窗口为黑色
  • 第三方录屏 App 中该窗口为黑色
  • 系统截图(电源键 + 音量键)中该窗口为黑色
  • 无法阻止物理拍照(用另一部手机拍屏幕)
FLAG_SHOW_WALLPAPER (0x00100000)

作用:窗口内容置于壁纸之上,壁纸作为窗口的背景(而非桌面背景)。

WMS 的效果

  • WMS 将该窗口的 Z-order 调整到壁纸窗口之上、其他窗口之下
  • 壁纸作为该窗口的"背景层"
  • 必须配合 windowIsTranslucent 或半透明背景使用,否则看不到壁纸

使用场景

  • 半透明主题的 App:如天气 App 的主界面透过半透明面板看到壁纸
  • Launcher:桌面本身
  • 壁纸选择器 / 预览
  • 锁屏界面
FLAG_DIM_BEHIND (0x00000002)

作用:使该窗口后面的所有窗口变暗。

WMS 的效果

  • WMS 在该窗口后面插入一个半透明黑色 Layer
  • 变暗的程度由 LayoutParams.dimAmount 控制(范围 0.0~1.0,默认 0.0 = 不变暗)
  • 用于实现"模态对话框"的遮罩效果

使用场景

  • AlertDialog:系统默认 AlertDialog 使用此 flag(dimAmount = 0.5)实现背景变暗效果
  • BottomSheet:半透明遮罩
  • Loading 弹窗:遮罩 + 加载动画

注意dimAmount 的值在 Theme 中通过 android:backgroundDimAmount 属性设置:

1<item name="android:backgroundDimAmount">0.6</item>
2
FLAG_BLUR_BEHIND (0x00000004)

作用:使该窗口后面的所有窗口内容模糊化。(API 31+ / Android 12+)

使用场景

  • 毛玻璃效果:iOS 风格的模糊背景
  • 通知面板 / 控制中心:下拉面板后面的模糊
  • Dialog 背景模糊

性能注意:实时模糊是 GPU 密集操作,在低端设备上可能导致掉帧。通常配合 windowBackgroundBlurRadius 控制模糊半径。


4.6 锁屏相关 Flags(Keyguard Flags)

FLAG_SHOW_WHEN_LOCKED (0x00080000)

作用:窗口可以显示在锁屏(Keyguard)之上。

使用场景

  • 来电界面:锁屏时接听电话的 UI
  • 闹钟:闹铃响时的关闭/贪睡界面
  • 音乐播放器锁屏控件
  • 紧急拨号器

安全注意:此 flag 不会绕过锁屏安全——用户仍然需要解锁才能访问 App 的其他部分。

FLAG_DISMISS_KEYGUARD (0x00400000)

作用:当窗口被显示时,自动解除普通锁屏(非安全锁屏——即无密码/图案的滑动解锁)。

使用场景

  • 来电界面:自动解除滑动锁屏,让用户直接看到接听按钮
  • 闹钟:闹铃时解除锁屏

注意:如果用户设置了密码/图案/PIN/生物识别锁屏,此 flag 无效——需要用户主动解锁。

FLAG_TURN_SCREEN_ON (0x00200000)

作用:当窗口被添加到 WMS 时,自动点亮屏幕。

使用场景

  • 来电界面:手机在口袋里,来电时自动亮屏
  • 闹钟:到时间自动亮屏
  • 视频通话请求:收到请求时自动亮屏
FLAG_KEEP_SCREEN_ON (0x00000080)

作用:只要该窗口可见,屏幕不自动熄灭。

使用场景

  • 视频播放器
  • 游戏
  • 地图导航
  • 阅读器(可选)
  • 相机

等效代码

1//  Activity  View 中设置(不需要 Window flag 权限):
2getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
3
4// 或者在 layout XML 中:
5<View android:keepScreenOn="true" />
6
FLAG_ALLOW_LOCK_WHILE_SCREEN_ON (0x00000001)

作用:即使屏幕亮着,也允许设备进入锁屏状态(与 FLAG_KEEP_SCREEN_ON 相反但互不冲突)。

使用场景:极少直接使用。通常由系统管理。


4.7 Flags 组合使用矩阵

以下是一些常见场景的 flags 组合,方便你快速查阅。

全屏沉浸式(视频/游戏)
1FLAG_FULLSCREEN                           隐藏所有系统栏
2FLAG_KEEP_SCREEN_ON                       不自动灭屏
3FLAG_LAYOUT_IN_SCREEN                     布局充满屏幕(可选,视需求)
4
Material Design 自定义状态栏颜色
1FLAG_TRANSLUCENT_STATUS                   状态栏透明
2FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS         窗口绘制状态栏背景
3+ statusBarColor = #2196F3                自定义颜色
4
透明/半透明 Activity(Dialog 样式)
1FLAG_TRANSLUCENT_STATUS                   状态栏透明(可选)
2+ LP.format = PixelFormat.TRANSLUCENT     Surface 支持 alpha
3+ windowBackground = transparent          DecorView 背景透明
4
悬浮窗(System Alert Window)
1FLAG_NOT_FOCUSABLE                        不抢键盘焦点
2FLAG_NOT_TOUCH_MODAL                      允许触摸穿透
3FLAG_WATCH_OUTSIDE_TOUCH                  监听外部触摸(可选)
4FLAG_SPLIT_TOUCH                          多点触摸(可选)
5+ type = TYPE_APPLICATION_OVERLAY         Z-order 在上层
6
锁屏上显示(来电/闹钟)
1FLAG_SHOW_WHEN_LOCKED                     显示在锁屏上方
2FLAG_DISMISS_KEYGUARD                     解除滑动锁屏
3FLAG_TURN_SCREEN_ON                       自动亮屏
4FLAG_KEEP_SCREEN_ON                       不自动灭屏(来电场景)
5
敏感内容保护(银行 App)
1FLAG_SECURE                               禁止截屏/录屏
2// 不需要其他特殊 flag,单独使用即可
3

5. Theme 属性分类详解

有了上面的 flags 知识储备,现在逐个分析每个 Theme XML 属性的 Java 消费路径就非常清晰了。

5.1 窗口 Flags 类

这些属性直接映射到 LayoutParams flags。

android:windowNoDisplay
1<item name="android:windowNoDisplay">true</item>
2

PhoneWindow 源码消费

1// PhoneWindow 构造函数
2if (a.getBoolean(R.styleable.Window_windowNoDisplay, false)) {
3    setFlags(FLAG_NOT_TOUCHABLE | FLAG_NOT_FOCUSABLE,
4             FLAG_NOT_TOUCHABLE | FLAG_NOT_FOCUSABLE);
5    // 额外设置输入特性,使窗口完全不参与输入系统
6    final WindowManager.LayoutParams params = getAttributes();
7    params.inputFeatures |= INPUT_FEATURE_NO_INPUT_CHANNEL;
8}
9

LayoutParams 影响LP.flags |= FLAG_NOT_TOUCHABLE | FLAG_NOT_FOCUSABLE,同时禁用 InputChannel。

使用场景

  • 后台 Service 持有的 Window(如不需要 UI 的后台任务)
  • 纯逻辑 Activity(如 URL Scheme 中转页,finish 前不显示任何 UI)
  • 极少直接在 Theme 中使用,通常在特定业务场景中由代码设置
android:windowDisablePreview
1<item name="android:windowDisablePreview">true</item>
2

PhoneWindow 源码消费

1// PhoneWindow 构造函数
2if (a.getBoolean(R.styleable.Window_windowDisablePreview, false)) {
3    addFlags(FLAG_DISABLE_PREVIEW);
4}
5

LayoutParams 影响LP.flags |= FLAG_DISABLE_PREVIEW

什么是 Starting Window(启动预览)?

当用户点击图标启动一个冷启动(进程不存在)的 Activity 时,在真正的 Activity 渲染出第一帧之前,AMS 会指示 WMS 显示一个"Starting Window"。Starting Window 根据 Theme 中的 windowBackgroundstatusBarColor 生成一个简单的纯色/渐变窗口,让用户感知到"应用正在启动"。

1冷启动时序:
2[点击图标]  [进程创建]  [Application.onCreate]  [Activity.onCreate]
3                                                          
4                                    在此时机,屏幕显示 Starting Window(如果没被 Disable)
5                                                          
6                                    [setContentView]  [首帧渲染]
7                                                          
8                                    此时 Starting Window 被移除,显示真正的 UI
9

使用场景

  • 自定义 Splash Screen:应用有自己的 SplashActivity(带品牌 Logo 动画),不希望系统再插入一个默认预览窗口
  • 透明背景 Activity:Starting Window 默认是纯色的,在半透明 Activity 下会先看到一个纯色闪烁再变透明,体验很差
  • Android 12+ (API 31) 引入了新的 SplashScreen API(SplashScreen 类),推荐使用它替代自定义 Splash Activity。此时系统会自动处理 FLAG_DISABLE_PREVIEW
android:windowEnableSplitTouch
1<item name="android:windowEnableSplitTouch">true</item>
2

PhoneWindow 源码消费

1// PhoneWindow 构造函数
2if (a.getBoolean(R.styleable.Window_windowEnableSplitTouch, false)) {
3    addFlags(FLAG_SPLIT_TOUCH);
4}
5

LayoutParams 影响LP.flags |= FLAG_SPLIT_TOUCH

使用场景

  • 分屏 / 多窗口:需要多个窗口同时响应不同的手指触摸
  • 游戏:双摇杆控制需要独立处理两个手指
  • 支持分屏的应用:Android 7.0+ 的分屏模式需要此 flag 才能正确分发多点触摸
android:windowShowWallpaper
1<item name="android:windowShowWallpaper">true</item>
2

PhoneWindow 源码消费

1// PhoneWindow 构造函数
2if (a.getBoolean(R.styleable.Window_windowShowWallpaper, false)) {
3    addFlags(FLAG_SHOW_WALLPAPER);
4}
5

LayoutParams 影响LP.flags |= FLAG_SHOW_WALLPAPER

使用场景

  • Launcher / 桌面:在壁纸之上显示图标和 Widget
  • 半透明主题:天气 App 的半透明面板让壁纸透出
  • 锁屏界面:在壁纸上叠加锁屏控件
  • 壁纸选择器:预览壁纸效果

注意:必须配合透明或半透明背景使用,否则不透明的窗口背景会完全遮挡壁纸:

1<item name="android:windowShowWallpaper">true</item>
2<item name="android:windowBackground">#80000000</item>  <!-- 半透明背景 -->
3
android:windowBlurBehind
1<item name="android:windowBlurBehind">true</item>
2

LayoutParams 影响LP.flags |= FLAG_BLUR_BEHIND(API 31+)

使用场景

  • 毛玻璃效果 Dialog:iOS 风格的对话框
  • 通知中心 / 控制中心:下拉面板的背景模糊
  • 半透明 Activity:内容后面的模糊背景

实现原理:WMS 请求 SurfaceFlinger 对下层窗口的 Surface 做 GPU 模糊渲染,再将结果作为本窗口的背景。性能开销较大,建议通过 windowBackgroundBlurRadius 控制模糊半径以平衡效果与性能:

1<item name="android:windowBlurBehind">true</item>
2<item name="android:windowBackgroundBlurRadius">25dp</item>
3
android:windowSecure
1<item name="android:windowSecure">true</item>
2

PhoneWindow 源码消费

1// PhoneWindow 构造函数
2if (a.getBoolean(R.styleable.Window_windowSecure, false)) {
3    addFlags(FLAG_SECURE);
4    // 同时在 InputChannel 层面标记 secure
5    params.inputFeatures |= INPUT_FEATURE_NO_INPUT_CHANNEL;
6}
7

LayoutParams 影响LP.flags |= FLAG_SECURE

使用场景

  • 银行 / 金融 App 所有页面
  • 密码输入页面
  • 支付确认页面
  • 企业 VPN / 内部工具
  • 医学 / 健康隐私数据页面
  • 加密货币钱包

代码中动态启用(更灵活,在特定页面才启用):

1// 在敏感页面的 onResume 中启用
2@Override
3protected void onResume() {
4    super.onResume();
5    getWindow().addFlags(WindowManager.LayoutParams.FLAG_SECURE);
6}
7
8// 在离开敏感页面时关闭(可选)
9@Override
10protected void onPause() {
11    super.onPause();
12    getWindow().clearFlags(WindowManager.LayoutParams.FLAG_SECURE);
13}
14

坑点

  • SurfaceView / TextureView 中的内容同样被保护(整个 Surface 都被标记 secure)
  • 系统截图快捷键(电源+音量)也会触发黑屏
  • Android 15 引入的私有空间(Private Space)可能会与此 flag 有交互
android:windowNotTouchable
1<item name="android:windowNotTouchable">true</item>
2

LayoutParams 影响LP.flags |= FLAG_NOT_TOUCHABLE(在 generateLayout() 中处理)

使用场景

  • 纯展示页面(如广告展示页、信息大屏):不需要用户交互
  • 悬浮 Loading/进度指示器:展示加载状态但不阻止用户操作(需配合 FLAG_NOT_FOCUSABLE
  • AOD(常亮显示)或屏保

5.2 窗口 Type 类

android:windowIsFloating
1<item name="android:windowIsFloating">true</item>
2

PhoneWindow 源码消费

1// 构造函数中保存标记
2mIsFloating = a.getBoolean(R.styleable.Window_windowIsFloating, false);
3
4// generateLayout() 中使用
5if (mIsFloating) {
6    LayoutParams lp = getAttributes();
7    lp.width = LayoutParams.WRAP_CONTENT;   // Dialog 风格:宽度自适应内容
8    lp.height = LayoutParams.WRAP_CONTENT;  // 高度自适应内容
9    lp.gravity = Gravity.CENTER;             // 居中显示
10    // 额外:如果窗口有边框/阴影设置,会在 DecorView 层面处理
11}
12

LayoutParams 影响

  • LP.width = WRAP_CONTENT
  • LP.height = WRAP_CONTENT
  • LP.gravity = CENTER

更深远的影响mIsFloating 还会影响 DecorView 的布局选择。PhoneWindow 根据不同 Feature 和 mIsFloating 的组合选择不同的 DecorView 布局文件:

Feature 组合DecorView 布局
标准 Activity(无特殊 Feature)R.layout.screen_simple
标准 Activity + FEATURE_NO_TITLER.layout.screen_simple(无标题区域)
mIsFloating + FEATURE_NO_TITLER.layout.dialog_custom_title 或简化布局
mIsFloating + ActionBarR.layout.screen_toolbar

使用场景

完整的 Dialog 样式 Theme(Android 系统内置的 Dialog Theme 大体上是这样的):

1<style name="Theme.AppCompat.Dialog" parent="Theme.AppCompat">
2    <item name="android:windowIsFloating">true</item>
3    <item name="android:windowBackground">@android:color/transparent</item>
4    <item name="android:windowNoTitle">true</item>
5    <item name="android:windowCloseOnTouchOutside">true</item>
6</style>
7

5.3 尺寸与布局类

android:windowFixedWidth / android:windowFixedHeight
1<item name="android:windowFixedWidth">320dp</item>
2<item name="android:windowFixedHeight">480dp</item>
3

PhoneWindow 源码消费

1// generateLayout()
2if (a.hasValue(R.styleable.Window_windowFixedWidth)) {
3    lp.width = a.getDimensionPixelSize(
4        R.styleable.Window_windowFixedWidth, lp.width);
5}
6if (a.hasValue(R.styleable.Window_windowFixedHeight)) {
7    lp.height = a.getDimensionPixelSize(
8        R.styleable.Window_windowFixedHeight, lp.height);
9}
10

LayoutParams 影响:覆写 LP.width / LP.height 为固定 dp 值。

使用场景

  • 特殊尺寸的 Activity:如电视 App 的遥控器提示面板(不需要全屏)
  • 自定义 Dialog:固定宽度的对话框
  • 多窗口 / 自由窗口模式(Freeform):指定窗口的初始尺寸

windowIsFloating 的配合

1<item name="android:windowIsFloating">true</item>  <!-- WRAP_CONTENT 兜底 -->
2<item name="android:windowFixedWidth">360dp</item> <!-- 覆写为固定宽度 -->
3
android:windowFixedWidthMajor / android:windowFixedWidthMinor

这两个属性配合横竖屏使用:

  • Major = 长边(landscape 下是宽度,portrait 下是高度)
  • Minor = 短边(landscape 下是高度,portrait 下是宽度)

示例:在平板上,竖屏时窗口宽度设为 360dp,横屏时设为 600dp:

1<item name="android:windowFixedWidthMajor">600dp</item>  <!-- 横屏时生效 -->
2<item name="android:windowFixedWidthMinor">360dp</item>  <!-- 竖屏时生效 -->
3

使用场景

  • 平板 / 折叠屏适配:不同屏幕方向下窗口尺寸不同
  • 多窗口 / Freeform 模式:在大屏设备上指定窗口初始大小
android:windowMinWidthMajor / android:windowMinWidthMinor

最小宽度/高度约束,与固定尺寸不同,它们是下限而非精确值。

1lp.minWidth = a.getDimensionPixelSize(
2    R.styleable.Window_windowMinWidthMajor, lp.minWidth);
3

LayoutParams 影响LP.minWidth / LP.minHeight

使用场景

  • 防止窗口过小:在多窗口模式下,窗口可能被缩得很小,设置 minWidth 可以防止内容被挤压到不可用
  • 响应式设计:窗口可以选择更大的尺寸,但不能小于某个阈值
android:windowElevation
1<item name="android:windowElevation">4dp</item>
2

PhoneWindow 源码消费

1final float elevation = a.getDimension(R.styleable.Window_windowElevation, 0);
2if (elevation != 0 && lp.setElevation(elevation)) {
3    // elevation 发生了变化,触发 relayout
4}
5

LayoutParams 影响LP.elevation

使用场景

  • Activity 间层级:后启动的 Activity 默认在更高的 Z 层,设置 elevation 可以微调
  • Dialog 相对于 Activity 的 Z 轴偏移:确保 Dialog 的阴影正确投射在下层 Activity 上
  • Material Design 阴影:配合背景的 elevation 阴影效果

注意elevation 影响的是 Z-order 和阴影投射,不是窗口在屏幕上的 x/y 位置。

android:windowClipToOutline
1<item name="android:windowClipToOutline">true</item>
2
1final boolean clipToOutline = a.getBoolean(
2    R.styleable.Window_windowClipToOutline, false);
3if (clipToOutline) {
4    lp.flags |= FLAG_LAYOUT_NO_LIMITS;
5}
6

使用场景

  • 圆角窗口:配合 windowBackground 的圆角 shape,将窗口裁剪为圆角矩形
  • 自定义形状窗口:如圆形头像悬浮窗

为什么 clipToOutline 会设置 FLAG_LAYOUT_NO_LIMITS?

因为裁剪到 outline 意味着窗口的可见区域由 outline path 决定,layout 可以超出屏幕(反正会被裁剪掉)。这个 flag 确保内容可以渲染到 outline 内的所有区域,即使部分在屏幕外。


5.4 背景与样式类

android:windowBackground
1<!-- 纯色 -->
2<item name="android:windowBackground">@color/window_bg</item>
3<!-- Drawable -->
4<item name="android:windowBackground">@drawable/my_bg</item>
5<!-- 透明 -->
6<item name="android:windowBackground">@android:color/transparent</item>
7

PhoneWindow 源码消费

1// generateLayout()
2final Drawable background;
3if (a.hasValue(R.styleable.Window_windowBackground)) {
4    // 优先作为 Drawable 读取
5    background = a.getDrawable(R.styleable.Window_windowBackground);
6} else {
7    // 其次作为 Color 读取
8    int color = a.getColor(R.styleable.Window_windowBackground, 0xFF000000);
9    background = new ColorDrawable(color);
10}
11// 设置给 DecorView
12mDecor.setWindowBackground(background);
13

LayoutParams 影响不直接影响 LP,但有两个重要间接影响:

  1. Starting Window(启动窗口)的颜色:AMS 读取 windowBackground 作为启动窗口的背景色(在 API 31 之前的实现中)
  2. 窗口是否为 "半透明" 的判定:系统会根据背景的 alpha 来判断窗口是否需要特殊处理

使用场景

  • 应用主色调背景:避免每个 Activity 的 root view 都要设置背景(系统级默认背景)
  • Splash Screen:启动窗口的背景色(API 31 后由 windowSplashScreenBackground 替代)
  • 防止启动白屏/黑屏:这是 windowBackground 最实用的场景之一:
1<!--  Theme 中设置与你的启动页相同的背景 -->
2<style name="AppTheme" parent="Theme.Material3.DayNight.NoActionBar">
3    <item name="android:windowBackground">@color/splash_bg</item>
4</style>
5

这样在 Activity 渲染出第一帧之前,用户看到的就是 splash_bg 颜色,而不是刺眼的白屏。

android:windowBackgroundFallback
1<item name="android:windowBackgroundFallback">@color/fallback_bg</item>
2

作用:当同时满足以下条件时,使用此背景替代 windowBackground

  1. windowBackground 未设置或为 null
  2. windowActivityTransitions 为 true

原因:Transition 框架需要一个背景来做转场动画的渐变/淡出。如果 windowBackground 为空,转场动画没有"底"可画,此时 fallback 登场。

使用场景:通常不需要手动设置,系统有合理的默认值。只有在精细化控制转场体验时才需要。

android:windowContentOverlay
1<item name="android:windowContentOverlay">@drawable/content_shadow</item>
2

作用:在 mContentParent(即 android.R.id.content)上方绘制一个遮罩层。

历史意义:在 Holo 时代,ActionBar 和 content 之间有一个阴影分隔线,这个属性就是用来设置那个阴影的。Material Design 已不再使用。

使用场景:几乎不再使用。如果你想要 content 区域的阴影/边框效果,建议用 elevation 或 View 自身的 background 实现。

android:windowTitleSize
1<item name="android:windowTitleSize">24sp</item>
2

→ 设置传统 Title Bar 的文字大小。在 ActionBar / Toolbar 时代基本废弃。

android:windowNoTitle
1<item name="android:windowNoTitle">true</item>
2
1if (a.getBoolean(R.styleable.Window_windowNoTitle, false)) {
2    requestFeature(FEATURE_NO_TITLE);
3}
4

→ 调用 requestFeature(FEATURE_NO_TITLE),移除传统标题栏,精简 DecorView 布局。

使用场景

  • 所有使用 Toolbar 的 App:老式 TitleBar 与 Toolbar 冲突,必须先 requestFeature(FEATURE_NO_TITLE) 才能正常使用 Toolbar
  • NoActionBar 主题Theme.Material3.DayNight.NoActionBar 的父主题里默认设置了此属性
  • 全屏 / 沉浸式页面
android:windowActionBar
1<item name="android:windowActionBar">true</item>
2<!-- 或设为 false 移除 ActionBar -->
3<item name="android:windowActionBar">false</item>
4

requestFeature(FEATURE_ACTION_BAR)

使用场景

  • 设为 false → 使用自定义 Toolbar 代替系统的 ActionBar
  • 设为 true → 使用系统 ActionBar
android:windowActionModeOverlay
1<item name="android:windowActionModeOverlay">true</item>
2

→ ActionMode(上下文操作栏,如文字选择时的"复制/粘贴/剪切"条)覆盖在 ActionBar 上方而不是推挤 ActionBar。


5.5 系统状态栏/导航栏类

这是实际开发中最常需要自定义的一类属性。

android:statusBarColor / android:navigationBarColor
1<item name="android:statusBarColor">@color/primary_dark</item>
2<item name="android:navigationBarColor">@color/nav_bar</item>
3
1mStatusBarColor = a.getColor(R.styleable.Window_statusBarColor, 0xFF000000);
2mNavigationBarColor = a.getColor(R.styleable.Window_navigationBarColor, 0xFF000000);
3

→ 颜色值存储到 PhoneWindow 字段,之后通过 WindowInsetsController(API 30+)或 View.setSystemUiVisibility()(API 21-29)发送给 SystemUI。

这两个颜色生效的前提条件(极其重要):

1statusBarColor 生效需要:
2  FLAG_TRANSLUCENT_STATUS = true     (windowTranslucentStatus)
3  FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS = true  (windowDrawsSystemBarBackgrounds)
4
5navigationBarColor 生效需要:
6  FLAG_TRANSLUCENT_NAVIGATION = true  (windowTranslucentNavigation)
7  FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS = true  (windowDrawsSystemBarBackgrounds)
8

使用场景

  • 品牌色状态栏:状态栏颜色与 Toolbar/ActionBar 颜色一致
  • 深色导航栏:配合深色主题,导航栏设为深色
  • 沉浸式页面:状态栏颜色与页面顶部内容融合
android:windowTranslucentStatus
1<item name="android:windowTranslucentStatus">true</item>
2
1if (a.getBoolean(R.styleable.Window_windowTranslucentStatus, false)) {
2    setFlags(FLAG_TRANSLUCENT_STATUS, FLAG_TRANSLUCENT_STATUS);
3}
4

LP.flags |= FLAG_TRANSLUCENT_STATUS

使用场景

  • 图片/视频延伸到状态栏:如个人主页头部大图
  • 自定义状态栏颜色:配合 windowDrawsSystemBarBackgrounds + statusBarColor
  • Material Design edge-to-edge:让状态栏成为 UI 的一部分

单独设置此属性时的视觉效果

1没有 FLAG_TRANSLUCENT_STATUS 时:
2┌─ 纯黑状态栏 ──────────────┐   不透明,挡住内容
3├──────────────────────────┤
4                          
5  Window Content             内容被限制在状态栏之下
6                          
7└──────────────────────────┘
8
9 FLAG_TRANSLUCENT_STATUS(未设 DRAWS_SYSTEM_BAR_BACKGROUNDS):
10┌─ 40% 黑色半透明状态栏 ────┐   半透明 scrim
11├──────────────────────────┤
12  Window Content             内容延伸到状态栏后面
13  (在状态栏后面可见)        
14                          
15└──────────────────────────┘
16
17FLAG_TRANSLUCENT_STATUS + FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS:
18┌─ statusBarColor = blue ──┐   自定义颜色
19├──────────────────────────┤
20  Window Content             内容延伸到状态栏后面
21  (在蓝色状态栏后面可见)     
22                          
23└──────────────────────────┘
24
android:windowTranslucentNavigation
1<item name="android:windowTranslucentNavigation">true</item>
2

LP.flags |= FLAG_TRANSLUCENT_NAVIGATION

与上面完全对称,作用于底部导航栏。对于全面屏手势设备(Android 10+),导航栏非常窄(通常只有一个横条),这个属性影响的是导航手势区域的颜色。

android:windowDrawsSystemBarBackgrounds
1<item name="android:windowDrawsSystemBarBackgrounds">true</item>
2
1if (a.getBoolean(R.styleable.Window_windowDrawsSystemBarBackgrounds, false)) {
2    setFlags(FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS,
3             FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
4}
5

LP.flags |= FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS

核心作用:告诉 WMS「系统栏的背景色由我的 statusBarColor / navigationBarColor 决定,你不要画默认的半透明黑色背景了」。

这三个属性必须成组使用

1<!-- 设置状态栏颜色的"正确姿势"三部曲 -->
2<item name="android:windowTranslucentStatus">true</item>
3<item name="android:windowDrawsSystemBarBackgrounds">true</item>
4<item name="android:statusBarColor">@color/primary_dark</item>
5

为什么 Theme.Material3.DayNight.NoActionBar 不需要手动设前两个?

因为 Google 在 Theme.Material3.DayNight 中已经预设了这些值为 true(至少在 API 21+ 的版本中)。如果你的 Theme 没有继承 Material3,或基于旧主题,就需要手动添加。

android:windowLightStatusBar
1<item name="android:windowLightStatusBar">true</item>
2

→ 在 Android 11+ (API 30+) 中通过 WindowInsetsController.setSystemBarsAppearance() 设置 APPEARANCE_LIGHT_STATUS_BARS

1// API 30+ 的实现路径
2final WindowInsetsController controller = getWindowInsetsController();
3if (controller != null) {
4    controller.setSystemBarsAppearance(
5        APPEARANCE_LIGHT_STATUS_BARS,   // 外观值
6        APPEARANCE_LIGHT_STATUS_BARS);  // mask
7}
8

作用:状态栏的背景是浅色(如白色)时,状态栏图标(时间、电池、信号等)变为深色。

使用场景

  • 浅色主题:如果 statusBarColor 是浅色(如白色、浅灰),必须设置此属性使图标可读
  • 白色状态栏:iOS 风格的白色顶部栏
  • 透明背景 + 浅色内容:图片延伸到状态栏后面且图片顶部是浅色

API 差异

API 级别实现方式
API 23-29View.setSystemUiVisibility(SYSTEM_UI_FLAG_LIGHT_STATUS_BAR)
API 30+WindowInsetsController.setSystemBarsAppearance(APPEARANCE_LIGHT_STATUS_BARS)
Theme 属性上述两个路径的声明式封装
android:windowLightNavigationBar
1<item name="android:windowLightNavigationBar">true</item>
2

→ 浅色导航栏背景 + 深色导航栏图标(三条横线或药丸按钮)。

使用场景:浅色底部的 UI(如浅色底部导航栏 + 浅色系统导航栏)。

android:enforceNavigationBarContrast / android:enforceStatusBarContrast
1<item name="android:enforceNavigationBarContrast">true</item>
2

→ API 29+,当系统栏内容(图标/文字)与你的窗口内容颜色对比度不足时,强制在系统栏后面添加一层半透明 scrim 确保可读性。

使用场景:当你的状态栏/导航栏颜色与背景图片/内容颜色相近,导致图标不可读时,开启此属性可自动添加保护层。Android 15 的 Edge-to-Edge 模式默认启用此行为。

android:windowFullscreen
1<item name="android:windowFullscreen">true</item>
2

→ 传统全屏模式(隐藏所有系统栏)。在现代开发中,推荐使用 FLAG_TRANSLUCENT_STATUS + FLAG_TRANSLUCENT_NAVIGATION + FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS 的方式实现全屏(因为用户可以随时下滑唤出系统栏),或者使用 WindowInsetsController.hide() / WindowInsetsController.show()


5.6 软键盘(SoftInput)类

android:windowSoftInputMode
1<item name="android:windowSoftInputMode">stateVisible|adjustResize</item>
2

这是最复杂但也最常用的属性之一。整个值是一个位掩码,分为状态 (state) 和调整 (adjust) 两部分,用 | 组合。

完整取值表

XML 值常量位值含义
状态部分(低 4 bits)
stateUnspecifiedSTATE_UNSPECIFIED0系统决定(通常是 hide)
stateUnchangedSTATE_UNCHANGED1保持上一 Activity 的键盘状态
stateHiddenSTATE_HIDDEN2进入时键盘隐藏
stateAlwaysHiddenSTATE_ALWAYS_HIDDEN3窗口获得焦点时隐藏键盘
stateVisibleSTATE_VISIBLE4进入时键盘显示
stateAlwaysVisibleSTATE_ALWAYS_VISIBLE5窗口获得焦点时显示键盘
调整部分(高 4 bits)
adjustUnspecifiedADJUST_UNSPECIFIED0x00系统决定(通常 = resize)
adjustResizeADJUST_RESIZE0x10键盘弹出时压缩窗口
adjustPanADJUST_PAN0x20键盘弹出时平移窗口
adjustNothingADJUST_NOTHING0x30键盘弹出时不做任何调整

PhoneWindow 源码消费

1// generateLayout()  实际在 Window.java 基类中
2final int softInputMode = a.getInt(
3    R.styleable.Window_windowSoftInputMode, 0);
4if (softInputMode != 0) {
5    getAttributes().softInputMode = softInputMode;  // 直接赋值
6    mHasSoftInputMode = true;  // 标记为"已设置",防止回退
7}
8

LayoutParams 影响LP.softInputMode 直接赋值

adjustResize vs adjustPan 的深入对比

1adjustResize:
2┌──────────────────┐
3  Toolbar            保持可见
4  ┌────────────┐  
5   ScrollView      窗口被压缩,可以滚动
6   EditText        焦点 EditText 自动可见(在可见区域内)
7  └────────────┘  
8├──────────────────┤
9    键盘区域       
10└──────────────────┘
11适用:列表/表单(内容可滚动)
12
13
14adjustPan:
15┌──────────────────┐
16                  
17                     整个窗口向上平移
18  EditText           焦点 EditText 保持可见
19├──────────────────┤
20    键盘区域       
21├──────────────────┤
22  Toolbar            Toolbar 可能被顶出屏幕!
23└──────────────────┘
24适用:简单表单(少量输入框在页面底部时)
25

使用场景

场景推荐模式原因
聊天页面(底部输入框 + 消息列表)adjustResize列表内容随键盘弹出自动上移
登录页面(顶部 Logo + 底部输入框)adjustResize整体缩放,Logo 可见但变小
简单表单(少量底部输入框)adjustPan平移即可露出输入框
全屏视频(键盘用于弹幕)adjustNothing键盘弹出不应移动视频画面
搜索页面(搜索框在顶部的列表)adjustResize列表需要重新布局
沉浸式游戏(虚拟键盘)adjustNothing游戏画面不应被键盘影响

stateAlwaysHidden 的妙用

1<item name="android:windowSoftInputMode">stateAlwaysHidden</item>
2

→ 用户点击 EditText 时键盘不会自动弹出,除非用户主动点击才会弹出。最适合搜索页(用户不想进入页面就看到键盘)。

默认值:如果没有设置 windowSoftInputMode,默认值是 STATE_UNCHANGED | ADJUST_RESIZE


5.7 转场动画类

API 21+ 引入的 Activity Transition 框架,所有属性在 generateLayout() 读取。

转场属性全景图
1Activity A    Activity B  的过程涉及的转场:
2
3windowExitTransition        Activity A 内容退出(如 Fade)
4windowEnterTransition       Activity B 内容进入(如 Explode)
5
6用户按返回键 (B  A)
7
8windowReturnTransition      Activity B 内容退出
9windowReenterTransition     Activity A 内容重新进入
10
11Shared Element(如头像从列表页飞入详情页):
12
13windowSharedElementExitTransition    A 的共享元素退出
14windowSharedElementEnterTransition   B 的共享元素进入
15windowSharedElementReenterTransition← 返回时重新进入
16windowSharedElementReturnTransition  返回时退出
17
android:windowActivityTransitions
1<item name="android:windowActivityTransitions">true</item>
2

→ 总开关。必须设为 true,后续的所有 Transition 设置才会生效。

android:windowEnterTransition / android:windowExitTransition
1<item name="android:windowEnterTransition">@transition/explode</item>
2<item name="android:windowExitTransition">@transition/fade</item>
3

使用场景

  • 页面切换动画:替代 overridePendingTransition()
  • Material Motion:Material Design 的转场系统
  • Shared Element Transition:必须配合这些属性才能工作
android:windowReturnTransition / android:windowReenterTransition

返回时的转场动画(按返回键时触发)。默认与 exit/enter 相同,但可以设置为不同:

1<item name="android:windowEnterTransition">@transition/slide_right</item>  <!-- 从右侧滑入 -->
2<item name="android:windowReturnTransition">@transition/slide_left</item>  <!-- 从左侧滑出 -->
3
android:windowSharedElementEnterTransition / android:windowSharedElementExitTransition

Shared Element 的内容转场。默认为 @transition/move(即系统内置的 ChangeBounds + ChangeTransform + ChangeClipBounds 组合)。

1<item name="android:windowSharedElementEnterTransition">@transition/change_image_transform</item>
2
android:windowAllowEnterTransitionOverlap / android:windowAllowReturnTransitionOverlap
1<item name="android:windowAllowEnterTransitionOverlap">true</item>
2

→ 设为 true 时,调用 startActivity() 后,当前 Activity 的退出动画和下一个 Activity 的进入动画并行执行;设为 false 时,串行执行(先退出完再进入)。

使用场景

android:windowTransitionBackgroundFadeDuration
1<item name="android:windowTransitionBackgroundFadeDuration">300</item>
2

→ 转场过程中,windowBackground 的淡出/淡入动画时长(毫秒)。这对于避免 Shared Element Transition 期间出现"白色闪烁"非常有用——设置一个合理的 fade duration 让背景渐变过渡。

代码中的等价实现
1//  Activity 中代码设置 Transition(与 Theme 属性等价)
2getWindow().requestFeature(Window.FEATURE_ACTIVITY_TRANSITIONS);
3getWindow().setEnterTransition(new Explode());
4getWindow().setExitTransition(new Fade());
5getWindow().setAllowEnterTransitionOverlap(true);
6

5.8 像素格式与绘制类

android:windowIsTranslucent
1<item name="android:windowIsTranslucent">true</item>
2

这是影响最深远的属性之一。它直接改变了 Window 所在 Surface 的像素格式。

PhoneWindow 源码全链路

1//  1 步:构造函数中标记
2if (a.getBoolean(R.styleable.Window_windowIsTranslucent, false)) {
3    // 先清除一些 flags(这些 flags  translucent 不兼容)
4    setFlags(0,
5        FLAG_NOT_TOUCHABLE   // translucent 意味着需要触摸
6        | FLAG_NOT_FOCUSABLE // translucent 意味着可以获得焦点
7    );
8    // 设置输入特性
9    params.inputFeatures |= INPUT_FEATURE_NO_INPUT_CHANNEL;
10}
11
12//  2 步:generateLayout() 中应用
13if (mTranslucent) {
14    lp.format = PixelFormat.TRANSLUCENT;  //  核心!
15}
16
17//  3 步:后续初始化
18if (mTranslucent) {
19    // translucent 窗口不设置 windowBackground 的前景 scrim
20    // 因为窗口本身就是半透明的
21}
22

LayoutParams 影响

字段变化
LP.formatOPAQUE → TRANSLUCENT

PixelFormat.TRANSLUCENT vs OPAQUE 对 SurfaceFlinger 的影响

1OPAQUE (默认):
2  SurfaceFlinger 将该 Layer 标记为 "不透明"
3  合成时不需要读取下层 Layer 的像素
4  性能:快(跳过混合运算)
5
6TRANSLUCENT:
7  SurfaceFlinger 将该 Layer 标记为 "带 alpha 通道"
8  合成时读取每个像素的 alpha 值,与下层做逐像素混合
9  性能:慢(增加 GPU 负载和带宽消耗)
10

完整的半透明 Activity Theme

1<style name="Theme.Transparent" parent="Theme.Material3.DayNight.NoActionBar">
2    <!--  3 个缺一不可 -->
3    <item name="android:windowIsTranslucent">true</item>
4    <item name="android:windowBackground">@android:color/transparent</item>
5    <item name="android:windowNoTitle">true</item>
6
7    <!-- 可选优化 -->
8    <item name="android:windowDisablePreview">true</item>  <!-- 避免启动闪烁 -->
9    <item name="android:windowAnimationStyle">@null</item> <!-- 移除默认动画 -->
10</style>
11

常见问题诊断

症状原因
背景是黑色不是透明的只设了 windowIsTranslucent=true,没设 windowBackground=transparent
状态栏区域是黑色的状态栏没设 translucent,半透明只对 content 生效
触摸穿透到了下层 AppwindowIsTranslucent 清理了 FLAG_NOT_TOUCHABLE,确认是否在其他地方又被设置了
启动时短暂白屏设置了 windowBackground=transparent 但没设置 windowDisablePreview=true
android:windowSwipeToDismiss
1<item name="android:windowSwipeToDismiss">true</item>
2

→ 启用滑动关闭手势(iOS 风格的侧滑返回)。

使用场景

  • 图片预览 / 大图浏览:下滑关闭
  • 视频播放:下滑缩小/关闭
  • 模态页面:iOS 风格的下滑 dismiss

5.9 FitSystemWindows 与 Edge-to-Edge 类

android:fitsSystemWindows

这是 View 属性而非 Window 属性,但在 Theme 中设置时会作用于 DecorView:

1<item name="android:fitsSystemWindows">true</item>
2

→ 设置 DecorView 的 fitsSystemWindows = true。DecorView 在 dispatchApplyWindowInsets() 时会先消费掉状态栏/导航栏的 insets(为其 padding),然后将剩余的 insets 分发给子 View。

使用场景

  • 需要内容自动避开状态栏:如标准的列表页面
  • 与 CoordinatorLayout 配合:CoordinatorLayout 自身会处理 insets

fitsSystemWindows = true 的效果

1状态栏 24dp ─┐
2              DecorView 消费了此 inset,给自身加 paddingTop=24dp
3                View 收到调整后的 insets(状态栏部分已消耗)
4内容区域    
5              效果:内容自动在状态栏下方开始,不会被遮挡
6导航栏 48dp ─┘
7
android:windowOptOutEdgeToEdgeEnforcement
1<item name="android:windowOptOutEdgeToEdgeEnforcement">true</item>
2

Android 15+ (API 35) 新增。从 API 35 开始,targetSdk=35 的应用默认强制启用 Edge-to-Edge 模式——即系统自动设置 FLAG_LAYOUT_IN_SCREENFLAG_TRANSLUCENT_STATUSFLAG_TRANSLUCENT_NAVIGATION 等标志,使窗口内容延伸到系统栏后面。

如果你需要退出这个行为(例如你的旧 UI 大量依赖 fitsSystemWindows 而没有使用 WindowInsets),设置此属性为 true:

1<item name="android:windowOptOutEdgeToEdgeEnforcement">true</item>
2

建议:尽量适配 Edge-to-Edge 而非 opt-out。Google 的长期方向是全面 Edge-to-Edge。

android:windowLayoutInDisplayCutoutMode
1<item name="android:windowLayoutInDisplayCutoutMode">shortEdges</item>
2

可选值:

XML 值常量行为
default (0)LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT竖屏:不允许伸入刘海;横屏:允许
shortEdges (1)LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES允许内容延伸到短边的刘海区域
never (2)LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER永远不允许延伸到刘海
always (3)LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS系统栏透明时允许延伸到任何方向的刘海
1int cutoutMode = a.getInt(
2    R.styleable.Window_windowLayoutInDisplayCutoutMode, 0);
3if (cutoutMode != 0) {
4    lp.layoutInDisplayCutoutMode = cutoutMode;
5}
6

LayoutParams 影响LP.layoutInDisplayCutoutMode

使用场景

场景推荐模式原因
普通列表页面default竖屏不伸入刘海,安全稳妥
全屏视频/游戏shortEdges利用顶部刘海两侧区域显示内容
横屏全屏always让内容充满整个屏幕(包括刘海后面)
刘海区域有重要 UI 元素never确保 UI 不被刘海遮挡

5.10 其他行为属性

android:windowCloseOnTouchOutside
1<item name="android:windowCloseOnTouchOutside">true</item>
2
1if (a.getBoolean(R.styleable.Window_windowCloseOnTouchOutside, false)) {
2    setCloseOnTouchOutsideIfNotSet(true);
3}
4

LayoutParams 影响LP.flags |= FLAG_NOT_TOUCH_MODAL | FLAG_WATCH_OUTSIDE_TOUCH

完整实现链路

1用户触摸 Dialog 外部区域
2   WMS 发送 ACTION_OUTSIDE 到该 Dialog
3     PhoneWindow 收到 ACTION_OUTSIDE
4       回调 to Window.onTouchEvent()
5         调用 dispatchTouchEvent()
6           因为 closeOnTouchOutside=true
7             判断触摸坐标在 DecorView 外部
8               调用 Activity.finish() (如果 attached  Activity)
9

使用场景

  • Dialog 样式 ActivityTheme.AppCompat.Dialog 默认开启
  • 底部菜单 / ActionSheet
  • Dropdown 菜单
  • PopupWindow
android:windowAnimationStyle
1<item name="android:windowAnimationStyle">@style/MyWindowAnimation</item>
2
1mAnimationStyle = a.getResourceId(
2    R.styleable.Window_windowAnimationStyle, 0);
3

LayoutParams 影响LP.windowAnimations = mAnimationStyle

这个资源 ID 传给 WMS,WMS 在窗口出现/消失时查找对应的 WindowAnimation 资源并播放。

自定义窗口动画

1<!-- res/values/styles.xml -->
2<style name="MyWindowAnimation">
3    <!-- 进入动画 -->
4    <item name="android:activityOpenEnterAnimation">@anim/slide_in_right</item>
5    <!-- 退出动画 -->
6    <item name="android:activityOpenExitAnimation">@anim/slide_out_left</item>
7    <!-- 返回时的进入动画 -->
8    <item name="android:activityCloseEnterAnimation">@anim/slide_in_left</item>
9    <!-- 返回时的退出动画 -->
10    <item name="android:activityCloseExitAnimation">@anim/slide_out_right</item>
11</style>
12

使用场景:任何需要自定义窗口转场动画的场景——做预设动画、淡入淡出、从底部弹出等。

android:windowBackgroundBlurRadius
1<item name="android:windowBackgroundBlurRadius">25dp</item>
2

→ API 31+,配合 windowBlurBehind 使用,设置背景模糊半径。值越大越模糊,但 GPU 开销越大。

android:backgroundDimAmount
1<item name="android:backgroundDimAmount">0.6</item>
2

→ 配合 FLAG_DIM_BEHIND 使用,设置下层窗口变暗的程度(0.0=不变暗,1.0=全黑)。Dialog 的默认值大约是 0.5。

android:backgroundDimEnabled
1<item name="android:backgroundDimEnabled">true</item>
2

→ 是否启用背景变暗(通常与 FLAG_DIM_BEHIND 联动)。

android:windowSplashScreenBackground (API 31+)
1<item name="android:windowSplashScreenBackground">@color/splash_bg</item>
2

→ Android 12+ SplashScreen API 使用的启动窗口背景色。等价于在代码中:

1SplashScreen splashScreen = SplashScreen.installSplashScreen(this);
2// 背景色通过 Theme 属性设置,代码中不需要额外调用
3
android:windowSplashScreenAnimationDuration (API 31+)
1<item name="android:windowSplashScreenAnimationDuration">300</item>
2

→ SplashScreen 动画持续时间(毫秒)。注意:系统会根据应用冷启动耗时决定实际显示时长,此值只是一个参考上限。

android:windowSplashScreenIcon (API 31+)

→ SplashScreen 中心图标(通常不需要手动设置,系统用应用图标)。

android:windowContentTransitions

→ 允许窗口内容在布局变化时启用 Transition(如 TransitionManager.beginDelayedTransition)。

android:windowHideAnimation / android:windowShowAnimation

→ 已废弃,被 windowAnimationStyle 和 Transition 框架取代。


6. 完整映射表速查

Theme XML 属性PhoneWindow 读取入口目标字段设置的 Flag/值
Flags 映射
windowNoDisplay构造函数LP.flagsFLAG_NOT_TOUCHABLE | FLAG_NOT_FOCUSABLE
windowDisablePreview构造函数LP.flagsFLAG_DISABLE_PREVIEW
windowEnableSplitTouch构造函数LP.flagsFLAG_SPLIT_TOUCH
windowShowWallpaper构造函数LP.flagsFLAG_SHOW_WALLPAPER
windowBlurBehind构造函数LP.flagsFLAG_BLUR_BEHIND (API 31+)
windowSecure构造函数LP.flags + InputChannelFLAG_SECURE
windowNotTouchablegenerateLayoutLP.flagsFLAG_NOT_TOUCHABLE
windowFullscreengenerateLayoutLP.flagsFLAG_FULLSCREEN
windowTranslucentStatusgenerateLayoutLP.flagsFLAG_TRANSLUCENT_STATUS (+ 隐式 LAYOUT_IN_SCREEN)
windowTranslucentNavigationgenerateLayoutLP.flagsFLAG_TRANSLUCENT_NAVIGATION
windowDrawsSystemBarBackgroundsgenerateLayoutLP.flagsFLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS
windowDimBehindgenerateLayoutLP.flagsFLAG_DIM_BEHIND
windowCloseOnTouchOutsidegenerateLayoutLP.flagsFLAG_NOT_TOUCH_MODAL | FLAG_WATCH_OUTSIDE_TOUCH
尺寸映射
windowFixedWidthgenerateLayoutLP.width固定像素值
windowFixedHeightgenerateLayoutLP.height固定像素值
windowFixedWidthMajorgenerateLayoutLP.width条件覆写(长边)
windowFixedWidthMinorgenerateLayoutLP.width条件覆写(短边)
windowMinWidthMajorgenerateLayoutLP.minWidth最小宽度(长边)
windowMinWidthMinorgenerateLayoutLP.minWidth最小宽度(短边)
windowElevationgenerateLayoutLP.elevationfloat (px)
windowIsFloating构造函数mIsFloating → LP.width/height/gravityWRAP_CONTENT + CENTER
系统栏映射
statusBarColorgenerateLayoutmStatusBarColor → InsetsControllerColor int
navigationBarColorgenerateLayoutmNavigationBarColor → InsetsControllerColor int
windowLightStatusBargenerateLayoutInsetsControllerAPPEARANCE_LIGHT_STATUS_BARS
windowLightNavigationBargenerateLayoutInsetsControllerAPPEARANCE_LIGHT_NAVIGATION_BARS
enforceNavigationBarContrastgenerateLayoutInsetsControllerBoolean
enforceStatusBarContrastgenerateLayoutInsetsControllerBoolean
软键盘映射
windowSoftInputModegenerateLayoutLP.softInputMode位掩码组合
像素与绘制映射
windowIsTranslucent构造函数 + generateLayoutLP.formatPixelFormat.TRANSLUCENT
windowClipToOutlinegenerateLayoutLP.flagsFLAG_LAYOUT_NO_LIMITS
转场动画映射
windowActivityTransitionsgenerateLayoutmActivityTransitionsAllowedboolean
windowEnterTransitiongenerateLayoutmEnterTransitionTransition ref
windowExitTransitiongenerateLayoutmExitTransitionTransition ref
windowReenterTransitiongenerateLayoutmReenterTransitionTransition ref
windowReturnTransitiongenerateLayoutmReturnTransitionTransition ref
windowSharedElementEnterTransitiongenerateLayoutmSharedElementEnterTransitionTransition ref
windowSharedElementExitTransitiongenerateLayoutmSharedElementExitTransitionTransition ref
windowAllowEnterTransitionOverlapgenerateLayoutmAllowEnterTransitionOverlapboolean
windowAllowReturnTransitionOverlapgenerateLayoutmAllowReturnTransitionOverlapboolean
windowTransitionBackgroundFadeDurationgenerateLayoutmBackgroundFadeDurationMillislong (ms)
背景映射
windowBackgroundgenerateLayoutmBackgroundDrawable → DecorViewDrawable/Color
windowBackgroundFallbackgenerateLayoutmBackgroundFallbackDrawable/Color
windowBackgroundBlurBehindgenerateLayoutmBackgroundBlurBehindboolean
windowBackgroundBlurRadiusgenerateLayoutmBackgroundBlurRadiusint
backgroundDimAmountgenerateLayoutLP.dimAmountfloat
Feature 映射
windowNoTitlegenerateLayoutrequestFeature(FEATURE_NO_TITLE)
windowActionBargenerateLayoutrequestFeature(FEATURE_ACTION_BAR)
windowActionModeOverlaygenerateLayoutrequestFeature(FEATURE_ACTION_MODE_OVERLAY)
动画映射
windowAnimationStyle构造函数LP.windowAnimationsstyle resource id
Cutout 映射
windowLayoutInDisplayCutoutModegenerateLayoutLP.layoutInDisplayCutoutModeint enum
Edge-to-Edge 映射
windowOptOutEdgeToEdgeEnforcement构造函数 (API 35+)退出强制 Edge-to-Edgeboolean
其他
windowContentOverlaygenerateLayoutmContentOverlay → DecorViewDrawable
windowTitleSizegenerateLayoutTitleView textSizepx
windowSwipeToDismissgenerateLayout注册滑动监听器boolean
windowSplashScreenBackground— (SplashScreen API)启动画面背景Color
windowSplashScreenAnimationDuration— (SplashScreen API)启动画面动画时长int (ms)
windowContentTransitionsgenerateLayoutmContentTransitionsAllowedboolean

7. 实战场景

以下每个场景都给出了完整的 Theme XML 配置等价的 Java 代码,以及关键属性的解释。

7.1 全屏 Activity

效果:隐藏状态栏和导航栏,Window 占据全部屏幕。

1<!-- res/values/themes.xml -->
2<style name="Theme.Fullscreen" parent="Theme.Material3.DayNight.NoActionBar">
3    <item name="android:windowFullscreen">true</item>
4    <item name="android:windowNoTitle">true</item>
5</style>
6

等价 Java 代码

1@Override
2protected void onCreate(Bundle savedInstanceState) {
3    super.onCreate(savedInstanceState);
4    getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
5    setContentView(R.layout.activity_fullscreen);
6}
7

现代推荐方式(Android 11+,允许用户下滑唤出系统栏):

1// 使用 WindowInsetsController 而非 FLAG_FULLSCREEN
2getWindow().getInsetsController().hide(WindowInsets.Type.systemBars());
3// 或让系统栏以半透明方式浮在内容上方
4getWindow().getInsetsController().setSystemBarsBehavior(
5    WindowInsetsController.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE);
6

7.2 透明背景 Activity / Dialog 样式 Activity

效果:Activity 的背景完全透明,可以看到下层窗口内容。

1<style name="Theme.Transparent" parent="Theme.Material3.DayNight.NoActionBar">
2    <item name="android:windowIsTranslucent">true</item>
3    <item name="android:windowBackground">@android:color/transparent</item>
4    <item name="android:windowNoTitle">true</item>
5    <item name="android:windowDisablePreview">true</item>
6    <item name="android:windowAnimationStyle">@null</item>
7</style>
8

在 AndroidManifest 中使用

1<activity
2    android:name=".TransparentActivity"
3    android:theme="@style/Theme.Transparent" />
4

使用范例

1public class TransparentActivity extends AppCompatActivity {
2    @Override
3    protected void onCreate(Bundle savedInstanceState) {
4        super.onCreate(savedInstanceState);
5        setContentView(R.layout.activity_transparent);
6        // 整个 Window 背景透明,只有 R.layout.activity_transparent
7        // 中的非透明 View 可见
8    }
9}
10

Dialog 样式 Activity(与上面类似,但加上了浮动窗口行为):

1<style name="Theme.DialogStyle" parent="Theme.Material3.DayNight.NoActionBar">
2    <item name="android:windowIsTranslucent">true</item>
3    <item name="android:windowBackground">@android:color/transparent</item>
4    <item name="android:windowIsFloating">true</item>
5    <item name="android:windowCloseOnTouchOutside">true</item>
6    <item name="android:windowNoTitle">true</item>
7    <item name="android:backgroundDimEnabled">true</item>
8    <item name="android:backgroundDimAmount">0.5</item>
9</style>
10

7.3 自定义状态栏颜色(Material 风格)

效果:状态栏颜色与 ActionBar/Toolbar 颜色统一。

1<style name="Theme.CustomStatusBar" parent="Theme.Material3.DayNight.NoActionBar">
2    <!-- 三部曲:缺一不可 -->
3    <item name="android:windowTranslucentStatus">true</item>
4    <item name="android:windowDrawsSystemBarBackgrounds">true</item>
5    <item name="android:statusBarColor">@color/colorPrimaryDark</item>
6
7    <!-- 如果是浅色状态栏,加上这个 -->
8    <item name="android:windowLightStatusBar">true</item>
9
10    <!-- 同样处理导航栏 -->
11    <item name="android:windowTranslucentNavigation">true</item>
12    <item name="android:navigationBarColor">@color/colorPrimaryDark</item>
13</style>
14

Java 等价代码

1getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
2getWindow().addFlags(
3    WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
4getWindow().setStatusBarColor(ContextCompat.getColor(this, R.color.colorPrimaryDark));
5
6// Android 11+
7getWindow().getInsetsController().setSystemBarsAppearance(
8    WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS,
9    WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS);
10

7.4 图片查看器(沉浸式)

效果:图片充满屏幕,状态栏和导航栏以半透明浮层方式覆盖,点击可切换。

1<style name="Theme.ImageViewer" parent="Theme.Material3.DayNight.NoActionBar">
2    <!-- 系统栏透明,内容延伸到后面 -->
3    <item name="android:windowTranslucentStatus">true</item>
4    <item name="android:windowTranslucentNavigation">true</item>
5    <item name="android:windowDrawsSystemBarBackgrounds">true</item>
6
7    <!-- 状态栏和导航栏:半透明深色 -->
8    <item name="android:statusBarColor">#40000000</item>
9    <item name="android:navigationBarColor">#40000000</item>
10
11    <!-- 深色系统栏图标(因为半透明深色背景上暗色图标看不清) -->
12    <item name="android:windowLightStatusBar">false</item>
13    <item name="android:windowLightNavigationBar">false</item>
14
15    <!-- 背景黑色,适合图片查看 -->
16    <item name="android:windowBackground">@android:color/black</item>
17</style>
18

点击切换显示/隐藏系统栏的代码

1private boolean isSystemBarsVisible = true;
2
3private void toggleSystemBars() {
4    if (isSystemBarsVisible) {
5        // 隐藏系统栏
6        getWindow().getInsetsController().hide(
7            WindowInsets.Type.systemBars());
8    } else {
9        // 显示系统栏
10        getWindow().getInsetsController().show(
11            WindowInsets.Type.systemBars());
12    }
13    isSystemBarsVisible = !isSystemBarsVisible;
14}
15

7.5 锁屏上显示窗口

效果:在锁屏上方显示一个窗口(如来电界面、闹钟)。

1<style name="Theme.LockScreenOverlay" parent="Theme.Material3.DayNight.NoActionBar">
2    <item name="android:windowShowWhenLocked">true</item>
3    <item name="android:windowTurnScreenOn">true</item>
4    <item name="android:windowDismissKeyguard">true</item>
5    <item name="android:windowKeepScreenOn">true</item>
6</style>
7

⚠️ 注意windowShowWhenLockedwindowTurnScreenOnwindowDismissKeyguard 等属性不能直接在 Theme XML 中设置,因为它们需要特殊权限或必须在代码中使用 setFlags() 动态设置。上述 XML 仅是示意对应关系。实际实现为:

1//  Activity.onCreate() 中(必须在 setContentView 之前)
2getWindow().addFlags(
3    WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED
4    | WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON
5    | WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD
6    | WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
7

7.6 禁止截屏的敏感页面

效果:阻止系统截屏和录屏。

1<style name="Theme.Secure" parent="Theme.Material3.DayNight.NoActionBar">
2    <item name="android:windowSecure">true</item>
3</style>
4

Java 等价代码

1@Override
2protected void onCreate(Bundle savedInstanceState) {
3    super.onCreate(savedInstanceState);
4    getWindow().addFlags(WindowManager.LayoutParams.FLAG_SECURE);
5    setContentView(R.layout.activity_secure);
6}
7

7.7 软键盘适配表单页面

场景一:聊天页面(底部输入框 + 消息列表)

1<style name="Theme.Chat" parent="Theme.Material3.DayNight.NoActionBar">
2    <item name="android:windowSoftInputMode">stateHidden|adjustResize</item>
3</style>
4
  • stateHidden:进入页面时不弹出键盘
  • adjustResize:键盘弹出时压缩消息列表,使最新消息可见

场景二:登录页面(顶部 Logo + 底部输入框)

1<style name="Theme.Login" parent="Theme.Material3.DayNight.NoActionBar">
2    <item name="android:windowSoftInputMode">stateHidden|adjustResize</item>
3</style>
4
  • 同样使用 adjustResize,但需要对布局做处理——如使用 ConstraintLayout 让 Logo 随窗口压缩而缩放或上移

场景三:搜索页面

1<style name="Theme.Search" parent="Theme.Material3.DayNight.NoActionBar">
2    <item name="android:windowSoftInputMode">stateAlwaysHidden|adjustResize</item>
3</style>
4
  • stateAlwaysHidden:即使用户上次在别的页面打开了键盘,进入搜索页也不自动弹出

8. 最佳实践与常见陷阱

8.1 statusBarColor 不生效的 4 种可能

1<!-- 正确配置(缺一不可) -->
2<item name="android:windowTranslucentStatus">true</item>
3<item name="android:windowDrawsSystemBarBackgrounds">true</item>
4<item name="android:statusBarColor">@color/custom</item>
5

检查清单

  1. windowTranslucentStatus 是否为 true
  2. windowDrawsSystemBarBackgrounds 是否为 true
  3. statusBarColor 是否被父 Theme 覆盖?(使用 styles.xmlparent 链追查)
  4. ☐ 代码中是否调用了 getWindow().setStatusBarColor(Color.TRANSPARENT) 或其他 setter 覆盖了 Theme 值?

8.2 透明 Activity 背景显示为黑色

1<!-- 错误 -->
2<item name="android:windowIsTranslucent">true</item>
3
4<!-- 正确:同时设置透明背景 -->
5<item name="android:windowIsTranslucent">true</item>
6<item name="android:windowBackground">@android:color/transparent</item>
7

原因windowIsTranslucent 只改变了 Surface 的像素格式(TRANSLUCENT),但 DecorView 的背景仍然从 Theme 继承为默认的白色(或主题默认颜色)。如果不覆写 windowBackground 为透明,DecorView 会用不透明的默认背景填满整个窗口。

8.3 windowSoftInputMode Theme vs 代码的优先级

Theme 默认值 → 代码覆写:代码中的 getWindow().setSoftInputMode() 会完全覆盖 Theme 中的 windowSoftInputMode

1@Override
2protected void onCreate(Bundle savedInstanceState) {
3    super.onCreate(savedInstanceState);
4    //  必须在 super.onCreate() 之后,
5    //     setContentView() 之前调用
6    getWindow().setSoftInputMode(
7        WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN);
8    setContentView(R.layout.my_layout);
9}
10

为什么必须在 setContentView 之前? 因为 setContentView 触发了 generateLayout(),而 generateLayout() 中会检查 mHasSoftInputMode。如果代码中已经调用过 setSoftInputMode(),则 mHasSoftInputMode = true,Theme 中的值被跳过。

8.4 Flags 设置的正确姿势

1// addFlags:添加 flags(OR 操作,不影响其他 bit)
2getWindow().addFlags(FLAG_SECURE);
3// 等价于:flags |= FLAG_SECURE
4
5// clearFlags:清除 flags(AND NOT 操作)
6getWindow().clearFlags(FLAG_SECURE);
7// 等价于:flags &= ~FLAG_SECURE
8
9// setFlags(mask, value):
10//   mask 中为 1  bit  设为 value 中对应 bit 的值
11//   mask 中为 0  bit  保持不变
12getWindow().setFlags(FLAG_SECURE, FLAG_SECURE);  // 打开
13getWindow().setFlags(0, FLAG_SECURE);             // 关闭
14// 等价于:flags = (flags & ~FLAG_SECURE) | (FLAG_SECURE & FLAG_SECURE)
15
16// getAttributes() 后直接修改(需要额外调用 setAttributes)
17WindowManager.LayoutParams lp = getWindow().getAttributes();
18lp.flags |= FLAG_SECURE;
19getWindow().setAttributes(lp);  // 触发 relayout
20

8.5 Android 15 Edge-to-Edge 迁移

targetSdk = 35 时必须面对的迁移:

老代码(依赖 fitsSystemWindows):

1<item name="android:fitsSystemWindows">true</item>
2

新代码(适配 Edge-to-Edge):

1// 方案 1:在 root View 中处理 WindowInsets
2ViewCompat.setOnApplyWindowInsetsListener(rootView) { view, insets ->
3    val statusBars = insets.getInsets(WindowInsetsCompat.Type.statusBars())
4    val navBars = insets.getInsets(WindowInsetsCompat.Type.navigationBars())
5    view.setPadding(
6        view.paddingLeft,
7        statusBars.top,
8        view.paddingRight,
9        navBars.bottom
10    )
11    WindowInsetsCompat.CONSUMED
12}
13
14// 方案 2(不想适配):退出强制模式
15//  Theme 中:
16<item name="android:windowOptOutEdgeToEdgeEnforcement">true</item>
17

8.6 windowClipToOutline 不生效?

windowClipToOutline 需要同时满足以下条件:

  1. windowClipToOutline = true
  2. windowBackground 设置了带有圆角/自定义形状的 Drawable
  3. windowElevation 已设置(需要 Z 轴高度来触发阴影/裁剪)

8.7 Shared Element Transition 闪烁

如果 Shared Element Transition 期间出现白色闪烁:

1<!-- 增加背景淡出时长,平滑过渡 -->
2<item name="android:windowTransitionBackgroundFadeDuration">300</item>
3<!-- 确保背景不是纯白 -->
4<item name="android:windowBackground">@color/window_background</item>
5

9. 总结

Android Theme 属性到 PhoneWindow 的映射链路核心归纳为四层:

1 1 层:定义层
2  R.styleable.Window(~120 个属性),在 attrs.xml 中声明
3  
4 2 层:读取层
5  PhoneWindow 构造函数(~15 个属性)+ generateLayout()(~80 个属性)
6  通过 TypedArray 读取
7  
8 3 层:分发层
9  根据属性类型分发到不同目标:
10  - requestFeature()     Feature flags(影响 DecorView 结构)
11  - addFlags()/setFlags()  LayoutParams.flags
12  - getAttributes()      LayoutParams 各字段
13  - setStatusBarColor()  InsetsController  SystemUI
14  - requestFitSystemWindows()  View insets 分发
15  
16 4 层:消费层
17  WindowManager.LayoutParams  IPC 传递  WMS  SurfaceFlinger
18  最终决定了窗口的 Z-order、尺寸、像素格式、输入事件策略、系统栏行为
19

核心要点

  • flags 是 Bitmask,正确理解每个 flag 的语义才能正确配置 Theme
  • 系统栏三件套windowTranslucentStatus + windowDrawsSystemBarBackgrounds + statusBarColor)是最常见的组合,缺一不可
  • windowIsTranslucent 改变了 Surface 像素格式,不仅是"背景透明",更是向下层窗口承诺了 alpha 通道
  • windowSoftInputMode 要在 setContentView 之前设置,否则 Theme 覆盖无效
  • Android 15 Edge-to-Edge 是未来趋势,尽早适配

理解这条链路,可以帮助你:

  • 精准定位 "为什么我的 window 样式不生效"
  • 在代码中精确覆写 Theme 默认值
  • 设计自定义 Dialog / 半透明 / 全屏 / 沉浸式等特殊窗口效果
  • 调试 WMS 相关的窗口行为异常

参考资料

本文基于 Android 14 (API 34) 源码分析,涵盖 Android 15 (API 35) 新增属性。

本文约 15000 字,阅读时间约 40 分钟。建议收藏,作为随手查阅的速查手册。


Android window属性全解析》 是转载文章,点击查看原文


相关推荐


GitHub 热榜项目 - 周榜(2026-07-04)
CoderJia_2026/7/8

GitHub 热榜项目 - 周榜(2026-07-04) 生成于:2026-07-04 共发现热门项目: 21 个 Token赞助:siliconflow 前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站。 本期热点趋势总结 本期 GitHub 热榜明显聚焦 AI Agent 工程化:多智能体协作、MCP / 知识图谱记忆、代码库索引与任务编排成为核心热点,代码生成、网页克隆、视频编辑、招聘评估等场景快速落地;


【从零开始大模型开发与微调:基于PyTorch与ChatGLM】(一学就会的深度学习基础算法详解)
承渊政道2026/6/30

🔥承渊政道:个人主页 ❄️个人专栏: 《C语言基础语法知识》 《数据结构与算法》 《C++知识内容》 《Linux系统知识》 《算法刷题指南》 《测评文章活动推广》 《大模型语言路线学习》 《MySQL数据库学习》 ✨逆境不吐心中苦,顺境不忘来时路!✨ 🎬 博主简介: 神经网络看起来由大量矩阵、激活函数和参数组成,但训练过程可以浓缩成四句话:先用当前参数完成一次预测;再用损失函数衡量预测有多差;接着通过链式法则把误差逐层传回;最后沿着能让损


栈和队列的实现
纪念 2292026/6/21

༺ 个人主页 · 纪念229 ༻ 🏠我的博客主页🏠 ༒专栏目录:《数据结构》༒ ༒其它有趣的计算机知识༒ ༺世上本没有路,走的人多了自然就有了༻ 这篇文章讲述的是用顺序表实现栈、用单链表实现队列,本文主要讲述栈和队列的定义,希望对大家有所帮助! 文章目录 1.Stack.h2.Stack.c2.1 STackDesTroy(ST* ps)2.2STackPush(ST* ps, STDataType x)2.3 STackEmpty(ST* ps)2.4 S


【云计算】华为公有云构建高可用Redis集群
Harvy_没救了2026/6/13

华为公有云构建高可用Redis集群(3主3从 + AS弹性扩容)详细方案 一、方案概述 本方案基于华为云服务(ECS、VPC、AS、IMS、ELB),手动搭建一个 Redis Cluster(3主3从),并通过 弹性伸缩AS 实现自动扩容(增加节点),但不配置自动缩容。扩容时新节点自动加入集群,并通过脚本完成集群拓扑更新。整体架构满足 高可用、负载均衡、水平扩展 的需求。 核心技术栈 服务作用VPC + 安全组隔离网络,保证内网互通ECS运行Redis服务的云服务器(6台基础节点)IMS


从零实现《三角洲行动》手游自动跑刀脚本:ADB 直控 + OpenCV 视觉识别 + 固定点位搜刮)三角洲自动跑刀教程
深度学习教程,2026/6/6

从零实现《三角洲行动》手游自动跑刀脚本:ADB 直控 + OpenCV 视觉识别 + 固定点位搜刮 从零实现《三角洲行动》手游自动跑刀脚本:ADB 直控 + OpenCV 视觉识别 + 固定点位搜刮一、前言二、整体架构与技术栈三、ADB 控制层:截图、点击、滑动四、核心难点一:怎么判断"真进游戏了"?五、核心难点二:识别"这把刷在哪个出生点"5.1 用圆检测把小地图"圆形抠出来"5.2 模板匹配识别出生点 六、核心难点三:自动拾取物资七、把它串起来:固定路线八、一个诚实的工程结论九、


React Native + RNOH:跨页面数据回传的最佳实践与避坑指南
皮蛋小精灵2026/5/31

从内存闭包到官方路由通信的深度对比 技术栈: React Native 0.77 + React Navigation v7 + RNOH(React Native OpenHarmony) 适用场景: 表单录入、列表选择器、跨页面数据回传通信 一句话结论: 内存闭包 Bridge 体验虽好但存在“热重载失效、系统回收丢回调、嵌套覆盖”三大致命缺陷;官方 route.params 需配合 setParams 清洗;在嵌套/鸿蒙 JS Stack 下,使用 CommonActions.setPa


aardio从惊喜到失望到被拉黑二三事
1681692026/5/9

aardio从惊喜到失望到被拉黑二三事 前情 其实我非常喜欢开发一些小工具,用于解决工作中和生活中的问题,我个人也有开发一些小程序和一些cli,但是对于桌面端一直没的找到好的开发方案,其中有试过autohotkey,但是它的语法和学习资料非常少,带你开发GUI就更少了,平时也就用用热词热键什么的,electron我也用过,但是它太重了,一直想找一个轻量点的,我也知道c#开发桌面工具非常不错,但是那要重新学一门语言,有想过学,但是一看c#教程就犯困也就没什么尝试了,直到某一天看到了aardio,真


一觉醒来,大模型就帮我排查完页面性能问题
candyTong2026/4/29

最近遇到一个性能问题,我让大模型自己去处理,然后就去午休了,醒来之后,它还真的把问题找出来并修复了 先说结果 最终定位出来的根因是: 这个业务工作台的查询表单,把 Formily 的 form 实例塞进了带 devtools 的 Zustand store。 这件事在开发环境里会非常要命,因为 form 不是一个轻量对象,它里面带着大量字段状态、reaction、effect、schema 和联动信息。 一旦进了 store,又被 devtools 观察、快照、序列化,内存就会被瞬间放大。


打造工业级全栈文件管理器:深度解析上传、回收站与三重下载流控技术
微特尔普拉斯2026/4/20

在构建企业级 Web 应用时,文件管理器是一个看似简单实则充满挑战的模块。面对大文件上传卡顿、大文件下载导致浏览器崩溃、以及误删不可恢复等痛点,我们需要一套更科学的架构方案。 本文将通过 Vue 2/3 + Spring Boot 的组合,详细拆解如何实现一套具备:排重检测、多线程后台下载、流式下载进度监控、以及回收站机制的文件管理系统。 一、 核心技术原理分析 1. 智能冲突检测上传 在上传文件前,系统会先发起一个“预检请求”(Check Exists)。 原理:前端获取文件名


一文搞懂Harness Engineering与Meta-Harness
GreenTea2026/4/12

一、什么是Harness Engineering harness engineering目前没有官方的英文翻译,但是我认为“驾驭工程”非常合适。“驾驭”一词本身有两层含义,“释放”与“约束”这两个相辅相成的维度,打个形象的比方,跟古代君臣关系一样,既要委以重任,又要设立制衡。 我们可以将这两层含义拆解如下: 1.1 释放潜力:让 AI 像工程师一样“真刀真枪”地干活 把模型放到现场,赋予了工程现场的实权,像一个工程师一样干活,能够接触代码库、执行命令,释放模型的潜力 传统的 Copilot

首页编辑器站点地图

本站内容在 CC BY-SA 4.0 协议下发布

Copyright © 2026 聚合阅读