gpt4 book ai didi

objective-c - 以编程方式设置后 NSView 框架恢复

转载 作者:搜寻专家 更新时间:2023-10-30 20:00:07 25 4
gpt4 key购买 nike

所以我有一个在 IB 中设置的 View ,我需要以编程方式更改框架。出于某种原因,框架在我设置后一直恢复到其 IB 位置。我将 NSView 子类化并在 -setFrame:(NSRect)frameRect 方法中记录了框架,看起来 -setFrame: 被调用了两次——一次是在我设置它时(它记录新值的地方)和一次恢复时(它记录 IB 值的地方)。我似乎无法提炼出问题的根源,因为在某些情况下(例如,如果我有一个专门用于设置它的 NSButton 或有一个计时器设置框架)它工作得很好,但如果我有 -setFrame : 调用我的其他代码,它总是会恢复。

编辑:

这是一个显示问题的简单示例(IB 中的原始框架是 {{20, 118}, {48, 48}}):

AppDelegate.m:

#import "AppDelegate.h"

@implementation AppDelegate

- (void)awakeFromNib{
[self.button setFrame:NSMakeRect(50, 10, 100, 100)];
}

@end

日志:

2014-02-18 18:01:40.206 WHS-ChangingFrameTest[15210:303] Frame: {{50, 10}, {100, 100}}
2014-02-18 18:01:41.223 WHS-ChangingFrameTest[15210:303] Frame: {{20, 118}, {48, 48}}

编辑#2:

我编辑框架时的调用堆栈(来自原始应用):

0   MyApp                 0x000000010000203c -[FrameLogProgressIndicator setFrame:] + 284
1 MyApp 0x000000010001c994 -[SubjectViewController updateTableViewHeight] + 1284
2 MyApp 0x000000010001c468 -[SubjectViewController updateUI] + 4664
3 MyApp 0x0000000100012f2f -[TabMenuViewController updateDisplayingBlock:] + 975
4 MyApp 0x0000000100010c59 -[TabMenuViewController switchBlockFromDaySchedulePopover:] + 873
5 AppKit 0x00007fff82eea959 -[NSApplication sendAction:to:from:] + 342
6 AppKit 0x00007fff82eea7b7 -[NSControl sendAction:to:] + 85
7 AppKit 0x00007fff82eea6eb -[NSCell _sendActionFrom:] + 138
8 AppKit 0x00007fff82ee8bd3 -[NSCell trackMouse:inRect:ofView:untilMouseUp:] + 1855
9 AppKit 0x00007fff82ee8421 -[NSButtonCell trackMouse:inRect:ofView:untilMouseUp:] + 504
10 AppKit 0x00007fff82ee7b9c -[NSControl mouseDown:] + 820
11 AppKit 0x00007fff82edf50e -[NSWindow sendEvent:] + 6853
12 AppKit 0x00007fff82edb644 -[NSApplication sendEvent:] + 5761
13 AppKit 0x00007fff82df121a -[NSApplication run] + 636
14 AppKit 0x00007fff82d95bd6 NSApplicationMain + 869
15 MyApp 0x00000001000020a2 main + 34
16 libdyld.dylib 0x00007fff8152a7e1 start + 0
17 ??? 0x0000000000000003 0x0 + 3
)

框架恢复时的调用堆栈:

0   MyApp                 0x000000010000203c -[FrameLogProgressIndicator setFrame:] + 284
1 AppKit 0x00007fff82e21e77 -[NSView resizeWithOldSuperviewSize:] + 659
2 AppKit 0x00007fff82e21307 -[NSView resizeSubviewsWithOldSize:] + 318
3 AppKit 0x00007fff82f08399 NSViewLevelLayout + 44
4 AppKit 0x00007fff82f07e65 -[NSView _layoutSubtreeHeedingRecursionGuard:] + 112
5 CoreFoundation 0x00007fff84b524a6 __NSArrayEnumerate + 582
6 AppKit 0x00007fff82f07fc6 -[NSView _layoutSubtreeHeedingRecursionGuard:] + 465
7 CoreFoundation 0x00007fff84b524a6 __NSArrayEnumerate + 582
8 AppKit 0x00007fff82f07fc6 -[NSView _layoutSubtreeHeedingRecursionGuard:] + 465
9 CoreFoundation 0x00007fff84b524a6 __NSArrayEnumerate + 582
10 AppKit 0x00007fff82f07fc6 -[NSView _layoutSubtreeHeedingRecursionGuard:] + 465
11 CoreFoundation 0x00007fff84b524a6 __NSArrayEnumerate + 582
12 AppKit 0x00007fff82f07fc6 -[NSView _layoutSubtreeHeedingRecursionGuard:] + 465
13 AppKit 0x00007fff82f07cfe -[NSView layoutSubtreeIfNeeded] + 615
14 AppKit 0x00007fff82f034ac -[NSWindow(NSConstraintBasedLayout) layoutIfNeeded] + 201
15 AppKit 0x00007fff82dfd0a8 _handleWindowNeedsDisplayOrLayoutOrUpdateConstraints + 446
16 AppKit 0x00007fff833c8901 __83-[NSWindow _postWindowNeedsDisplayOrLayoutOrUpdateConstraintsUnlessPostingDisabled]_block_invoke_01208 + 46
17 CoreFoundation 0x00007fff84b20417 __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__ + 23
18 CoreFoundation 0x00007fff84b20381 __CFRunLoopDoObservers + 369
19 CoreFoundation 0x00007fff84afb7b8 __CFRunLoopRun + 728
20 CoreFoundation 0x00007fff84afb0e2 CFRunLoopRunSpecific + 290
21 HIToolbox 0x00007fff8231aeb4 RunCurrentEventLoopInMode + 209
22 HIToolbox 0x00007fff8231ab94 ReceiveNextEventCommon + 166
23 HIToolbox 0x00007fff8231aae3 BlockUntilNextEventMatchingListInMode + 62
24 AppKit 0x00007fff82dfa533 _DPSNextEvent + 685
25 AppKit 0x00007fff82df9df2 -[NSApplication nextEventMatchingMask:untilDate:inMode:dequeue:] + 128
26 AppKit 0x00007fff82df11a3 -[NSApplication run] + 517
27 AppKit 0x00007fff82d95bd6 NSApplicationMain + 869
28 MyApp 0x00000001000020a2 main + 34
29 libdyld.dylib 0x00007fff8152a7e1 start + 0
30 ??? 0x0000000000000003 0x0 + 3
)

