我想在保留约束的同时将一个NSView替换为其他视图.
我有一个superview,subview,因为它是小孩和占位符,我打算迁移到子视图的地方.
但它似乎是代码
[[superview] replaceSubview:subview with:placeholder];
约束如何从一个视图“复制”到另一个视图?
解决方法
这是我写的很久以前的一些代码来做你所要求的.
我的代码用于在同一个超级视图中交换两个NSView,但是您可以轻松地将其替换为剥离不必要的位,并以仔细的顺序执行视图/约束添加和删除.事实上,我在“代理”视图控制器类中有一个较短的版本的代码,它完全符合你的要求,但我不能共享,因为它是一个不属于我的专有项目.
我会告诉你,你需要做的是将约束从代理视图复制到新视图,然后将新视图添加到超级视图.之后,将代理的超级视图约束复制到新视图,只有在您执行此操作后,才能从超级视图中删除代理视图.
- (void)swapView:(NSView*) source withView:(NSView*) dest persist:(BOOL) persist { NSLog(@"swapping %@ with %@",source.identifier,dest.identifier); // !!!: adjust the "Auto Layout" constraints for the superview. // otherwise changing the frames is impossible. (instant reversion) // we could disable "Auto Layout",but let's try for compatibility // TODO: we need to either enforce that the 2 controls have the same superview // before accepting the drag operation // or modify this code to take two diffrent superviews into account // we are altering the constraints so iterate a copy! NSArray* constraints = [dest.superview.constraints copy]; for (NSLayoutConstraint* constraint in constraints) { id first = constraint.firstItem; id second = constraint.secondItem; id newFirst = first; id newSecond = second; BOOL match = NO; if (first == dest) { newFirst = source; match = YES; } if (second == dest) { newSecond = source; match = YES; } if (first == source) { newFirst = dest; match = YES; } if (second == source) { newSecond = dest; match = YES; } if (match && newFirst) { [dest.superview removeConstraint:constraint]; @try { NSLayoutConstraint* newConstraint = nil; newConstraint = [NSLayoutConstraint constraintWithItem:newFirst attribute:constraint.firstAttribute relatedBy:constraint.relation toItem:newSecond attribute:constraint.secondAttribute multiplier:constraint.multiplier constant:constraint.constant]; newConstraint.shouldBeArchived = constraint.shouldBeArchived; newConstraint.priority = NSLayoutPriorityWindowSizeStayPut; [dest.superview addConstraint:newConstraint]; } @catch (NSException *exception) { NSLog(@"Constraint exception: %@\nFor constraint: %@",exception,constraint); } } } [constraints release]; NSMutableArray* newSourceConstraints = [NSMutableArray array]; NSMutableArray* newDestConstraints = [NSMutableArray array]; // again we need a copy since we will be altering the original constraints = [source.constraints copy]; for (NSLayoutConstraint* constraint in constraints) { // WARNING: do not tamper with intrinsic layout constraints if ([constraint class] == [NSLayoutConstraint class] && constraint.firstItem == source) { // this is a source constraint. we need to copy it to the destination. NSLayoutConstraint* newConstraint = nil; newConstraint = [NSLayoutConstraint constraintWithItem:dest attribute:constraint.firstAttribute relatedBy:constraint.relation toItem:constraint.secondItem attribute:constraint.secondAttribute multiplier:constraint.multiplier constant:constraint.constant]; newConstraint.shouldBeArchived = constraint.shouldBeArchived; [newDestConstraints addObject:newConstraint]; [source removeConstraint:constraint]; } } [constraints release]; // again we need a copy since we will be altering the original constraints = [dest.constraints copy]; for (NSLayoutConstraint* constraint in constraints) { // WARNING: do not tamper with intrinsic layout constraints if ([constraint class] == [NSLayoutConstraint class] && constraint.firstItem == dest) { // this is a destination constraint. we need to copy it to the source. NSLayoutConstraint* newConstraint = nil; newConstraint = [NSLayoutConstraint constraintWithItem:source attribute:constraint.firstAttribute relatedBy:constraint.relation toItem:constraint.secondItem attribute:constraint.secondAttribute multiplier:constraint.multiplier constant:constraint.constant]; newConstraint.shouldBeArchived = constraint.shouldBeArchived; [newSourceConstraints addObject:newConstraint]; [dest removeConstraint:constraint]; } } [constraints release]; [dest addConstraints:newDestConstraints]; [source addConstraints:newSourceConstraints]; // auto layout makes setting the frame unnecissary,but // we do it because its possible that a module is not using auto layout NSRect srcRect = source.frame; NSRect dstRect = dest.frame; // round the coordinates!!! // otherwise we will have problems with persistant values srcRect.origin.x = round(srcRect.origin.x); srcRect.origin.y = round(srcRect.origin.y); dstRect.origin.x = round(dstRect.origin.x); dstRect.origin.y = round(dstRect.origin.y); source.frame = dstRect; dest.frame = srcRect; if (persist) { NSString* rectString = NSStringFromRect(srcRect); [[_theme prefrences] setObject:rectString forKey:dest.identifier]; rectString = NSStringFromRect(dstRect); [[_theme prefrences] setObject:rectString forKey:source.identifier]; } }
你可以放心地忽略你想象的情况下的持久性.在我的情况下,我想实现iOS跳板功能(能够点按并按住一个按钮,它会跳动,让我拖动到另一个按钮,并在发射之间交换位置)