UI 的根容器)在系统窗口中被系统留出的边距(insets)情况。 它负责: 处理拖拽事件(drag & drop) 响应手势(如返回、home、最近任务) 调整内容以避开系统 insets “检查 DragLayer 的 insets” 的意思这通常是指: 确保 DragLayer 正确应用了系统 Insets,即没有被状态栏、导航栏遮挡; 验证 insets 是否被 Launcher 正确计算(例如使用 onApplyWindowInsets()); 用于调试布局问题 (insets);}或者在 QuickstepLauncher.java 的 onInsetsChanged() 回调里:@Overridepublic void onInsetsChanged(Insets insets) { mDragLayer.setInsets(insets); // 检查 DragLayer 的 insets 是否正确生效} 小结 “检查 DragLayer 的 insets
“窗口 Insets(WindowInsets)” 不是 Android 15 才有的东西——它其实早在 Android 10(API 29) 之前就出现了,但到了 Android 11–15,它被彻底取代了老的布局适配机制 一、什么是「Window Insets」WindowInsets 表示的是 系统窗口(System Windows)占用的区域信息,比如:区域示例说明状态栏(Status bar)屏幕上方时间/信号栏内容不要绘制到这里导航栏 API键盘遮挡输入框需要监听键盘高度直接通过 Insets 获取 IME 区域刘海屏、圆角屏适配手动判断 cutout 区域通过 DisplayCutoutInsets 自动提供多窗口 / 分屏旧 API (view) { v, insets -> val systemBarsInsets = insets.getInsets(WindowInsetsCompat.Type.systemBars() 小结概念含义WindowInsets系统窗口占用的安全区域信息用途让布局避开状态栏、导航栏、键盘、刘海等区域解决问题统一适配、自动避让、兼容多形态设备Android 15 特点完全过渡到 Insets
(); blocks_scaled_with_insets->updateWithBatchNode(batchNode_scaled_with_insets, Rect(0, 0, , 96 * 2.5)); blocks_scaled_with_insets->setPosition(Point(x, y)); this->addChild(blocks_scaled_with_insets ->setContentSize(Size(96 * 4.5, 96 * 2.5)); blocks_scaled_with_insets->setPosition(Point(x, ->setContentSize(Size(14 * 16, 10 * 16)); blocks_scaled_with_insets->setPosition(Point(x , y (32); blocks_scaled_with_insets->setInsetRight(32); blocks_scaled_with_insets->setPreferredSize
----
在 Container 中 , 定义了一个 getInsets 函数 , 在该函数的文档中可以看到 , Insets 是 Container 容器的空白边框 , 对于不同的组件 , Insets 的表现不同 , 针对 Frame 窗口容器 , Insets 对象的 top 就是 Frame 窗口的顶部空白 , 也就是标题栏空白 , 下面着重分析 Insets 类 ;
/** Insets getInsets() {
return insets();
}
分析 Insets 类的原型 , 阅读下面的文档可知 , Insets 是 Container , Insets#top 就是标题栏高度 ;
package java.awt;
/**
* An Insets object is a representation of Insets 数据 :
java.awt.Insets[top=31,left=8,bottom=8,right=8]
DragLayer.java根布局,负责 Insets 应用。 四、你要看的具体函数(最相关的)可以从下面几个函数入手调试: QuickstepLauncher.java @Override public void onInsetsChanged(Insets insets ) { mDragLayer.setInsets(insets); // ✅ 在这里加日志 Log.d("LauncherInsets", "Insets changed: " + insets); } DragLayer.java @Override public WindowInsets onApplyWindowInsets(WindowInsets insets) { Log.d("DragLayer", "onApplyWindowInsets: " + insets); return super.onApplyWindowInsets(insets
边衬区 (Insets) 不少 Android 开发者看到边衬区 (insets) 往往会退避三舍,这个可能来源自他们在 Android Lollipop 时代试图在状态栏后面绘制 UI 的经历,而这个经历并不那么令人愉悦 可点击区域 方法: getTappableElementInsets() 接下来是 Android 10 中新增的可点击区域 insets。它们与上面的系统窗口区域 insets 非常相似。 从实用的角度出发,在日常开发中我建议使用系统窗口区域 insets,它可以更好地满足几乎所有需要使用可点击区域 insets 的用例。 v.updatePadding(bottom = insets.systemWindowInsets.bottom) // Return the insets so that they keep = v.paddingBottom + insets.systemWindowInsets.bottom) insets } 请不要在计算边距时使用自加运算 (+=)。
int top = insets.getInt("top"); int right = insets.getInt("right"); int bottom _androidStretch(imagePath, finalOptions.insets); } else { // H5 fallback方案 return this. _h5Fallback(imagePath, finalOptions.insets); } }, _iosStretch(imagePath, insets) { // 调用iOS 原生模块 }, _androidStretch(imagePath, insets) { // 调用Android原生模块 }, _h5Fallback(imagePath, insets = prediction.dataSync(); return { left: insets[0], top: insets[1], right: insets[2], bottom
= null), assert(insets ! = null); final BorderSide borderSide; final EdgeInsetsGeometry insets; @override Decoration : EdgeInsetsGeometry.lerp(a.insets, insets, t), ); } return super.lerpFrom(a, t); } : EdgeInsetsGeometry.lerp(insets, b.insets, t), ); } return super.lerpTo(b, t); } => decoration.insets; Rect _indicatorRectFor(Rect rect, TextDirection textDirection) { assert
textRect(forBounds bounds: CGRect, limitedToNumberOfLines numberOfLines: Int) -> CGRect { let insets = self.padding var rect = super.textRect(forBounds:bounds.inset(by: insets), limitedToNumberOfLines : numberOfLines) rect.origin.x -= insets.left rect.origin.y -= insets.top rect.size.width += (insets.left + insets.right) rect.size.height += (insets.top + insets.bottom) return
removeTarget:nil action:nil forControlEvents:UIControlEventTouchUpInside]; 第九、 设置按钮内部图片间距和标题间距 UIEdgeInsets insets ; // 设置按钮内部图片间距 insets.top = insets.bottom = insets.right = insets.left = 10; bt.contentEdgeInsets = insets; bt.titleEdgeInsets = insets; // 标题间距
this.weighty = weighty; return this; } public GBC setInsets(int distance) { this.insets = new Insets(distance, distance, distance, distance); return this; } public GBC setInsets (int top, int left, int bottom, int right) { this.insets = new Insets(top, left, bottom, right
() + insets.top + insets.bottom; } layout 然后介绍layout方法,和自定义ViewGroup一样,LayoutManager完成ItemView的测量后就是布局了 = ((LayoutParams) child.getLayoutParams()).mDecorInsets; child.layout(left + insets.left, top + insets.top, right - insets.right, bottom - insets.bottom); } public void layoutDecoratedWithMargins = lp.mDecorInsets; child.layout(left + insets.left + lp.leftMargin, top + insets.top + lp.topMargin , right - insets.right - lp.rightMargin, bottom - insets.bottom - lp.bottomMargin
val sysWindow = insets.systemWindowInsets + val sysWindow = insets.getInsets(Type.systemBars() or Type.ime()) - val stable = insets.stableInsets + val stable = insets.getInsetsIgnoringVisibility (Type.systemBars()) - val systemGestures = insets.systemGestureInsets + val systemGestures = insets.getInsets 同样地,如果我们想查出高度,我们也可以通过相同的方法实现: val insets = ViewCompat.getRootWindowInsets(view) val imeVisible = insets.isVisible ,并且使用同样的函数: ViewCompat.setOnApplyWindowInsetsListener(view) { v, insets -> val imeVisible = insets.isVisible
this.weighty = weighty; return this; } public GBC setInsets(int distance) { this.insets = new Insets(distance, distance, distance, distance); return this; } public GBC setInsets (int top, int left, int bottom, int right) { this.insets = new Insets(top, left, bottom, right
WindowInsets 分发机制是「懒惰式且缺乏自动性」的 —— 依赖 ViewRootImpl.performTraversals() 调用链的主动触发,无法在布局未完成的场景中保证完整、时机正确地分发 Insets 深入剖析:WindowInsets 的传递机制演化 Android版本 WindowInsets分发机制 是否自动触发重新分发 是否支持动态监听Insets变化 Android 4.4 (API 19) layout 流程中调用 dispatchApplyWindowInsets() 才有效; 一旦 View 是 GONE 或尺寸为 0,在 performTraversals() 过程中它不会参与 insets 分发; 导致后续将 View 设置为 VISIBLE 时,它不会自动收到 Insets,即使它应该需要。 hide() // 强制刷新 Insets 和 Layout window.decorView.requestApplyInsets() }}
原文地址:Windows Insets + Fragment Transitions: A tale of woe 原文作者:Chris Banes 译文出自:掘金翻译计划 本文永久链接:github.com fragment_container.setOnApplyWindowInsetsListener { view, insets -> var consumed = false (view as (insets) // If the child consumed the insets, record it if (childResult.isConsumed) { consumed = true } } // If any of the children consumed the insets, return // an appropriate value if ( consumed) insets.consumeSystemWindowInsets() else insets } 在我们应用这个修复之后,这两个 fragment 都会收到 WindowInsets
--关键点1--> insets = updateColorViews(insets, true /* animate */); insets = updateStatusGuard(insets --关键点2 重新计算消费结果----> if (insets ! = null) { insets = insets.replaceSystemWindowInsets( insets.getSystemWindowInsetLeft (), insets.getSystemWindowInsetTop(), insets.getSystemWindowInsetRight return insets; } 在6.0对应的源码中,DecorView自身主要对NavigationBar那部分的Insets做了处理,并没有对状态栏做处理。
javax.swing.JScrollPane; import java.awt.GridBagConstraints; import javax.swing.JButton; import java.awt.Insets = new Insets(0, 0, 5, 0); gbc_scrollPane.fill = GridBagConstraints.BOTH; gbc_scrollPane.gridx = new Insets(0, 0, 5, 0); gbc_button.gridx = 0; gbc_button.gridy = 1; contentPane.add ); GridBagConstraints gbc_scrollPane_1 = new GridBagConstraints(); gbc_scrollPane_1.insets = new Insets(0, 0, 5, 0); gbc_scrollPane_1.fill = GridBagConstraints.BOTH; gbc_scrollPane
GridBagConstraints.NORTH; // 当组件没有空间大时,使组件处在北部 fill = GridBagConstraints.BOTH; // 当格子有剩余空间时,填充空间 insert = new Insets gridy, gridwidth, gridheight, weightx, weighty, anchor, fill, insert, ipadx, ipady); gridBagConstraints.insets = new java.awt.Insets(4, 4, 0, 4);//设置组件的位置 gridx,gridy 设置组件所处行与列的起始坐标。 若一个组件的尺寸为30*10像素,ipadx=2,ipady=3,则单元格内的组件最小尺寸为34*16像素 insets Insets是AWT里面一个类的名字,它的用途是用来定义组件容器周围的空间大小, 其中带有四个参数: Insets(第一个参数,第二个参数,第三个参数,第四个参数 ) Insets(上,左,下,右) insets用来设置一个组件和其他的组件之间的距离的。
weightx,weighty: 是否拉伸(0不拉伸,1拉伸) insets: 设置元素的位置,类似html的margin,只是顺序有点不一样,依次是上,左,下,右。 java.awt.Insets.Insets(int top, int left, int bottom, int right) fill: 当某个组件未能填满单元格时,可由此属性设置横向、纵向或双向填满