我从UIControl创建了一个自定义UIButton子类(称为“ OZCustomButton”)。它在Storyboard中运行良好,但是当我尝试以编程方式使用它来替换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;
但是导航栏的左侧没有任何显示。
导航栏:
Dubug View层次结构工具显示以下警告消息:
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
答案 0 :(得分:0)
我找到了一个解决方案。我没有设置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];
然后正确地获得了布局。
如果您还有其他解决方法,请告诉我。