Мой пользовательский UIButton не может быть использован для замены leftBarButtonItem - PullRequest
0 голосов
/ 22 марта 2019

Я создал пользовательское подклассификацию UIButton из UIControl (он называется "OZCustomButton"). Он отлично работает в раскадровке, однако, когда я пытался использовать его для программной замены кнопки возврата leftBarButtonItem, возникла проблема с его расположением.

Вот код, который я использую для замены leftBarButtonItem.

OZCustomButton *customBackButton = [[OZCustomButton alloc] initWithFrame:CGRectZero];
customBackButton.buttonImage = [UIImage imageNamed:@"BackArrow"];
customBackButton.buttonText = @"Back";
[customBackButton sizeToFit];  

NSLog(@"this size: %@", NSStringFromCGRect(customBackButton.frame));

UIBarButtonItem *item = [[UIBarButtonItem alloc] initWithCustomView:customBackButton];
self.navigationItem.leftBarButtonItem = item;

Но в левой части панели навигации ничего не отображается.

Панель навигации:

Navigation bar

И инструмент Dubug View Hierarchy показывает следующие предупреждающие сообщения:

Warning error 1

Warning error 2

Кажется, что customBackButton находится в иерархии представлений, но компоновка неверна.

Это код моего OZCustomButton.

OZCustomButton.h:

#import <UIKit/UIKit.h>

NS_ASSUME_NONNULL_BEGIN

IB_DESIGNABLE
@interface OZCustomButton : UIControl <NSCoding>

@property (assign, nonatomic) IBInspectable CGFloat borderWidth;
@property (assign, nonatomic) IBInspectable CGFloat borderRadius;
@property (strong, nonatomic) IBInspectable UIColor *borderColor;
@property (strong, nonatomic) IBInspectable UIColor *fillColor;
@property (strong, nonatomic) IBInspectable UIColor *tintColor;

@property (strong, nonatomic) IBInspectable NSString *buttonText;
@property (assign, nonatomic) IBInspectable CGFloat textSize;
@property (assign, nonatomic) IBInspectable BOOL isTextBold;
@property (strong, nonatomic) UIFont *textFont;

@property (nullable, strong, nonatomic) IBInspectable UIImage *buttonImage;
@property (nullable, strong, nonatomic) NSArray *gradientColors;

@end

NS_ASSUME_NONNULL_END

OZCustomButton.m

#import "OZCustomButton.h"
#import "UIColor+Custom.h"
#import "CAGradientLayer+Utilities.h"

@interface OZCustomButton ()

@property (strong, nonatomic) UILabel *buttonLabel;
@property (nullable, strong, nonatomic) UIImageView *buttonImageView;
@property (nullable, strong, nonatomic) CAGradientLayer *gradientLayer;
@property (nullable, strong, nonatomic) UIStackView *stackView;

@end

@implementation OZCustomButton

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

- (instancetype)initWithCoder:(NSCoder *)aDecoder {
    self = [super initWithCoder:aDecoder];
    if (self) {
        [self setupDefaults];
    }
    return self;
}

- (void)layoutLabelAndImageView {
    _buttonLabel = [[UILabel alloc] initWithFrame:CGRectZero];
    _buttonLabel.numberOfLines = 1; // need to set to 1
    _buttonLabel.textAlignment = NSTextAlignmentCenter;
    //_buttonLabel.backgroundColor = [UIColor redColor];

    _buttonImageView = [[UIImageView alloc] initWithFrame:CGRectZero];
    _buttonImageView.contentMode = UIViewContentModeScaleAspectFit;
    //_buttonImageView.backgroundColor = [UIColor redColor];

    _stackView = [[UIStackView alloc] init];
    _stackView.axis = UILayoutConstraintAxisHorizontal;
    _stackView.alignment = UIStackViewAlignmentCenter;
    _stackView.distribution = UIStackViewDistributionFillProportionally;
    _stackView.spacing = 8;
    _stackView.userInteractionEnabled = NO;
    [_stackView addArrangedSubview:_buttonImageView];
    [_stackView addArrangedSubview:_buttonLabel];
    _stackView.translatesAutoresizingMaskIntoConstraints = false;
    [self addSubview:_stackView];
    [[_stackView.centerXAnchor constraintEqualToAnchor:self.centerXAnchor] setActive:YES];
    [[_stackView.centerYAnchor constraintEqualToAnchor:self.centerYAnchor] setActive:YES];
}

