Tra*_*ggs 44 xcode objective-c interface-builder ios uistoryboard
我在XCode/iOS世界中相对较新; 我已经做了一些像样的大小基于故事板的应用程序,但我从来没有在整个nib/xib的东西上削减我的力量.我想使用相同的工具为场景设计/布局可重用的视图/控件.所以我为我的视图子类创建了我的第一个xib并绘制了它:

我已连接我的插座和约束设置,就像我以前在故事板中做的那样.我将my的类设置File Owner为我的自定义UIView子类.所以我假设我可以用一些API实例化这个视图子类,它将如图所示配置/连接.
现在回到我的故事板中,我想嵌入/重用它.我在表视图原型单元格中这样做:

我有一个观点.我已将它的类设置为我的子类.我为它创建了一个插座,所以我可以操纵它.
64美元的问题是在哪里/如何表明仅仅放置我的视图子类的空/未配置实例是不够的,但是使用我创建的.xib来配置/实例化它?这真的很酷,如果在XCode6中,我可以输入XIB文件用于给定的UIView,但我没有看到这样做的字段,所以我假设我必须在代码中的某些地方做一些事情.
(我确实在SO上看到了这样的其他问题,但是没有找到任何关于这部分难题的问题,或者最新的XCode6/2015)
我可以通过实现我的表格单元格来实现这一点,awakeFromNib如下所示:
- (void)awakeFromNib
{
// gather all of the constraints pointing to the uncofigured instance
NSArray* progressConstraints = [self.contentView.constraints filteredArrayUsingPredicate: [NSPredicate predicateWithBlock:^BOOL(id each, NSDictionary *_) {
return (((NSLayoutConstraint*)each).firstItem == self.progressControl) || (((NSLayoutConstraint*)each).secondItem == self.progressControl);
}]];
// fetch the fleshed out variant
ProgramProgressControl *fromXIB = [[[NSBundle mainBundle] loadNibNamed:@"ProgramProgressControl" owner:self options:nil] objectAtIndex:0];
// ape the current placeholder's frame
fromXIB.frame = self.progressControl.frame;
// now swap them
[UIView transitionFromView: self.progressControl toView: fromXIB duration: 0 options: 0 completion: nil];
// recreate all of the constraints, but for the new guy
for (NSLayoutConstraint *each in progressConstraints) {
id firstItem = each.firstItem == self.progressControl ? fromXIB : each.firstItem;
id secondItem = each.secondItem == self.progressControl ? fromXIB : each.secondItem;
NSLayoutConstraint *constraint = [NSLayoutConstraint constraintWithItem: firstItem attribute: each.firstAttribute relatedBy: each.relation toItem: secondItem attribute: each.secondAttribute multiplier: each.multiplier constant: each.constant];
[self.contentView addConstraint: constraint];
}
// update our outlet
self.progressControl = fromXIB;
}
Run Code Online (Sandbox Code Playgroud)
这很容易吗?还是我为此努力工作?
Seg*_*gev 28
你快到了.您需要在分配视图的自定义类中覆盖initWithCoder.
- (id)initWithCoder:(NSCoder *)aDecoder {
if ((self = [super initWithCoder:aDecoder])) {
[self addSubview:[[[NSBundle mainBundle] loadNibNamed:@"ViewYouCreated" owner:self options:nil] objectAtIndex:0]];
}
return self; }
Run Code Online (Sandbox Code Playgroud)
一旦完成,StoryBoard将知道在UIView中加载xib.
这是一个更详细的解释:
这就是UIViewController你的故事板上的样子:

蓝色空间基本上是一个将"保持"你的xib的UIView.
这是你的xib:

有一个Action连接到它上面的一个按钮,它将打印一些文本.
这是最终的结果:

第一个clickMe和第二个之间的区别在于第一个被添加到UIViewController使用了StoryBoard.第二个是使用代码添加的.
Tom*_*ift 16
您需要awakeAfterUsingCoder:在自定义UIView子类中实现.此方法允许您将解码的对象(来自故事板)与不同的对象(来自可重用的xib)交换,如下所示:
- (id) awakeAfterUsingCoder: (NSCoder *) aDecoder
{
// without this check you'll end up with a recursive loop - we need to know that we were loaded from our view xib vs the storyboard.
// set the view tag in the MyView xib to be -999 and anything else in the storyboard.
if ( self.tag == -999 )
{
return self;
}
// make sure your custom view is the first object in the nib
MyView* v = [[[UINib nibWithNibName: @"MyView" bundle: nil] instantiateWithOwner: nil options: nil] firstObject];
// copy properties forward from the storyboard-decoded object (self)
v.frame = self.frame;
v.autoresizingMask = self.autoresizingMask;
v.translatesAutoresizingMaskIntoConstraints = self.translatesAutoresizingMaskIntoConstraints;
v.tag = self.tag;
// copy any other attribtues you want to set in the storyboard
// possibly copy any child constraints for width/height
return v;
}
Run Code Online (Sandbox Code Playgroud)
这里有一篇非常好的文章,讨论了这种技术和一些替代方案.
此外,如果你添加IB_DESIGNABLE到@interface声明,并提供一个initWithFrame:方法,你可以让设计时预览在IB中工作(需要Xcode 6!):
IB_DESIGNABLE @interface MyView : UIView
@end
@implementation MyView
- (id) initWithFrame: (CGRect) frame
{
self = [[[UINib nibWithNibName: @"MyView"
bundle: [NSBundle bundleForClass: [MyView class]]]
instantiateWithOwner: nil
options: nil] firstObject];
self.frame = frame;
return self;
}
Run Code Online (Sandbox Code Playgroud)
bra*_*ipt 15
这个Interface Builder和Swift 4的一种非常酷且可重用的方式:
像这样创建一个新类:
import Foundation
import UIKit
@IBDesignable class XibView: UIView {
@IBInspectable var xibName: String?
override func awakeFromNib() {
guard let name = self.xibName,
let xib = Bundle.main.loadNibNamed(name, owner: self),
let view = xib.first as? UIView else { return }
self.addSubview(view)
}
}
Run Code Online (Sandbox Code Playgroud)在您的故事板中,添加一个UIView,它将充当Xib的容器.给它一个类名XibView:

在此new的属性检查器中XibView,在IBInspectable字段中设置.xib的名称(不带文件扩展名):

将新的Xib视图添加到项目中,并在属性检查器中,将Xib的"文件所有者"设置为XibView(确保您只将"文件所有者"设置为自定义类,不要将内容视图子类化,否则它将崩溃),再次设置IBInspectable字段:

有一点需要注意:这假设您将.xib框架与其容器匹配.如果你没有,或者需要它可以调整大小,你需要添加一些编程约束或修改子视图的框架以适应.我使用snapkit使事情变得简单:
xibView.snp_makeConstraints(closure: { (make) -> Void in
make.edges.equalTo(self)
})
Run Code Online (Sandbox Code Playgroud)
奖励积分
据称,您可以使用prepareForInterfaceBuilder()这些可重用的视图在Interface Builder中可见,但我没有太多运气.此博客建议添加contentView属性,并调用以下内容:
override func prepareForInterfaceBuilder() {
super.prepareForInterfaceBuilder()
xibSetup()
contentView?.prepareForInterfaceBuilder()
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
37389 次 |
| 最近记录: |