iOS

xib相关(二十三) —— 几个xib使用场景示例(一)

2018-08-04  本文已影响0人  刀客传奇

版本记录

版本号 时间
V1.0 2018.08.04

前言

iOS中的视图加载可以有两种方式,一种是通过xib加载,另外一种就是通过纯代码加载。它们各有优点和好处,xib比较直观简单,代码比较灵活但是看着很多很乱,上一家公司主要风格就是用纯代码,这一家用的就是xib用的比较多。这几篇我们就详细的介绍一个xib相关知识。感兴趣的可以看上面写的几篇。
1. xib相关(一) —— 基本知识(一)
2. xib相关(二) —— 文件冲突问题(一)
3. xib相关(三) —— xib右侧标签介绍(一)
4. xib相关(四) —— 连线问题(一)
5. xib相关(五) —— 利用layout进行约束之界面(一)
6. xib相关(六) —— 利用layout进行约束之说明和注意事项(二)
7. xib相关(七) —— Storyboard中的segue (一)
8. xib相关(八) —— Size Classes(一)
9. xib相关(九) —— 几个IB修饰符(一)
10. xib相关(十) —— xib的国际化(一)
11. xib相关(十一) —— xib的高冷用法之修改视图的圆角半径、边框宽度和颜色(一)
12. xib相关(十二) —— UIStackView之基本介绍(一)
13. xib相关(十三) —— UIStackView之枚举UIStackViewDistribution使用(二)
14. xib相关(十四) —— UIStackView之UIStackViewAlignment使用(三)
15. xib相关(十五) —— UIStackView之工程实践(四)
16. xib相关(十六) —— UINib之基本介绍(一)
17. xib相关(十七) —— UINib之Introduction(二)
18. xib相关(十八) —— UINib之Nib文件(三)
19. xib相关(十九) —— UINib之Nib文件(四)
20. xib相关(二十) —— UINib之字符串资源(五)
21. xib相关(二十一) —— UINib之图像、声音和视频资源(六)
22. xib相关(二十二) —— UINib之数据资源文件(七)

直接拖动控件到xib

这个是最简单的用法,就是直接拖动控件到xib中,这个首先我们创建个自定义VC,并勾选上创建Also create XIB file,如下所示:

在下面方法中进行实例化,并设置为window的根控制器。

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
     //这个就是从xib中加载VC对应的视图
    JJMainVC *mainVC = [[JJMainVC alloc] initWithNibName:@"JJMainVC" bundle:nil];
    self.window.rootViewController = mainVC;
    [self.window makeKeyAndVisible];
    
    return YES;
}

下面将JJMainVC的根view设置为蓝色,并run,可以看见蓝色背景图。

可以看见模拟器运行正常

接着我们就拖进去一个UIView系统的控件,如下所示:

运行起来,看一下模拟器

这个是入门级别的,其实可以略过去,但是之所以写出来,是我坚持的一贯的从简入繁的原理,这样有一个过程。


可以给UIImageView拖子控件吗

下面我们一起看一个问题,首先我们往xib中拖进去一个UIImageView并设置如下约束。

可以看见左边的层级关系,UIView和UIImageView都是一个层级上的,下面我们就给UIView上拖一个子控件UILabel,如下所示:

大家可以看见,这个拖进去的UILabel自然就成为了UIView的子控件,看左边的树形图可以清晰的看出来层级关系。

那么下面我们就进入正题了,我们可以给UIImageView控件像给UIView一样拖一个子控件吗?下面我们就试试。

可以看见,我们已经给UIImageView上面拖一个UILabel,但是系统不会让这个UILabel作为UIImageView的子视图,依然会将其和UIImageView作为平级进行展示,如下所示:

所以,通过这个简单的示例我们需要知道:

所以这个话题的结论就是不可以,尽量用UIView做底部父控件,除非你确定这个地方就是一个UIImageView并且长时间不用改变,那你就用UIImageView。


VC中添加xib子view

这里其实是另外一个使用场景,在根View中拖进去一个UIView作为其子控件,这个子控件是一个自定义的UIView,是用xib进行实例化的。

也就是说上面的这个子视图还是一个xib关联的视图。

1. 第一种实现方式

首先我们需要自定义一个该子View的实例化xib对象。

我们首先写一个UIView的分类,这个分类用来实例化xib。

看一下子View中的xib内容,如下所示。

#import "UIView+JJRootView.h"

@implementation UIView (JJRootView)

+ (instancetype)fromNib {
    UINib *nib = [UINib nibWithNibName:NSStringFromClass(self) bundle:nil];
    NSArray * views = [nib instantiateWithOwner:nil options:nil];
    for (UIView * view in views) {
        if ([view isKindOfClass:[self class]]) {
            return view;
        }
    }
    return nil;
}

@end

然后在VC中自定义view属性,并实例化和添加约束。

#import "JJMainVC.h"
#import "JJView.h"
#import "UIView+JJRootView.h"
#import "Masonry.h"

@interface JJMainVC ()

@property (nonatomic, strong) JJView *jjView;