- (void)layoutGradientLayer {
    _gradientLayer = [CAGradientLayer createGradientLayerWithBounds:self.bounds
                                                             colors:nil
                                                          direction:GradientFromLeftTopToRightBottom
                                                          locations:@[@0.0, @1.0]];
    _gradientLayer.anchorPoint = CGPointMake(0, 0);
    [self.layer insertSublayer:_gradientLayer below:_stackView.layer];
}

- (void)setupDefaults {
    _borderWidth = 0.0f;
    _borderRadius = 0.0f;
    _borderColor = [UIColor blackColor];
    _fillColor = [UIColor whiteColor];
    _buttonText = @"Button";
    _tintColor = [UIColor blackColor];
    _textSize = 17.0f;
    _isTextBold = false;
    _textFont = _isTextBold ? [UIFont fontWithName:@"AlteHaasGrotesk_Bold" size:_textSize] : [UIFont fontWithName:@"AlteHaasGrotesk" size:_textSize];
    _gradientColors = nil;
    _buttonImage = nil;
    [self layoutLabelAndImageView];
    [self updateView];
}

- (void)updateView {
    self.layer.borderColor = _borderColor.CGColor;
    self.layer.borderWidth = _borderWidth;
    self.layer.cornerRadius = _borderRadius;
    self.layer.masksToBounds = true;
    self.layer.backgroundColor = _fillColor.CGColor;

    // update button text label
    _buttonLabel.text = _buttonText;
    _buttonLabel.textColor = _tintColor;
    _textFont = _isTextBold ? [UIFont fontWithName:@"AlteHaasGrotesk_Bold" size:_textSize] : [UIFont fontWithName:@"AlteHaasGrotesk" size:_textSize];
    _buttonLabel.font = _textFont;
    _buttonLabel.textAlignment = NSTextAlignmentCenter;
    [_buttonLabel sizeToFit];

    // update button image
    if (_buttonImage != nil) {
        _buttonImageView.hidden = NO;
        _buttonImageView.image = [_buttonImage imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
        _buttonImageView.tintColor = _tintColor;
        [_buttonImageView sizeToFit];
    } else {
        _buttonImageView.image = nil;
        _buttonImageView.hidden = YES;
        [_buttonImageView sizeToFit];
    }

    // update gradient layer
    if (_gradientColors != nil) {
        // if gradient layer is not initialized, call layoutGradientLayer()
        if (_gradientLayer == nil) {
            [self layoutGradientLayer];
        }
        // transform the UIColor to CGColorRef
        NSMutableArray *colors = [NSMutableArray arrayWithCapacity:_gradientColors.count];
        for (UIColor *color in _gradientColors) {
            [colors addObject:(id)[color CGColor]];
        }
        if (colors.count > 0) {
            _gradientLayer.colors = [colors copy];
        }
    }
}

#pragma mark - setters

- (void)setTextSize:(CGFloat)textSize {
    if (_textSize != textSize) {
        _textSize = textSize;
        _textFont = _isTextBold ? [UIFont fontWithName:@"AlteHaasGrotesk_Bold" size:_textSize] : [UIFont fontWithName:@"AlteHaasGrotesk" size:_textSize];
        [self updateView];
    }
}

- (void)setBorderColor:(UIColor *)borderColor {
    if (_borderColor != borderColor) {
        _borderColor = borderColor;
        [self updateView];
    }
}

- (void)setBorderWidth:(CGFloat)borderWidth {
    if (_borderWidth != borderWidth) {
        _borderWidth = borderWidth;
        [self updateView];
    }
}

- (void)setBorderRadius:(CGFloat)borderRadius {
    if (_borderRadius != borderRadius) {
        _borderRadius = borderRadius;
        [self updateView];
    }
}

- (void)setFillColor:(UIColor *)fillColor {
    if (_fillColor != fillColor) {
        _fillColor = fillColor;
        [self updateView];
    }
}


- (void)setTintColor:(UIColor *)tintColor {
    if (_tintColor != tintColor) {
        _tintColor = tintColor;
        [self updateView];
    }
}

- (void)setButtonText:(NSString *)buttonText {
    if (_buttonText != buttonText) {
        _buttonText = buttonText;
        [self updateView];
    }
}

- (void)setTextFont:(UIFont *)textFont {
    if (_textFont != textFont) {
        _textFont = textFont;
        [self updateView];
    }
}

- (void)setGradientColors:(NSArray *)gradientColors {
    if (_gradientColors != gradientColors) {
        _gradientColors = gradientColors;
        [self updateView];
    }
}

- (void)setButtonImage:(UIImage *)buttonImage {
    if (_buttonImage != buttonImage) {
        _buttonImage = buttonImage;
        [self updateView];
    }
}

- (void)setIsTextBold:(BOOL)isTextBold {
    if (_isTextBold != isTextBold) {
        _isTextBold = isTextBold;
        [self updateView];
    }
}

#pragma mark - UIControl actions

- (void)setHighlighted:(BOOL)highlighted {
    [super setHighlighted:highlighted];
    CABasicAnimation *fadeAnimation = [CABasicAnimation animationWithKeyPath:@"opacity"];
    fadeAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut];
    fadeAnimation.duration = 0.2f;
    if (highlighted) {
        fadeAnimation.toValue = @0.6f;
    } else {
        fadeAnimation.toValue = @1.0f;
    }

    self.buttonLabel.layer.opacity = [fadeAnimation.toValue floatValue];
    self.layer.opacity = [fadeAnimation.toValue floatValue];
    [self.buttonLabel.layer addAnimation:fadeAnimation forKey:@"textFadeAnimation"];
    [self.layer addAnimation:fadeAnimation forKey:@"backgroundFadeAnimation"];
}

