iOS进阶不易的地方iOS开发iOS开发

ios Xib的几种用法[转]

2017-04-20  本文已影响2774人  Hanser0503

大多数Ios开发者都喜欢运用xib以及约束来布局,这样省去了大量初始化代码,但是xib的使用也是存在不少差异的:

一.xib的几个重要属性

二.Demo实现

1.加载xib中File's owner为nil的视图

blueView.png

ViewController:

- (void)addBlueView {
    // BlueView.xib的File's Owner为nil
    NSArray *views = [[NSBundle mainBundle] loadNibNamed:@"BlueView" owner:nil options:nil];
    self.blueView = views[0];
    
    // 从xib加载进来的View大小是确定的,但是该视图在父视图中的位置是不确定的
    // 此外,视图中的子视图也是原封不动地Load进来的
    CGRect rect = _blueView.frame;
    rect.origin.x += 37.5f;
    rect.origin.y += 80.0f;
    _blueView.frame = rect;
    [self.view addSubview:_blueView];
}

运行结果:


blueViewResult.png

总结:

2.加载File's owner为self的视图

greenView.png

ViewController

- (void)addGreenView {
    // GreenView.xib的File's Owner设为self,并建立了一个从该xib的View到self的IBOutlet greenView
    [[NSBundle mainBundle] loadNibNamed:@"GreenView" owner:self options:nil];
    // 只要self主动调用Load XIB的方法,self持有的IBOutlet指向的视图就会被初始化
    // 这里不需要通过views[0]的方式存取视图
    CGRect rect = _greenView.frame;
    rect.origin.x = _blueView.frame.origin.x;
    rect.origin.y = _blueView.frame.origin.y + 80.0f;
    _greenView.frame = rect;
    [self.view addSubview:_greenView];
}

运行结果:

greenViewResult.png

总结:

3.加载xib中File’s Owner为特定类的视图

redView.png

RedViewOwner:

@interface RedViewOwner : NSObject
@property (strong, nonatomic) IBOutlet UIView *redView;
@end

ViewController:
- (void)addRedView {
    self.redViewOwner = [RedViewOwner new];
    [[NSBundle mainBundle] loadNibNamed:@"RedView" owner:self.redViewOwner options:nil];
    UIView *redView = _redViewOwner.redView;
    CGRect rect = redView.frame;
    rect.origin.x = _greenView.frame.origin.x;
    rect.origin.y = CGRectGetMaxY(_greenView.frame) + 30;
    redView.frame = rect;
    [self.view addSubview:redView];
}

结果:


redresult.png

总结:

4.加载xib中文件名和视图类名一致的视图(File’s Owner为nil)

yellowview.png
@implementation YellowView

+ (instancetype)loadYellowViewFromXib {
    // 加载xib中的视图,其中xib文件名和本类类名必须一致
    // 这个xib文件的File's Owner必须为空
    // 这个xib文件必须只拥有一个视图,并且该视图的class为本类
    NSArray *views = [[NSBundle mainBundle] loadNibNamed:NSStringFromClass([self class]) owner:nil options:nil];
    return views[0];
}
@end
ViewController:
- (void)addYellowView {
    self.yellowView = [YellowView loadYellowViewFromXib];
    CGRect rect = _yellowView.frame;
    rect.origin.x = _redViewOwner.redView.frame.origin.x;
    rect.origin.y = CGRectGetMaxY(_redViewOwner.redView.frame) + 30;
    _yellowView.frame = rect;
    [self.view addSubview:self.yellowView];
}

结果:

yellowresult.png

总结:

5. 通过UIViewController的initWithNibName:bundle:方法加载xib文件中的视图

blackView.png

如果想要self.view是视图中的底层view,那么要连线File's owner 和view


blackviewll.png

BlackViewController

@interface BlackViewController : UIViewController
@property (weak, nonatomic) IBOutlet UILabel *label;
+ (instancetype)viewControllerFromNIB;
@end
+ (instancetype)viewControllerFromNIB {
    return [[BlackViewController alloc] initWithNibName:NSStringFromClass([self class]) bundle:[NSBundle mainBundle]];
}

ViewController

