在自动布局世界中正确调整 NSWindow 大小

2024-04-08

我在使用自动布局滚动视图调整垂直窗口大小时遇到​​问题。

我想要的是

我想尽可能地复制我的应用程序当前的窗口大小调整行为。窗口的宽度是灵活的,但窗口的高度通常应跟踪内容的高度。具体来说:

  1. 通常,窗口会自动调整其高度以精确调整
    匹配其内容(#2 除外)。
  2. 用户可以选择手动调整窗口大小,使其小于其实际大小 内容,在这种情况下,嵌入的滚动视图将滚动 内容。一旦变短,窗口就会保持该高度,直到手动 调整大小或内容再次变得等于或小于窗口。
  3. 如果内容增长到窗口底部 碰撞到停靠栏或屏幕边界,窗口的高度被固定 到那个高度,就像用户调整了它的大小一样。

我有什么

我创建了一个带有一组代表性子视图的窗口,这些子视图模仿了我的应用程序的基本需求。窗口的层次结构很简单:

Window
    NSView (contentView)
        NSScrollView
            NSClipView (NSScrollView.contentView)
                NSView (NSScrollView.documentView)
                    A bunch of standard and custom subviews with constraints

您可以在此处下载测试项目(macOS 10.12/Xcode 8):http://mbx.cm/t/4FUGY http://mbx.cm/t/4FUGY

我组织了各种子视图,使它们具有灵活的宽度,但约束恰好定义了一种可能的高度。父滚动视图填充窗口的内容视图。

自动布局的东西效果很好。窗口会自动调整大小以匹配内容的大小。如果内容的高度发生变化,窗口的高度也会发生变化以匹配。惊人的。

我无法去上班的事情

我没有运气让 NSWindow 让我手动调整其高度。调整大小指示器(将鼠标悬停在边缘上时)显示我可以更改窗口的宽度,但不能更改其高度。

我最初想“哦,这一定是滚动视图之一中的压缩阻力优先级。”但我找不到抗压性或拥抱优先级的组合来改变这种行为。我尝试过设置滚动视图本身和文档视图的优先级(这对我来说没有意义,但我还是尝试了)。我尝试了我能想到的每一种组合值 749、499、49 和 1。

我搜索了似乎已发布的每个问题,但大多数发布的问题似乎都在解决不同的问题。

我添加了一个“转储”按钮来记录垂直约束。列出的所有内容似乎都符合预期,除了少数我不理解的 NSAutoresizingMaskLayoutConstraint 对象。但是,这些似乎是文档视图和剪辑视图之间的约束,因此我假设它们是自动创建的并且不是问题的一部分。

<NSLayoutConstraint:0x608000082580 PartBoxView:0x608000140840'Part B'.height == 96   (active)>
<NSLayoutConstraint:0x608000083de0 V:[PartBoxView:0x608000140840'Part B']-(0)-|   (active, names: '|':NSView:0x6080001212c0 )>
<NSLayoutConstraint:0x608000083e80 V:[PartBoxView:0x608000140370'Part A']-(NSSpace(8))-[PartBoxView:0x608000140840'Part B']   (active)>
<NSLayoutConstraint:0x608000082da0 V:|-(0)-[NSScrollView:0x6080001c10e0]   (active, names: '|':NSView:0x608000121400 )>
<NSLayoutConstraint:0x608000083430 V:|-(0)-[NSView:0x6080001212c0]   (active, names: '|':NSClipView:0x10040e2a0 )>
<NSLayoutConstraint:0x608000081e00 V:[NSScrollView:0x6080001c10e0]-(0)-|   (active, names: '|':NSView:0x608000121400 )>
<NSAutoresizingMaskLayoutConstraint:0x650000082b20 h=-&- v=-&- NSView:0x608000121400.minY == 0   (active, names: '|':NSThemeFrame:0x102504ea0'Window' )>
<NSAutoresizingMaskLayoutConstraint:0x6500000823f0 h=-&- v=-&- NSClipView:0x10040e2a0.minY == 1   (active, names: '|':NSScrollView:0x6080001c10e0 )>
<NSLayoutConstraint:0x608000083480 V:[NSView:0x6080001212c0]-(0)-|   (active, names: '|':NSClipView:0x10040e2a0 )>
<NSAutoresizingMaskLayoutConstraint:0x650000082440 h=-&- v=-&- V:[NSClipView:0x10040e2a0]-(1)-|   (active, names: '|':NSScrollView:0x6080001c10e0 )>
<NSLayoutConstraint:0x608000083d40 V:|-(0)-[PartBoxView:0x608000140370'Part A']   (active, names: '|':NSView:0x6080001212c0 )>
<NSLayoutConstraint:0x608000083c50 V:[NSImageView:0x608000161bc0]-(20)-|   (active, names: '|':PartBoxView:0x608000140370'Part A' )>
<NSLayoutConstraint:0x608000083bb0 V:|-(20)-[NSImageView:0x608000161bc0]   (active, names: '|':PartBoxView:0x608000140370'Part A' )>
<NSLayoutConstraint:0x608000083660 NSImageView:0x608000161bc0.height == 64   (active)>

我希望有自动布局经验的人可以告诉我如何让#2 工作。我很确定#3 需要一些自定义代码,但#2 是最大的障碍。

的背景

我正在对我的应用程序进行重大改进。这是一个相当大的应用程序,因此我首先创建一组测试项目来测试一些新的 UI 和技术。

第一项重大任务是将所有内容转换为自动布局。大部分看起来都相当顺利,我期待着自动布局的众多好处中的一些。


没有完全自动化的方法来实现你的目标#2。你想要两种不同的模式。在一种模式下,窗口总是足够大以容纳内容。如果它增长,窗口就会增长;如果它缩小,窗口就会缩小。在另一种模式下,允许窗口小于适合内容所需的大小,因为用户以这种方式调整了窗口大小。在这种情况下,如果内容增长,窗口不会增长;如果缩小,窗口不会缩小,除非内容变得足够小以使其全部适合,然后切换回第一种模式。

自动布局实际上并不会执行这样的模式,至少不会自动执行。您必须检测模式更改并以编程方式修改约束以实现两种行为模式。

显然,您已经在文档视图和剪辑视图之间创建了约束,以保持它们的顶部和底部重合。这实际上迫使剪辑视图和滚动视图与文档视图一样大。滚动视图永远不会滚动,因为它永远不会太小而无法显示所有内容。

我认为您可能需要对底部间距有两个约束。一个约束是所需优先级 (1000) 的不等式。您想要表达剪辑视图永远不应该大于文档视图。文档视图的底部可以大于或等于剪辑视图的底部,但绝不能小于。

第二个底部间距约束将是一个等式(与现在一样,常数为 0),但优先级略小于NSLayoutPriorityWindowSizeStayPut(500)。这表示您希望剪辑视图和滚动视图足够大以适合内容,除非这会强制窗口增大或阻止用户缩小它。

问题是,如果窗口足够大以容纳内容,然后内容增长,则不会强制窗口增长。我所描述的实现了第二种模式。

您可以尝试通过将第二个约束的优先级设置得更高来实现第一种模式。那么问题是用户将不被允许调整窗口大小。你又回到了现在的状态。

我认为您需要做的是通过观察文档视图来注意内容何时调整大小NSViewFrameDidChangeNotification。请务必通过设置其来告诉视图发布该内容postsFrameChangedNotifications属性为真。当框架发生变化时,如果您认为应该处于第一种模式,请将第二个约束的优先级设置得更高,调用-layoutIfNeeded窗口上,然后将优先级设置回原来的位置。我认为您可能需要将优先级设置推迟到事件循环的下一轮,因为不清楚您是否会在剪辑视图之后收到通知,因此也许可以使用 GCD 来安排它。

那么,你怎么知道你应该处于哪种模式呢?我不太确定。我think它将为窗口委托(通常是其控制器)实现-windowDidEndLiveResize:了解用户何时完成调整窗口大小。我认为用户调整它的大小将是实时调整大小,而以编程方式调整它的大小或自动布局调整它的大小则不会。

如果是用户调整了窗口大小,则您需要知道用户是否放大了窗口以便所有内容都适合,或者用户是否将窗口大小调整得更小。为此,您可以将文档视图边界的高度与剪辑视图的边界进行比较documentVisibleRect.

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

在自动布局世界中正确调整 NSWindow 大小 的相关文章

随机推荐

  • Youtube iOS 播放器帮助程序库无法正常工作

    我尝试实现 youtube ios player helper 库来在我的应用程序中播放视频 我可以准备好播放器并加载视频 并且可以显示起始缩略图 但是 当我尝试播放视频时 却收到以下错误消息 SendDelegateMessage NSI
  • 通过尾指针添加到链表,无需 3 级间接

    我正在开发一个需要实现链表的项目 在开始这个项目之前 我正在回顾创建链表的经典方法 我意识到过去我一直通过head遍历列表直到到达空指针的指针 我发现没有必要这样做 并以涉及的方式实现它tail指针 但我能想到的唯一方法是涉及三重指针或全局
  • Jquery Multiselect:如何知道选择/取消选择哪个值

    我有多选下拉菜单 每当有选择或取消选择时 我都需要获取该值 我正在使用更改事件 但很难确定选择 取消选择了哪个选项 all options var all multiple each function i selected all i se
  • 如何在 C# 中附加 xml 文件?

    我正在为一个简单进程添加跟踪 以进行审计 我将其构建为 exe 并在调度程序中设置为每 10 分钟运行一次 我想让应用程序将结果输出到 xml 文件中 如果文件存在 则打开并向其追加数据 如果不存在 我想创建一个新的 xml 文件 该文件将
  • C/C++ 中的动态位向量

    我正在寻找一个可以使用的现成的 C 或 C 动态位向量 不幸的是 由于各种原因 我目前无法使用 BoostT 库 std bitvector 看起来很有希望 但它是模板化的 所以我无法动态设置位向量的长度 有人可以建议吗 谢谢 您不必仅仅为
  • 安装SSDT(SQL Server数据工具)时出错

    我在安装 SQL Server Data Tools for Visual Studio 2017 过程中遇到问题 我收到以下错误 已翻译 The requested meta file operation is not supported
  • SwiftUI:两个并排列表和一个导航视图出现意外行为

    我的屏幕有两个List并排 在一个NavigationView 布局渲染正确 我可以独立滚动两个列表 问题是 当我滚动第一个列表时 它位于导航栏后面 而没有触发对其应用背景颜色的效果 下面的 gif 展示了正在发生的事情 这是我用于此视图的
  • request.getSession() 在 sendRedirect() 之后创建新会话

    我们正在开发旅行应用程序 通过这个航班 可以预订酒店 巴士票 它是基于产品的应用程序 我们有近 25 个客户 3 个客户正在使用 其余仍在开发中 我们为所有客户维护一台服务器 一台服务器 应用程序 多个客户端是我的应用程序中的伟大成就 但问
  • 使用 jq 将 JSON 对象转换为 Prometheus 指标格式

    考虑一个 JSON 对象 例如 foo 42 baz 12 bar label1 value1 12 34 建造者jq https github com stedolan jq使用一些数据源 实际的键名称及其数量可能会有所不同 但结果将始终
  • HAL_Delay() 陷入无限循环

    我被 HAL Delay 函数困住了 当我调用此函数 HAL Delay 时 控制陷入无限循环 在寻找问题的过程中 我发现了这个 http www openstm32 org forumthread2145 threadId2146 htt
  • 在Python中的同一个图上绘制多个位置的年度数据[重复]

    这个问题在这里已经有答案了 我有几个站 20 年的数据框 我想以某种方式绘制它 x 轴是年份 y 轴是观测值 线条的颜色显示位置 station year observations 0 3939 2000 0 346518 1 3939 2
  • 通过 UDF 获取 Google 搜索第一个结果[重复]

    这个问题在这里已经有答案了 Santosh 对以下问题有一个很棒的答案 vba 代码 link https stackoverflow com questions 17495644 using vba in excel to google
  • 将 .NET 事件公开给 COM?

    我一直在尝试向 VBA 客户端公开并触发事件 到目前为止 在 VBA 客户端 事件已公开 并且我看到方法事件处理方法已添加到我的模块类中 但是 VBA 事件处理方法不会触发 由于某种原因 调试时事件为空 同步修改我的代码也没有帮助 作为记录
  • 文件锁如何工作?

    我一直在尝试使用FileLock获得对文件的独占访问权限 以便 删除它 重命名它 写信给它 因为在 Windows 上 至少 您似乎无法删除 重命名或写入已在使用的文件 我写的代码看起来像这样 import java io File imp
  • Spring security 已登录用户的重定向问题

    在使用我的基于 GWT 的 Web 应用程序实现 Spring Security 时 我找到 一切都按预期正常工作 除了以下事实 我打开了 login jsp 并给出了有效的用户登录凭据 提交后 成功重定向到主页 现在 当我在地址栏中编辑
  • 电子关闭按钮不起作用

    我正在尝试使用 Electron 以前称为 Atom Shell 创建一个应用程序 该应用程序包装了 AngularJS 应用程序 并与在 Node js 中创建的端点交互以编辑和保存 HTML 内容 我能够毫无问题地创建应用程序 当我尝试
  • glEnableClientState 和 glEnableVertexAttribArray

    后者是否贬低前者 我正在编写希望在着色器 2 0 硬件上工作的代码 但我想使用更新的编程约定 例如 VAO 所以我一直在使用glVertexAttribPointer函数而不是glVertexPointer glNormalPointer
  • 强制 ListView 的 onSizeChanged

    我有一个列表视图 它动态分配不同的数据集 这很好用 我还使 fastScrollEnabled 为 true 为了更新sectionIndexer 我需要调用 list setFastScrollEnabled false list set
  • 如何禁用 Jupyter 笔记本会话的密码请求?

    多年来我一直使用以下命令启动 Jupyter Notebook jupyter notebook port 7000 no browser no mathjax 当我尝试在浏览器上打开 jupyter 时 它会要求我输入密码 即使我以前从未
  • 在自动布局世界中正确调整 NSWindow 大小

    我在使用自动布局滚动视图调整垂直窗口大小时遇到 问题 我想要的是 我想尽可能地复制我的应用程序当前的窗口大小调整行为 窗口的宽度是灵活的 但窗口的高度通常应跟踪内容的高度 具体来说 通常 窗口会自动调整其高度以精确调整匹配其内容 2 除外