2014-02-18 27 views
3

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

编辑:

这是一个简单的例子,示出了该问题(在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 
) 

让我知道是否需要从堆栈中使用的方法发布代码,以便有用。 (对不起,我从来没有真正处理了这个东西之前)

+0

请发布一个调用堆栈,其中setFrame被调用错误的数据 – Avt

+0

大概你是从错误的地方调用你的帧更新。但是你没有向我提供额外的信息。所以我不能帮你。 – Avt

+0

改变帧的含义是什么?它的大小,位置? -1 –

回答

1

所以我设法通过继承他们停下来的意见调整大小和压倒一切的-resizeWithOldSuperviewSize:只是什么也不做,就像这样:

- (void)resizeWithOldSuperviewSize:(NSSize)oldSize {}; 
2

从awakeFromNib描述:

由于其对象从归档中实例化的顺序是不能保证,你的初始化方法应该不发送消息给其他对象在层次结构中。到其他对象的消息可以从awakeFromNib方法中安全地发送。 通常,您需要为需要额外设置的对象实现awakeFromNib,而这些对象在设计时无法完成。例如,您可以使用此方法自定义任何控件的默认配置,以匹配用户首选项或其他控件中的值。您也可以使用它将单个控件恢复到应用程序的某个以前的状态。

我不是100%肯定,但我强烈建议移动

[self.button setFrame:NSMakeRect(50, 10, 100, 100)]; 

- (void)viewDidLoad 

方法。你也不应该忘记调用super的方法 - 在某些情况下,它可能很重要。因此,最终的代码应该是这样的:

@implementation AppDelegate 

- (void)awakeFromNib{ 
    [super awakeFromNib]; 
    ... non GUI initialization 
} 

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

@end 

UPDATE: 感谢电话卡。看起来你的观点是自动化的。您应该检查autoresizingMask自动布局约束

+0

谢谢,但我不认为这解决了我的问题,因为在更大的应用程序中,我正在开发返回,即使在'-setFrame:'从'-awakeFromNib'之外的地方调用时也会发生。我用我原来的应用程序的调用堆栈更新了我的问题。 –

+0

感谢致电卡住。看起来你的观点是自动化的。你应该检查autoresizingMask和自动布局的约束条件 – Avt

+0

我试着将autoreziseMask设置为NSViewNotSizeable(这似乎没有效果)并且摆脱了所有约束条件(它将初始帧设置为与IB完全不同的东西,但是我还试着将superview的'-setAuotresizesSubviews:'设置为NO,这也没有做任何事情。你有什么想法可以阻止视图的autoresizing?autoresizingMask返回12,唯一的约束是:

3

的替代更换内容resizeWithOldSuperviewSize:是通知自动布局系统,你不希望你的NSView被调整大小。这将使您的NSView保持在您以编程方式指定的原点,从而保持您对接口生成器的覆盖不变。

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

其中<id>将是你的NSView的实例,即self.button:您可以通过做到这一点。第一行指出视图不是很大,而第二行指出掩码应该被自动布局系统视为约束。然后,您的修订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 

更新: 如果您使用此方法,你打算设置hidden一个的NSView,自动布局系统将仍然需要隐藏的框架调整框架的超级视图/窗口大小时考虑NSView。这意味着如果隐藏的NSView在调整大小之后会在超级视图的可见区域之外,自动布局系统将阻止超级视图正确调整大小,而是强制超级视图框架将隐藏的NSView包围起来。

一种Na ï已经解决了这个问题是设置hidden:YES和设置hidden:NO之前恢复的宽度和高度后到的NSView的宽度和高度设置为零。例如,在代码中的某个点使用的NSView self.button

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

及更高版本:

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

不过,如果你对一个NSView设置(以编程方式或宽度/高度自动布局限制通过界面生成器),这些变化可能会引发类似的警告:

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)]> 

您可以忽略这些警告,约束优先级降低到低号,从=约束更改为,或交替您可以隐藏的NSView,并将其设置为YES之前之前只是setTranslatesAutoresizingMaskIntoConstraints:NO来取消隐藏所的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];,并且重写的方法将处理所有内容。