- (void)addBlackView {
    self.blackVC = [[BlackViewController alloc] initWithNibName:@"BlackView" bundle:[NSBundle mainBundle]];
    UIView *views = self.blackVC.view;
    CGRect rect = views.frame;
    rect.origin.x = _yellowView.frame.origin.x;
    rect.origin.y = CGRectGetMaxY(_yellowView.frame) + 20;
    views.frame = rect;
    [self.view addSubview:views];
}

总结:

6. 通过UIViewController+NIB加载xib文件中的View Controller类和其视图

GrayView.xib

grayView.png grayviewaction.png

UIViewController+NIB.h/m

@interface UIViewController (NIB)
// 要求xib文件名和View Controller类名一致
+ (instancetype)loadFromNib;
@end
@implementation UIViewController (NIB)
+ (instancetype)loadFromNib {
    // [self class]会由调用的类决定
    Class controllerClass = [self class];
    NSLog(@"class = %@", controllerClass);
    return [[controllerClass alloc] initWithNibName:NSStringFromClass(controllerClass) bundle:[NSBundle mainBundle]];
}
@end

GrayViewController.h/m

@interface GrayViewController : UIViewController
@property (weak, nonatomic) IBOutlet UILabel *titleLabel;
@property (weak, nonatomic) IBOutlet UIButton *actionButton;
@end
@implementation GrayViewController
- (void)viewDidLoad {
    [super viewDidLoad];
     
    self.view.backgroundColor = [UIColor grayColor];
     
    self.titleLabel.text = @"Gray View";
    self.titleLabel.textColor = [UIColor whiteColor];
    self.titleLabel.textAlignment = NSTextAlignmentCenter;
    self.titleLabel.font = [UIFont systemFontOfSize:8.5f];
     
    [self.actionButton setTitle:@"action" forState:UIControlStateNormal];
    [self.actionButton setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
}
- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}
// 推荐从XIB文件中加载View Controller的方法,这种方法可以将XIB文件中的视图和其按钮响应事件全部封装在GrayViewController
// 如果GrayViewController的按钮响应事件由MainViewController作出响应,那么二者的耦合度就过高
// 建议:
// 单纯的通用View展示,使用从xib文件加载视图的方法,File's Owner设为nil
// 特定拥有者的View展示,从xib文件加载视图时,File's Owner设为拥有者
// 如果视图中有按钮响应事件,或其它可以和用户交互的事件,建议采用从XIB文件中加载View Controller的方法,这样可以封装UI展示和交互事件
- (IBAction)action:(id)sender {
    NSLog(@"action");
}
@end

ViewController

...
@property (strong, nonatomic) GrayViewController *grayViewController;
...
- (void)loadGrayViewFromXIB {
    self.grayViewController = [GrayViewController loadFromNib];
     
    UIView *grayView = _grayViewController.view;
    UIView *blackView = _blackViewController.view;
    CGRect rect = grayView.frame;
    rect.origin.x = blackView.frame.origin.x;
    rect.origin.y = blackView.frame.origin.y + 80.0f;
    grayView.frame = rect;
    [self.view addSubview:grayView];
}

结果:


grayViewResult.png

总结:

三.总结

在写界面时同时混用xib和代码可以提高效率,而对xib的使用主要体现在其专用性和通用性上。

对于通用的xib:

四.发现的问题

以前使用xib时一直都有点疑问,xib中可以有多个视图控件,但是从xib中load出来的是一个数组,那么怎么确定哪个对象对应的是哪个控件呢?

TestView.xib

testView.png

ViewController:

- (void)loadFromNib {
    NSArray *array = [[NSBundle mainBundle] loadNibNamed:@"TestView" owner:nil options:nil];
    [array enumerateObjectsUsingBlock:^(id  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
        NSLog(@"%ld----%@",idx,NSStringFromClass([obj class]));
    }];
}

控制台输出如下:

2017-03-30 17:53:21.128 启动页[7655:288700] 0----UIView
2017-03-30 17:53:21.128 启动页[7655:288700] 1----UIButton
2017-03-30 17:53:21.128 启动页[7655:288700] 2----UITableView
2017-03-30 17:53:21.128 启动页[7655:288700] 3----UIImageView

结论:
从xib中load出来的views数组中视图对象的排列顺序和xib scene中的对象排列顺序一致(其实就是xml文件中元素的排序而已)。

result.png
上一篇 下一篇

猜你喜欢

热点阅读