Используйте пользовательский UIView в качестве IBOutlet в .xib - PullRequest
0 голосов
/ 18 октября 2019

У меня есть пользовательский класс, унаследованный от UIView

@interface StatusBarView : UIView

@property (weak, nonatomic) id <ActivationStatusDelegate> delegate;


//MARK: init
- (id) initWithCustom: (struct WidgetCustom *) widget;
- (id) initWithStatus:(ActivationBtnStatus) activeStatus;

//MARK: Function
- (void) setStatus: (ActivationBtnStatus) status;
@end

, и это является частью реализации

@interface StatusBarView ()
@property (strong, nonatomic) IBOutlet UIButton *button1;
@property (strong, nonatomic) IBOutlet UIButton *button2;

- (void) createDefaultWidget;

@end

@implementation StatusBarView

ActivationBtnStatus status = noStatus;
struct WidgetCustom widget;
bool isWidgetSet = false;
- (void)awakeFromNib {
    [super awakeFromNib];
    if (!isWidgetSet) {
        [self createDefaultWidget];
    }
    [self createButton];
}
- (instancetype)initWithCoder:(NSCoder *)coder
{
    self = [super initWithCoder:coder];
    if (self) {

        [self createDefaultWidget];
        [self createButton];
    }
    return self;
}

- (void)layoutSubviews {
    CAShapeLayer * maskLayer1 = [CAShapeLayer layer];
    maskLayer1.path = [UIBezierPath bezierPathWithRoundedRect: self.bounds byRoundingCorners: UIRectCornerBottomRight | UIRectCornerTopRight cornerRadii: (CGSize){10.0, 10.}].CGPath;
    CAShapeLayer * maskLayer2 = [CAShapeLayer layer];
    maskLayer2.path = [UIBezierPath bezierPathWithRoundedRect: self.bounds byRoundingCorners: UIRectCornerBottomLeft | UIRectCornerTopLeft cornerRadii: (CGSize){10.0, 10.}].CGPath;

    _button1.layer.mask = maskLayer1;
    _button2.layer.mask = maskLayer2;

}


- (id)initWithCustom:(struct WidgetCustom *) widget {
    self = [[[NSBundle mainBundle] loadNibNamed:@"ActivationStatus" owner:nil options:nil] lastObject];

    if (self) {
        isWidgetSet = true;
        widget = widget;
    }

    return self;
}

- (id)initWithStatus:(ActivationBtnStatus)activeStatus {
    self = [[[NSBundle mainBundle] loadNibNamed:@"ActivationStatus" owner:nil options:nil] lastObject];

    if (self) {
        status = activeStatus;
    }

    return self;
}
}

, и именно так я управлял файлом .xib Владельца файлакласс пустой и для этого нет розетки

enter image description here

enter image description here

Розетки подключенывместо этого, и я установил StatusBarView класс для представления файла .xib, как показано ниже

enter image description here

enter image description here

Теперь В другом ViewController я хочу использовать этот класс в качестве IBOutlet, подобного этому, без дополнительной инициализации: enter image description here

, но результат - просто серый вид. Возможно ли такое делать такие вещи? если да, пожалуйста, скажите мне, где я иду не так?

1 Ответ

0 голосов
/ 18 октября 2019

Загрузка пользовательских представлений из XIB не так проста, как кажется. Я создал собственный класс для этого, содержащий несколько удобных методов. Поэтому, чтобы это работало, вы должны позволить своему пользовательскому представлению наследовать от этого класса и установить для него свойство bundle, также по умолчанию имя вашего класса должно совпадать с именем XIB

Interface

#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>

@interface MLSXibLoadingView : UIView

- (instancetype)initWithWidth:(CGFloat)width;

- (instancetype)initWithHeight:(CGFloat)height;

- (instancetype)initWithXibClass:(Class)xibClass;

- (instancetype)initFromXib;

- (instancetype)commonInit;

- (void)setup;

- (void)layoutDone;

- (void)localize;

- (void)update;

- (NSLayoutConstraint *)constraintWithIdentifier:(NSString *)identifier;

- (void)setConstant:(CGFloat)constant forConstraintWithIdentifier:(NSString *)identifier;

