防止视图布局子视图
Posted
技术标签:
【中文标题】防止视图布局子视图【英文标题】:Prevent view to layout Subviews 【发布时间】:2013-07-16 09:51:22 【问题描述】:我在 .xib 文件中设计了一个 UIViewController。它使用自动布局。
我在其中有一个 UISlider,当它的值更改时它会更改 UILabel 的文本:我已将发送的事件“值更改”链接到我的头文件,然后在我的控制器的 .m 文件中实现该功能。此方法仅根据滑块的值更改标签的文本。
当视图出现时,滑块不显示(设置在屏幕之外)。我使用动画将其呈现在视图上。 问题是当我更改滑块的值时,它会自动调用
-(void)viewDidLayoutSubviews
不幸的是,它将我的控制器视图的所有子视图重置为其原始位置。
如何呈现滑块以“破坏”实际布局。
编辑
我的滑块在界面生成器中的连接:
以及相关函数的代码:
- (IBAction)sliderDureeValueChanged:(id)sender
dureeMois = (int) sliderDuree.value;
if (sliderDuree.maximumValue == sliderDuree.value)
[lblDuree setText:@"Max"];
else if (sliderDuree.minimumValue == sliderDuree.value)
[lblDuree setText:@"Min"];
else
[lblDuree setText:[NSString stringWithFormat:@"%d month",dureeMois]
EDIT2
这是使用滑块调用时在viewDidLayoutSubviews
中使用[NSThread callStackSymbols]
获得的堆栈。
2013-07-16 16:39:47.420 MyApp[2363:907] Stack trace : (
0 MyApp 0x0003cd5f -[GraphiqueFVViewController viewDidLayoutSubviews] + 50
1 UIKit 0x34f938c9 <redacted> + 456
2 QuartzCore 0x34d3dd8b <redacted> + 214
3 QuartzCore 0x34d3d929 <redacted> + 460
4 QuartzCore 0x34d3e85d <redacted> + 16
5 QuartzCore 0x34d3e243 <redacted> + 238
6 QuartzCore 0x34d3e051 <redacted> + 316
7 QuartzCore 0x34d3deb1 <redacted> + 60
8 CoreFoundation 0x3315d6cd <redacted> + 20
9 CoreFoundation 0x3315b9c1 <redacted> + 276
10 CoreFoundation 0x3315bd17 <redacted> + 742
11 CoreFoundation 0x330ceebd CFRunLoopRunSpecific + 356
12 CoreFoundation 0x330ced49 CFRunLoopRunInMode + 104
13 GraphicsServices 0x36c922eb GSEventRunModal + 74
14 UIKit 0x34fe4301 UIApplicationMain + 1120
15 MyApp 0x00021add main + 116
16 libdyld.dylib 0x3b264b20 <redacted> + 0
并在调试区回溯:
* thread #1: tid = 0x2503, 0x00101d46 MyApp`-[GraphiqueFVViewController viewDidLayoutSubviews](self=0x1ed972f0, _cmd=0x3541247c) + 42 at GraphiqueFVViewController.m:386, stop reason = breakpoint 2.1
frame #0: 0x00101d46 MyApp`-[GraphiqueFVViewController viewDidLayoutSubviews](self=0x1ed972f0, _cmd=0x3541247c) + 42 at GraphiqueFVViewController.m:386
frame #1: 0x34f938c8 UIKit`-[UIView(CALayerDelegate) layoutSublayersOfLayer:] + 456
frame #2: 0x34d3dd8a QuartzCore`-[CALayer layoutSublayers] + 214
frame #3: 0x34d3d928 QuartzCore`CA::Layer::layout_if_needed(CA::Transaction*) + 460
frame #4: 0x34d3e85c QuartzCore`CA::Layer::layout_and_display_if_needed(CA::Transaction*) + 16
frame #5: 0x34d3e242 QuartzCore`CA::Context::commit_transaction(CA::Transaction*) + 238
frame #6: 0x34d3e050 QuartzCore`CA::Transaction::commit() + 316
frame #7: 0x34d3deb0 QuartzCore`CA::Transaction::observer_callback(__CFRunLoopObserver*, unsigned long, void*) + 60
frame #8: 0x3315d6cc CoreFoundation`__CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__ + 20
frame #9: 0x3315b9c0 CoreFoundation`__CFRunLoopDoObservers + 276
frame #10: 0x3315bd16 CoreFoundation`__CFRunLoopRun + 742
frame #11: 0x330ceebc CoreFoundation`CFRunLoopRunSpecific + 356
frame #12: 0x330ced48 CoreFoundation`CFRunLoopRunInMode + 104
frame #13: 0x36c922ea GraphicsServices`GSEventRunModal + 74
frame #14: 0x34fe4300 UIKit`UIApplicationMain + 1120
frame #15: 0x000e6a84 MyApp`main(argc=1, argv=0x2fd1bd18) + 116 at main.m:16
frame #16: 0x3b264b20 libdyld.dylib`start + 4
thread #3: tid = 0x2903, 0x3b31b648 libsystem_kernel.dylib`kevent64 + 24
frame #0: 0x3b31b648 libsystem_kernel.dylib`kevent64 + 24
frame #1: 0x3b2544f0 libdispatch.dylib`_dispatch_mgr_invoke + 796
frame #2: 0x3b246df8 libdispatch.dylib`_dispatch_mgr_thread$VARIANT$up + 36
thread #5: tid = 0x2b03, 0x3b31aeb4 libsystem_kernel.dylib`mach_msg_trap + 20
frame #0: 0x3b31aeb4 libsystem_kernel.dylib`mach_msg_trap + 20
frame #1: 0x3b31b04c libsystem_kernel.dylib`mach_msg + 40
frame #2: 0x3315d044 CoreFoundation`__CFRunLoopServiceMachPort + 128
frame #3: 0x3315bda2 CoreFoundation`__CFRunLoopRun + 882
frame #4: 0x330ceebc CoreFoundation`CFRunLoopRunSpecific + 356
frame #5: 0x330ced48 CoreFoundation`CFRunLoopRunInMode + 104
frame #6: 0x390cd504 WebCore`RunWebThread(void*) + 444
frame #7: 0x3b284310 libsystem_c.dylib`_pthread_start + 308
thread #7: tid = 0x241f, 0x3b31aeb4 libsystem_kernel.dylib`mach_msg_trap + 20
frame #0: 0x3b31aeb4 libsystem_kernel.dylib`mach_msg_trap + 20
frame #1: 0x3b31b04c libsystem_kernel.dylib`mach_msg + 40
frame #2: 0x3315d044 CoreFoundation`__CFRunLoopServiceMachPort + 128
frame #3: 0x3315bda2 CoreFoundation`__CFRunLoopRun + 882
frame #4: 0x330ceebc CoreFoundation`CFRunLoopRunSpecific + 356
frame #5: 0x330ced48 CoreFoundation`CFRunLoopRunInMode + 104
frame #6: 0x33a1b3d4 Foundation`+[NSURLConnection(Loader) _resourceLoadLoop:] + 308
frame #7: 0x33a9ee84 Foundation`__NSThread__main__ + 972
frame #8: 0x3b284310 libsystem_c.dylib`_pthread_start + 308
thread #8: tid = 0x2d03, 0x3b32b594 libsystem_kernel.dylib`select$DARWIN_EXTSN + 20
frame #0: 0x3b32b594 libsystem_kernel.dylib`select$DARWIN_EXTSN + 20
frame #1: 0x331611f6 CoreFoundation`__CFSocketManager + 678
frame #2: 0x3b284310 libsystem_c.dylib`_pthread_start + 308
thread #11: tid = 0x3003, 0x3b32b08c libsystem_kernel.dylib`__psynch_cvwait + 24
frame #0: 0x3b32b08c libsystem_kernel.dylib`__psynch_cvwait + 24
frame #1: 0x3b27cd2e libsystem_c.dylib`_pthread_cond_wait + 646
frame #2: 0x3b27caa4 libsystem_c.dylib`pthread_cond_timedwait + 44
frame #3: 0x37088c74 javascriptCore`WTF::ThreadCondition::timedWait(WTF::Mutex&, double) + 108
frame #4: 0x3719a556 JavaScriptCore`JSC::BlockAllocator::blockFreeingThreadMain() + 82
frame #5: 0x371acfaa JavaScriptCore`WTF::wtfThreadEntryPoint(void*) + 14
frame #6: 0x3b284310 libsystem_c.dylib`_pthread_start + 308
thread #12: tid = 0x3103, 0x3b31aeb4 libsystem_kernel.dylib`mach_msg_trap + 20
frame #0: 0x3b31aeb4 libsystem_kernel.dylib`mach_msg_trap + 20
frame #1: 0x3b31b04c libsystem_kernel.dylib`mach_msg + 40
frame #2: 0x3315d044 CoreFoundation`__CFRunLoopServiceMachPort + 128
frame #3: 0x3315bda2 CoreFoundation`__CFRunLoopRun + 882
frame #4: 0x330ceebc CoreFoundation`CFRunLoopRunSpecific + 356
frame #5: 0x330ced48 CoreFoundation`CFRunLoopRunInMode + 104
frame #6: 0x39167d06 WebCore`WebCore::runLoaderThread(void*) + 142
frame #7: 0x371acfaa JavaScriptCore`WTF::wtfThreadEntryPoint(void*) + 14
frame #8: 0x3b284310 libsystem_c.dylib`_pthread_start + 308
thread #15: tid = 0x3403, 0x3b32b08c libsystem_kernel.dylib`__psynch_cvwait + 24
frame #0: 0x3b32b08c libsystem_kernel.dylib`__psynch_cvwait + 24
frame #1: 0x3b27cd2e libsystem_c.dylib`_pthread_cond_wait + 646
frame #2: 0x3b286f18 libsystem_c.dylib`pthread_cond_wait + 40
frame #3: 0x37088c46 JavaScriptCore`WTF::ThreadCondition::timedWait(WTF::Mutex&, double) + 62
frame #4: 0x392e1e8c WebCore`WTF::PassOwnPtr<WebCore::StorageTask> WTF::MessageQueue<WebCore::StorageTask>::waitForMessageFilteredWithTimeout<bool (WebCore::StorageTask*)>(WTF::MessageQueueWaitResult&, bool (&)(WebCore::StorageTask*), double) + 56
frame #5: 0x392e1e40 WebCore`WebCore::StorageThread::threadEntryPoint() + 124
frame #6: 0x371acfaa JavaScriptCore`WTF::wtfThreadEntryPoint(void*) + 14
frame #7: 0x3b284310 libsystem_c.dylib`_pthread_start + 308
thread #17: tid = 0x3903, 0x3b32bd98 libsystem_kernel.dylib`__workq_kernreturn + 8
frame #0: 0x3b32bd98 libsystem_kernel.dylib`__workq_kernreturn + 8
frame #1: 0x3b279cfa libsystem_c.dylib`_pthread_workq_return + 18
frame #2: 0x3b279a16 libsystem_c.dylib`_pthread_wqthread + 366
thread #18: tid = 0x3b03, 0x3b32bd98 libsystem_kernel.dylib`__workq_kernreturn + 8
frame #0: 0x3b32bd98 libsystem_kernel.dylib`__workq_kernreturn + 8
frame #1: 0x3b279cfa libsystem_c.dylib`_pthread_workq_return + 18
frame #2: 0x3b279a16 libsystem_c.dylib`_pthread_wqthread + 366
thread #19: tid = 0x3707, 0x3b32bd98 libsystem_kernel.dylib`__workq_kernreturn + 8
frame #0: 0x3b32bd98 libsystem_kernel.dylib`__workq_kernreturn + 8
frame #1: 0x3b279cfa libsystem_c.dylib`_pthread_workq_return + 18
frame #2: 0x3b279a16 libsystem_c.dylib`_pthread_wqthread + 366
【问题讨论】:
您希望控制器子视图保持原始位置,还是让滑块“破坏”控制器子视图布局? 嗯...我的滑块是一个“参数”。当视图出现在屏幕外时,我通过按一个按钮让它出现。此按钮和滑块使用 UIView 类的animateWithDuration:animations:^
方法进行动画处理。更改滑块的值时,我希望滑块和按钮都保持原位(修改滑块时滑块消失没有用,不是吗?)
这是一个 UISlider 吗?可以显示修改滑块时调用的代码吗?
是的。请参阅编辑代码...
能否在更改滑块值时包含 viewDidLayoutSubviews 方法的堆栈跟踪?
【参考方案1】:
嘿,这里的聚会迟到了,但我们遇到了相对相同的问题,我想稍微解释一下。
我们的主视图中包含 3 个视图:一个标签、一个包含登录字段的视图和一个包含 facebook 按钮的视图。当你按下一个按钮时,它会在 2 个登录视图之间切换,当它遇到错误时,标签会缩放到 0,切换文本,然后缩放回 1。我们发现当标签动画并改变大小时,约束将被重新应用,第一个视图将被切换回原位。
我们发现“didLayoutSubviews”的文档说,当视图更改边界时,它会在视图的父级上调用。我们假设当您修改视图的变换时,它也算作更改边界。
所以问题是,如果一个视图动画,它会导致它的所有兄弟视图重新定位到它们的原始状态。
我们通过将标签放在其自己的视图中来解决此问题。动画时,它会在其父级上调用“layoutSubviews”,而父级只会布置自己。
【讨论】:
感谢您的回答。自从我发布它以来,我已经解决了我的问题。问题是因为约束动画视图只是移动它们,并且对超级视图有影响的事件(如添加子视图,呈现视图控制器,自动旋转......)重置约束。解决方案是添加对约束的引用,更改它们的值,要求超级视图布局其子视图并更新约束。 这很有帮助,谢谢!它给我造成了巨大的内存问题,因为我正在用手势拖动视图,并且布局子视图不断被调用并将其放在另一个视图中解决了我的内存问题。以上是关于防止视图布局子视图的主要内容,如果未能解决你的问题,请参考以下文章
Android:如何防止键盘在我的布局中向上推某个视图? [复制]
如果在自动布局中删除子视图,则重新排列 UIView 子视图