@end

@implementation JJMainVC

#pragma mark - Override Base Function

- (void)viewDidLoad
{
    [super viewDidLoad];
    
    self.jjView = [JJView fromNib];
    [self.view addSubview:self.jjView];
    [self.jjView mas_makeConstraints:^(MASConstraintMaker *make) {
        make.left.equalTo(self.view).offset(100.0);
        make.top.equalTo(self.view).offset(100.0);
        make.width.equalTo(@200);
        make.height.equalTo(@100);
    }];
}

@end

通过上面的代码就可以将自定义的xib放在VC的根View中了,这里有几点需要注意:

我们在模拟器中run一下,如下所示:

可见,根据xib实例化的JJView视图添加到VC的根view上了。

2. 第二种实现方式

1)在VC的根view上添加子视图并进行关联

在这种方式中,我们要在VC中的根view中首先拖进去一个view,并将其和JJView关联。

并设置好约束

在VC中进行拖线,如下所示:

这样拖进去就是实例化了,就不用像上面那样fromNib实例化和addSubview了。也就是说VC中什么代码都不用写了,如下所示:

#import "JJMainVC.h"
#import "JJView.h"
#import "UIView+JJRootView.h"
#import "Masonry.h"

@interface JJMainVC ()

@property (weak, nonatomic) IBOutlet JJView *jjView;

@end

@implementation JJMainVC

#pragma mark - Override Base Function

- (void)viewDidLoad
{
    [super viewDidLoad];
}

@end

2)子JJView中进行拖线和关联设置

首先进行关联设置,如下所示:

可以看见,在File's Owner中进行关联设置,没有在View那一栏进行了关联。

下一步就是拖线了,将view拖线到JJView的m文件中。

然后在JJView中用下面代码进行加载。

#import "JJView.h"

@interface JJView()

@property (weak, nonatomic) IBOutlet UIView *contentView;

@end

@implementation JJView

#pragma mark - Override Base Function

- (void)awakeFromNib
{
    [super awakeFromNib];
    
    [[NSBundle mainBundle] loadNibNamed:@"JJView" owner:nil options:nil];
    [self addSubview:self.contentView];
}

@end

运行起来可以看见崩溃了