- (void)setEnabled:(BOOL)enabled {
    [super setEnabled:enabled];

    if (enabled) {
        self.layer.backgroundColor = self.fillColor.CGColor;
        self.buttonLabel.textColor = self.tintColor;
    } else {
        self.layer.backgroundColor = [UIColor lighterColorForColor:self.fillColor].CGColor;
        self.buttonLabel.textColor = [UIColor lightGrayColor];
    }
}

#pragma mark - Override functions
- (void)layoutSubviews {
    [super layoutSubviews];
    [self updateView];
}

- (CGSize)sizeThatFits:(CGSize)size {
    CGFloat minWidth = _buttonImageView.frame.size.width + 8 + _buttonLabel.frame.size.width;
    CGFloat minHeight = MAX(_buttonImageView.frame.size.height, _buttonLabel.frame.size.height);
    return CGSizeMake(minWidth + 6, minHeight + 4);
}

@end

1 Ответ

0 голосов
/ 23 марта 2019

Я нашел одно решение. Вместо установки привязки centenX и привязки centerY, я изменяю ее на использование левой, правой, верхней и нижней привязок:

[[_stackView.topAnchor constraintEqualToAnchor:_stackView.superview.topAnchor] setActive:YES];
[[_stackView.bottomAnchor constraintEqualToAnchor:_stackView.superview.bottomAnchor] setActive:YES];
[[_stackView.leftAnchor constraintEqualToAnchor:_stackView.superview.leftAnchor] setActive:YES];
[[_stackView.rightAnchor constraintEqualToAnchor:_stackView.superview.rightAnchor] setActive:YES];

Тогда он получил правильное расположение.

Если у вас есть другие способы решения проблемы, пожалуйста, дайте мне знать.

...