@property (nonatomic) NSBundle *bundle;
@property (nonatomic) BOOL layoutIsDone;

@end

Реализация

#import "MLSXibLoadingView.h"


@implementation MLSXibLoadingView

- (instancetype)init
{
    self = [super init];
    if (self) {
        self = [self commonInit];
    }
    return self;
}

- (instancetype)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        self = [self commonInit];
    }
    return self;
}

- (id)awakeAfterUsingCoder:(NSCoder *)aDecoder
{
    if (!self.subviews.count) {
        return [self commonInit];
    }

    return self;
}

- (void)layoutSubviews
{
    [super layoutSubviews];

    if (!_layoutIsDone) {
        _layoutIsDone = YES;
        [self layoutDone];
    }
}

- (instancetype)initWithWidth:(CGFloat)width
{
    self = [self commonInitAssigningFrame:NO];
    self.frame = [MLSUtils rect:self.frame scaledToWidth:width];
    return self;
}

- (instancetype)initWithHeight:(CGFloat)height
{
    self = [self commonInitAssigningFrame:NO];
    self.frame = [MLSUtils rect:self.frame scaledToHeight:height];
    return self;
}

- (instancetype)initWithXibClass:(Class)xibClass
{
    return [self commonInitAssigningFrame:NO xibClass:xibClass];
}

- (instancetype)initFromXib
{
    return [self commonInitAssigningFrame:NO];
}

- (instancetype)commonInit
{
    return [self commonInitAssigningFrame:YES];
}

- (void)setup
{
}

- (void)layoutDone
{
}

- (void)localize
{
}

- (void)update
{
}

- (NSBundle *)bundle
{
    return nil; // implement in subclasses
}

- (instancetype)commonInitAssigningFrame:(BOOL)assignFrame
{
    return [self commonInitAssigningFrame:assignFrame xibClass:self.class];
}

- (instancetype)commonInitAssigningFrame:(BOOL)assignFrame xibClass:(Class)xibClass
{
    NSBundle *b = [self bundle];
    assert(b);

    NSString *xibName = NSStringFromClass(xibClass);
    assert([b pathForResource:xibName ofType:@"nib"]);

    MLSXibLoadingView *xibView = [b loadNibNamed:xibName owner:nil options:nil][0];
    xibView.frame = assignFrame ? self.frame : xibView.frame;
    xibView.autoresizingMask = self.autoresizingMask;
    xibView.translatesAutoresizingMaskIntoConstraints = self.translatesAutoresizingMaskIntoConstraints;

    for (NSLayoutConstraint *constraint in self.constraints) {
        id firstItem = constraint.firstItem;

        if (firstItem == self) {
            firstItem = xibView;
        }

        id secondItem = constraint.secondItem;

        if (secondItem == self) {
            secondItem = xibView;
        }

        NSLayoutConstraint *newConstraint = [NSLayoutConstraint constraintWithItem:firstItem
                                                                         attribute:constraint.firstAttribute
                                                                         relatedBy:constraint.relation
                                                                            toItem:secondItem
                                                                         attribute:constraint.secondAttribute
                                                                        multiplier:constraint.multiplier
                                                                          constant:constraint.constant];

        newConstraint.priority = constraint.priority;
        newConstraint.identifier = constraint.identifier;

        [xibView addConstraint:newConstraint];
    }

    return xibView;
}

- (NSLayoutConstraint *)constraintWithIdentifier:(NSString *)identifier
{
    for (NSLayoutConstraint *constraint in self.constraints) {
        if ([constraint.identifier isEqualToString:identifier]) {
            return constraint;
        }
    }

    return nil;
}

/**
 * Use this method to change constraint constant with given identifier because constraints outlets get invalid
 * after view exchange in commonInitAssigningFrame: method
 */
- (void)setConstant:(CGFloat)constant forConstraintWithIdentifier:(NSString *)identifier
{
    for (NSLayoutConstraint *constraint in self.constraints) {
        if ([constraint.identifier isEqualToString:identifier]) {
            constraint.constant = constant;
            break;
        }
    }
}

@end
...