让我知道是否需要发布堆栈中使用的方法的代码以使其有用。 (抱歉,我以前从未真正处理过这些东西)

最佳答案

替换 resizeWithOldSuperviewSize: 内容的替代方法是通知自动布局系统您不希望调整 NSView 的大小。这将使您的 NSView 保持在您以编程方式指定的原点,从而保持您对界面构建器的覆盖不变。你这样做:

[<id> setAutoresizingMask:NSViewNotSizable];
[<id> setTranslatesAutoresizingMaskIntoConstraints:YES];

哪里<id>将是您的 NSView 的实例,即 self.button .第一行说明 View 不可调整大小,而第二行说明掩码应被自动布局系统视为约束。您修改后的 AppDelegate.m 将是:

#import "AppDelegate.h"

@implementation AppDelegate

- (void)awakeFromNib{
[self.button setAutoresizingMask:NSViewNotSizable];
[self.button setTranslatesAutoresizingMaskIntoConstraints:YES];
[self.button setFrame:NSMakeRect(50, 10, 100, 100)];
}

@end

更新:如果您将此方法与您计划设置的 NSView 一起使用 hidden ,自动布局系统仍然会在调整框架的 super View /窗口大小时考虑隐藏 NSView 的框架。这意味着如果隐藏的 NSView 在调整大小后位于父 View 的可见区域之外,自动布局系统将阻止父 View 正确调整大小,而是强制父 View 框架包围隐藏的 NSView。

这个问题的一个简单的解决方案是在设置 hidden:YES 之后将 NSView 的宽度和高度设置为零。并在设置 hidden:NO 之前恢复宽度和高度.例如,在您的代码中的某个时刻使用您的 NSView self.button :

...
[self.button setHidden:YES];
[self.button setFrameSize:NSZeroSize];
...

及以后:

...
[self.button setFrameSize:NSMakeSize(160, 90)];
[self.button setHidden:NO];
...

但是,如果您在 NSView 上设置了宽度/高度自动布局约束(以编程方式或通过 Interface Builder),这些更改可能会引发如下警告:

Unable to simultaneously satisfy constraints:
(
"<NSLayoutConstraint:0x608000082990 H:[NSButton:0x6080001200a0(100)]>",
"<NSAutoresizingMaskLayoutConstraint:0x60800008bae0 h=--& v=--& H:[NSButton:0x6080001200a0(0)]>"
)

Will attempt to recover by breaking constraint
<NSLayoutConstraint:0x608000082990 H:[NSButton:0x6080001200a0(100)]>

您可以忽略这些警告,将约束优先级降低到一个较低的数字,将约束从 = 更改为 ,或者您可以简单地 setTranslatesAutoresizingMaskIntoConstraints:NO在隐藏 NSView 并将其设置为 YES 之前在取消隐藏 NSView 之前:

...
[self.button setTranslatesAutoresizingMaskIntoConstraints:NO];
[self.button setHidden:YES];
...

当我们取消隐藏 NSView 时:

...
[self.button setTranslatesAutoresizingMaskIntoConstraints:YES];
[self.button setHidden:NO];
...

您还可以通过子类化 NSView 并覆盖 setHidden: 来自动执行此操作(注意 ! ):

- (void)setHidden:(BOOL)hidden {
[self setTranslatesAutoresizingMaskIntoConstraints:!hidden];
[super setHidden:hidden];
}

然后您可以简单地调用 [self.button setHidden:YES];[self.button setHidden:NO];覆盖的方法将处理所有事情。

关于objective-c - 以编程方式设置后 NSView 框架恢复,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21867867/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com