美文网首页
iOS自定义UIView

iOS自定义UIView

作者: p_peng | 来源:发表于2019-07-10 16:45 被阅读0次

    XIB自定义UIView

    在XIB中使用autolayout是非常方便的,所以有的时候我们需要使用XIB来创建自定义UIView。但是不像UITableViewCell,创建Class的时候可以选择勾选自动创建XIB,UIView只能单独创建XIB,下面整理一下通过XIB创建自定义UIView的步骤:

    • 创建自定义的UIView,例如MyXibView extends UIView;
    • 创建不相同名字的XIB,使用View模板,例如MyXib.xib;
    • 在XIB中设置View的Class为MyXibView;
    • 在MyXibView.m中实现一个类方法,代码如下:
    + (MyXibView*) myXibView {
      NSArray* array = [[NSBundle mainBundle] loadNibNamed:@"MyXib" owner:nil options:nil];
      return [array objectAtIndex:0]; 
    }
    

    后续的操作就如你正常的进行,在XIB中放置控件,并设置autolayout约束,关联代码文件中的IBOutlet和IBAction,进行相关的业务逻辑处理;

    这里XIB与Class的必须要使用不同的名字,否则会出各种问题:

    1. 在XIB的ViewController中frame问题,设置了frame无效,必须要在viewWillLayoutSubviews方法重设。
    2. 在纯代码的ViewController中会奔溃,[UIViewController _loadViewFromNibNamed:bundle:] loaded the "MyView" nib but the view outlet was not set.。猜测原因是[NSBundle loadNibNamed]方法会寻找Nib同名的Class,默认认为这个Class是UIViewController,需要一个IBOutlet,但是这里没有连接IBOutlet,而且对应的也只是一个UIView。

    initWithCoder

    在测试上面自定义方法的时候我有想到initWithCoder方法,也参考了initWithFrame方法的实现,结果就死循环了,loadNibNamed方法会调用initWithCoder方法,而initWithCoder方法又调用了loadNibNamed方法。

    initWithCoder方法是当前控件被其他的XIB或者Storyboard文件引用的时候调用的,自己有一个对应的XIB文件,然而外部的XIB或者Storyboard文件中也有相应的布局,那么这两个布局冲突了。如果不实现initWithCoder方法,XIB或者Storyboard引用的时候自己的XIB中的内容和布局都不会存在。

    所以如果需要在外部的XIB或者Storyboard文件中使用自定义的控件,不要使用XIB这种方式创建,应该试用纯代码的方式创建。

    参考链接:iPhone-load-a-uiview-from-a-nib-file

    IB_DESIGNABLE和IBInspectable

    使用纯代码自定义UIView的时候可以使用这两个属性,让使用者在XIB或者Storyboard中实时看到修改属性的效果。

    具体使用方法是在Interface上加上IB_DESIGNABLE,在属性上加上IBInspectable,重写属性的setter方法,对UIView的样式进行修改。

    #import <UIKit/UIKit.h>
    
    IB_DESIGNABLE
    /**
     自定义导航栏
     */
    @interface CustomNavi : UIView
    
    /**
     是否需要返回按钮
     */
    @property (nonatomic, assign) IBInspectable BOOL needBackButton;
    /**
     显示的标题
     */
    @property (nonatomic, copy) IBInspectable NSString *title;
    /**
     背景色
     */
    @property (nonatomic, copy) IBInspectable UIColor *bgColor;
    
    @end
    
    // ------------------------- 我是分割线 ------------------------- 
    #import "CustomNavi.h"
    
    @implementation CustomNavi {
        UIButton *_backButton;
        UILabel *_titleLabel;
    }
    
    - (instancetype)initWithCoder:(NSCoder *)aDecoder {
        self = [super initWithCoder:aDecoder];
        if (self) {
            [self initUI];
        }
        return self;
    }
    
    - (instancetype)initWithFrame:(CGRect)frame {
        self = [super initWithFrame:frame];
        if (self) {
            [self initUI];
        }
        return self;
    }
    
    /**
     初始化,代码创建标题Label
     */
    - (void)initUI {
        _titleLabel = [[UILabel alloc] init];
        [self addSubview:_titleLabel];
    }
    
    
    /**
     设置标题,居中显示
    
     @param title 标题
     */
    - (void)setTitle:(NSString *)title {
        [_titleLabel setText:title];
        [_titleLabel sizeToFit];
        CGFloat screenWidth = [UIScreen mainScreen].bounds.size.width;
        _titleLabel.center = CGPointMake(screenWidth/2.0f, 22);
    }
    
    /**
     设置是否需要返回按钮
     */
    - (void)setNeedBackButton:(BOOL)needBackButton {
        if (needBackButton) {
            self.backButton.hidden = !needBackButton;
        } else {
            _backButton.hidden = !needBackButton;
        }
    }
    
    /**
     懒加载方式创建返回按钮
     */
    - (UIButton *)backButton {
        if (_backButton == nil) {
            _backButton = [UIButton buttonWithType:UIButtonTypeCustom];
            _backButton.frame = CGRectMake(8, 6, 28, 28);
            [_backButton setTitle:@"<" forState:UIControlStateNormal];
            [self addSubview:_backButton];
        }
        return _backButton;
    }
    
    /**
     设置背景颜色
     */
    - (void)setBgColor:(UIColor *)bgColor {
        self.backgroundColor = bgColor;
    }
    
    @end
    

    XIB创建UIView方式2

    XIB创建UIView除了上面的方法外,还有一种方式。

    1. 创建XIB文件,创建Class文件,两个文件名随意,可以相同也可以不相同。
    2. 选择XIB的File's Owner,设置Class为创建的Class文件名。
    3. 在Class中定义一个IBOutlet的view,将XIB中的View连线至这个IBOutlet。
    4. 在XIB中放置控件,并设置autolayout约束,关联代码文件中的IBOutlet和IBAction。
    5. 重写Class中的init方法:
    @interface CustomXibView : UIView
    
    @property (nonatomic, weak) IBOutlet UIView *contentView;
    
    @end
    
    @implementation CustomXibView
    
    - (instancetype)initWithCoder:(NSCoder *)coder {
        self = [super initWithCoder:coder];
        if (self) {
            [self commonInit];
        }
        return self;
    }
    
    - (instancetype)initWithFrame:(CGRect)frame {
        self = [super initWithFrame:frame];
        if (self) {
            [self commonInit];
        }
        return self;
    }
    
    - (void)commonInit {
        // 这里因为与XIB名字相同,所以使用[self class]
        [[NSBundle mainBundle] loadNibNamed:NSStringFromClass([self class]) owner:self options:nil];
        [self addSubview:self.contentView];
        self.contentView.frame = self.bounds;
        // 把内容放到最下面
        [self sendSubviewToBack:self.contentView];
    }
    

    参考链接:Creating a Custom View using a xib in Objective-C

    这种方式创建的UIView其实外面会套个壳,frame修改的时候需要同步到contentView,但是优点是可以同时在存代码和XIB中使用。

    相关文章

      网友评论

          本文标题:iOS自定义UIView

          本文链接:https://www.haomeiwen.com/subject/mplhkctx.html