我创建的自定义视图应该出现在应用程序中的多个视图控制器中。
所以...我已经用它的xib,h和m文件创建了UIView的子视图(并使用类在xib文件中设置了View),将我的UI添加到视图xib文件并将它们连接为IBOutlets:
然后......我向视图控制器添加了2个UIViews,将它们的类设置为MYCustomView并将该类型的IBOutlet连接到VC:
而且......它不起作用......
现在......我熟悉使用NSBundle loadNibNamed:owner:options:方法加载xib的技术。
但是......我真的希望能够直接在IB中设置MYCustomView的实例(约束,大小等等)。
还有其他办法吗?或者我应该创建'占位符'UIViews并将我的MYCustomView实例添加为他们的子视图?
答案 0 :(得分:2)
我总是使用一些UIView类别来自定义视图,你可以自己使用它,只需几个简单的步骤:
单击命令+ N以添加新的Objective-C类别。 在头文件中添加以下行:
// This category let the UIView that using it to load a XIB with the same name as the UIView.h & .m files easily.
// See: MyContentWaitingSong custom view for reference.
@interface UIView (NibLoading)
+ (id)loadInstanceFromNib;
@end
在.m文件中添加以下行:
// This category let the UIView that using it to load a XIB with the same name as the UIView.h & .m files easily.
// See: MyContentWaitingSong custom view for reference.
@implementation UIView (NibLoading)
+ (id)loadInstanceFromNib
{
UIView *result = nil;
NSArray* elements = [[NSBundle mainBundle] loadNibNamed:NSStringFromClass([self class]) owner:nil options:nil];
for (id anObject in elements) {
if ([anObject isKindOfClass:[self class]]) {
result = anObject;
break;
}
}
return result;
}
@end
您可以在自定义视图类中使用它,只需导入类别并实现类似这样的init方法:
- (id)init
{
self = [YourCustomClassName loadInstanceFromNib];
if (self)
{
// Your initial implementation
}
return self;
}
比你的实现应该是这样的:
YourCustomClassName *someName = [[YourCustomClassName alloc] init];
someName.frame = frame;
[self.view addSubView:someName];
祝你好运。
答案 1 :(得分:1)
不,你问一下从其他笔尖引用笔尖。有一些方法可以通过一些awakeAfterUsingCoder:
黑客或类似的东西实现这一目标。通常你检查视图是否没有子视图并从nib加载视图然后创建一些IB-dummy类,它在加载后用目标类替换自己。所有这些技巧都有问题,所以我建议不要这样做。
所以我建议从代码加载,好的方法是使用视图控制器包含。
有一些非常酷的东西,不久前出现过:IBDesignable and IBInspectable,它必须在某个时刻出现。
一个例子是我在使用框架尚未就绪时使用的一些临时代码(它是一个UIButton虚拟IB子类):
//
// That's just an example, do not use it in production code
//
- (id)awakeAfterUsingCoder:(NSCoder *)aDecoder
{
UIButton *buttonMain = // create button, which will replace button of dummy class from nib
buttonMain.translatesAutoresizingMaskIntoConstraints = NO;
// copy internal constraints
[self copyInternalConstraintsToView:buttonMain];
// set titles
NSString *title = [self titleForState:UIControlStateNormal];
[buttonMain setTitle:title forState:UIControlStateNormal];
title = [self titleForState:UIControlStateHighlighted];
[buttonMain setTitle:title forState:UIControlStateHighlighted];
title = [self titleForState:UIControlStateDisabled];
[buttonMain setTitle:title forState:UIControlStateDisabled];
title = [self titleForState:UIControlStateSelected];
[buttonMain setTitle:title forState:UIControlStateSelected];
return buttonMain;
}
/**
* Used only in awakeAfterUsingCoder, as self has only internal constraints at that moment.
* If you'll try to use it somewhere else, behavior is undefined.
*
* This method is straightforward and could not suit everybody's needs.
*
* %Comments edited%
*
* @param replacementView view to add constraints to
*/
- (void)copyInternalConstraintsToView:(UIView *)replacementView
{
for (NSLayoutConstraint* constraint in self.constraints)
{
if([constraint isMemberOfClass:[NSLayoutConstraint class]])
{
id first = constraint.firstItem;
id second = constraint.secondItem;
id newFirst = first;
id newSecond = second;
BOOL match = NO;
if (first == self)
{
newFirst = replacementView;
match = YES;
}
if (second == self)
{
newSecond = replacementView;
match = YES;
}
// constraints to subviews from recource are not supported
if(newFirst != nil && newFirst != replacementView)
{
match = NO;
}
if(newSecond != nil && newSecond != replacementView)
{
match = NO;
}
if (match)
{
@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 = constraint.priority;
[replacementView addConstraint:newConstraint];
}
@catch (NSException *exception)
{
NSLog(@"Constraint exception: %@\nFor constraint: %@", exception, constraint);
}
}
}
}
}
一些链接: Embedding custom-view Nibs in another Nib: Towards the holy grail,An Update on Nested Nib Loading
答案 2 :(得分:1)
我认为有两种可能的方法:
loadNibNamed:owner:options
对于第二种方法,您需要使用视图控制器来放入自定义视图,但这应该是一个问题。在我看来,使用单独的视图控制器放入视图控制器逻辑会更好。