2018-08-04 17:15:34.847414+0800 JJXib[957:25807] *** Terminating app due to uncaught exception 'NSUnknownKeyException', reason: '[<NSObject 0x600000206a40> setValue:forUndefinedKey:]: this class is not key value coding-compliant for the key contentView.'
*** First throw call stack:
(
    0   CoreFoundation                      0x00000001065551e6 __exceptionPreprocess + 294
    1   libobjc.A.dylib                     0x0000000105bea031 objc_exception_throw + 48
    2   CoreFoundation                      0x00000001065550b9 -[NSException raise] + 9
    3   Foundation                          0x000000010560bb47 -[NSObject(NSKeyValueCoding) setValue:forKey:] + 292
    4   UIKit                               0x0000000106e5be8a -[UIRuntimeOutletConnection connect] + 109
    5   CoreFoundation                      0x00000001064f7e8d -[NSArray makeObjectsPerformSelector:] + 317
    6   UIKit                               0x0000000106e5a834 -[UINib instantiateWithOwner:options:] + 1856
    7   UIKit                               0x0000000106e622ed -[NSBundle(UINSBundleAdditions) loadNibNamed:owner:options:] + 222
    8   JJXib                               0x00000001052bf1ac -[JJView awakeFromNib] + 140
    9   UIKit                               0x0000000106e5aa61 -[UINib instantiateWithOwner:options:] + 2413
    10  UIKit                               0x0000000106b750d7 -[UIViewController _loadViewFromNibNamed:bundle:] + 383
    11  UIKit                               0x0000000106b75a04 -[UIViewController loadView] + 177
    12  UIKit                               0x0000000106b75d21 -[UIViewController loadViewIfRequired] + 175
    13  UIKit                               0x0000000106b76574 -[UIViewController view] + 27
    14  UIKit                               0x0000000106a44123 -[UIWindow addRootViewControllerViewIfPossible] + 122
    15  UIKit                               0x0000000106a44834 -[UIWindow _setHidden:forced:] + 294
    16  UIKit                               0x0000000106a575cc -[UIWindow makeKeyAndVisible] + 42
    17  JJXib                               0x00000001052ca084 -[AppDelegate application:didFinishLaunchingWithOptions:] + 516
    18  UIKit                               0x00000001069c96fb -[UIApplication _handleDelegateCallbacksWithOptions:isSuspended:restoreState:] + 278
    19  UIKit                               0x00000001069cb172 -[UIApplication _callInitializationDelegatesForMainScene:transitionContext:] + 4123
    20  UIKit                               0x00000001069d05cb -[UIApplication _runWithMainScene:transitionContext:completion:] + 1677
    21  UIKit                               0x0000000106d92f7e __111-[__UICanvasLifecycleMonitor_Compatability _scheduleFirstCommitForScene:transition:firstActivation:completion:]_block_invoke + 866
    22  UIKit                               0x0000000107165a39 +[_UICanvas _enqueuePostSettingUpdateTransactionBlock:] + 153
    23  UIKit                               0x0000000106d92bba -[__UICanvasLifecycleMonitor_Compatability _scheduleFirstCommitForScene:transition:firstActivation:completion:] + 236
    24  UIKit                               0x0000000106d933db -[__UICanvasLifecycleMonitor_Compatability activateEventsOnly:withContext:completion:] + 675
    25  UIKit                               0x0000000107704614 __82-[_UIApplicationCanvas _transitionLifecycleStateWithTransitionContext:completion:]_block_invoke + 299
    26  UIKit                               0x00000001077044ae -[_UIApplicationCanvas _transitionLifecycleStateWithTransitionContext:completion:] + 433
    27  UIKit                               0x00000001073e875d __125-[_UICanvasLifecycleSettingsDiffAction performActionsForCanvas:withUpdatedScene:settingsDiff:fromSettings:transitionContext:]_block_invoke + 221
    28  UIKit                               0x00000001075e34b7 _performActionsWithDelayForTransitionContext + 100
    29  UIKit                               0x00000001073e8627 -[_UICanvasLifecycleSettingsDiffAction performActionsForCanvas:withUpdatedScene:settingsDiff:fromSettings:transitionContext:] + 223
    30  UIKit                               0x00000001071650e0 -[_UICanvas scene:didUpdateWithDiff:transitionContext:completion:] + 392
    31  UIKit                               0x00000001069ceeac -[UIApplication workspace:didCreateScene:withTransitionContext:completion:] + 515
    32  UIKit                               0x0000000106fa1bcb -[UIApplicationSceneClientAgent scene:didInitializeWithEvent:completion:] + 361
    33  FrontBoardServices                  0x000000010adff2f3 -[FBSSceneImpl _didCreateWithTransitionContext:completion:] + 331
    34  FrontBoardServices                  0x000000010ae07cfa __56-[FBSWorkspace client:handleCreateScene:withCompletion:]_block_invoke_2 + 225
    35  libdispatch.dylib                   0x0000000109f357ec _dispatch_client_callout + 8
    36  libdispatch.dylib                   0x0000000109f3adb8 _dispatch_block_invoke_direct + 592
    37  FrontBoardServices                  0x000000010ae33470 __FBSSERIALQUEUE_IS_CALLING_OUT_TO_A_BLOCK__ + 24
    38  FrontBoardServices                  0x000000010ae3312e -[FBSSerialQueue _performNext] + 439
    39  FrontBoardServices                  0x000000010ae3368e -[FBSSerialQueue _performNextFromRunLoopSource] + 45
    40  CoreFoundation                      0x00000001064f7bb1 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 17
    41  CoreFoundation                      0x00000001064dc4af __CFRunLoopDoSources0 + 271
    42  CoreFoundation                      0x00000001064dba6f __CFRunLoopRun + 1263
    43  CoreFoundation                      0x00000001064db30b CFRunLoopRunSpecific + 635
    44  GraphicsServices                    0x000000010b6c8a73 GSEventRunModal + 62
    45  UIKit                               0x00000001069d2057 UIApplicationMain + 159
    46  JJXib                               0x00000001052bed0f main + 111
    47  libdyld.dylib                       0x0000000109fb2955 start + 1
    48  ???                                 0x0000000000000001 0x0 + 1
)
libc++abi.dylib: terminating with uncaught exception of type NSException

问题就出在下面这句

[[NSBundle mainBundle] loadNibNamed:@"JJView" owner:nil options:nil];

这里设置了File's Owner,那么这句话owner这个参数就不能传递为nil,应该为self,修改下如下所示:

[[NSBundle mainBundle] loadNibNamed:@"JJView" owner:self options:nil];

运行起来查看结果,如下所示:

可见子视图已经加载上来了,且如约束所示,加在了视图的中间。

这里你可以不在下面这里这么写:

- (void)awakeFromNib
{
    [super awakeFromNib];
    
    [[NSBundle mainBundle] loadNibNamed:@"JJView" owner:nil options:nil];
    [self addSubview:self.contentView];
}

你也可以用下面这几行代码进行替换

@property (nonatomic, weak)   IBOutlet UIView  *view;

- (instancetype)initWithCoder:(NSCoder *)aDecoder
{
    self = [super initWithCoder:aDecoder];
    if (self) {
        self.backgroundColor = [UIColor clearColor];
        
        NSString *className = NSStringFromClass([self class]);
        self.view = [[[NSBundle mainBundle] loadNibNamed:className owner:self options:nil] firstObject];
        self.view.frame = self.bounds;
        [self addSubview:self.view];
        return self;
    }
    return nil;
}

- (void)awakeFromNib 
{
    [super awakeFromNib];

}

运行起来效果是一样的。

后记

本篇主要讲述了xib几种常用的用法,感兴趣的给个赞或者关注~~~~

上一篇下一篇

猜你喜欢

热点阅读