I created a custom UIButton subclassing from UIControl (It is called "OZCustomButton"). It works fine in Storyboard, however when I was trying to use it to replace the leftBarButtonItem back button programmatically, it had a problem with its layout.
Here is the code I use to replace the 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;
But nothing is showing on the left side of the navigation bar.
Navigation bar:
And the Dubug View Hierarchy tool shows these warning messages:
It seems the customBackButton is in the View Hierarchy, but the layout is not correct.
This is the code for my 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
I found one solution. Instead of setting the centenX anchor and centerY anchor, I change it to using left, right, top and bottom anchors:
[[_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];
Then it got the layout correctly.
If you have any other methods to solve the problem, please let me know.
Related
I have a custom CALayer within which I'm trying to enable the animation of certain properties using actionForKey and following this tutorial.
I have a CGFloat property that will change perfectly when inside an animation block but my other property, a UIColor, will not.
Here's my function:
- (id<CAAction>)actionForKey:(NSString *)event {
if ([self presentationLayer] != nil && [[self class] isCustomAnimationKey:event]) {
id animation = [super actionForKey:#"backgroundColor"];
if (animation == nil || [animation isEqual:[NSNull null]]) {
[self setNeedsDisplay];
return [NSNull null];
}
[animation setKeyPath:event];
[animation setFromValue:[self.presentationLayer valueForKey:event]];
[animation setToValue:nil];
return animation;
}
return [super actionForKey:event];
}
The colour is being set using CGContextSetFillColorWithColor but I can see from logs that the colour simply changes from one to the next without any of the interpolated values.
Any ideas?
It turned out to be obvious in the end, I needed to expose a CGColor property in my CALayer and animate that instead.
Edit:
Here's some code for this, using the UIViewCustomPropertyAnimation project as a basis.
In OCLayer.h add a new property:
#property (nonatomic) CGColorRef myColor;
In OCLayer.m add the #dynamic directive:
#dynamic myColor;
And update isCustomAnimKey:
+ (BOOL)isCustomAnimKey:(NSString *)key {
return [key isEqualToString:#"percent"] || [key isEqualToString:#"myColor"];
}
In OCView.h add the same property but as a UIColor. This already existed in my project so didn't require modification, which is great because it didn't break any code.
#property (nonatomic, strong) UIColor *progressColor;
The main changes would be in OCView.m as the getter and setter need to convert from CGColor to UIColor and back again.
- (void)setMyColor:(UIColor *)color {
self.layer.myColor = color.CGColor;
}
- (UIColor*)myColor {
return [UIColor colorWithCGColor: self.layer.myColor];
}
The animation can now be carried out as normal:
[UIView animateWithDuration:1.f animations:^{
self.animView.myColor = [UIColor redColor];
}];
This is my code and not an answer. There are three classes: OCLayer, OCView and OCViewController. You can see the value of "percent" is changing during animation while the value of "myColor" won't.
#interface OCLayer : CALayer
#property (nonatomic) CGFloat percent;
#property (nonatomic) CGColorRef myColor;
#end
#import "OCLayer.h"
#implementation OCLayer
#dynamic percent;
#dynamic myColor;
- (id<CAAction>)actionForKey:(NSString *)key
{
if ([[self class] isCustomAnimKey:key])
{
id animation = [super actionForKey:#"backgroundColor"];
if (animation == nil || [animation isEqual:[NSNull null]])
{
[self setNeedsDisplay];
return [NSNull null];
}
[animation setKeyPath:key];
[animation setFromValue: [self.presentationLayer valueForKey:key]];
[animation setToValue : nil];
return animation;
}
return [super actionForKey:key];
}
- (id)initWithLayer:(id)layer
{
self = [super initWithLayer:layer];
if (self)
{
if ([layer isKindOfClass:[OCLayer class]])
{
self.percent = ((OCLayer *)layer).percent;
}
}
return self;
}
+ (BOOL)needsDisplayForKey:(NSString *)key
{
if ([self isCustomAnimKey:key]) return true;
return [super needsDisplayForKey:key];
}
+ (BOOL)isCustomAnimKey:(NSString *)key
{
return [key isEqualToString:#"percent"] || [key isEqualToString:#"myColor"];
}
#end
#interface OCView : UIView
#property (weak, nonatomic) IBOutlet UIView *percentView;
#property (weak, nonatomic) IBOutlet UILabel *label;
#property (nonatomic, strong) UIColor * myColor;
//- (UIColor*)myColor ;
//- (void)setMyColor:(UIColor *)color;
- (CGFloat )percent;
- (void)setPercent:(CGFloat )percent;
#end
#import "OCView.h"
#import "OCLayer.h"
#implementation OCView
- (void)displayLayer:(CALayer *)layer
{
CGFloat percent = [(OCLayer *)[self.layer presentationLayer] percent];
CGColorRef myColor = [(OCLayer *)[self.layer presentationLayer] myColor];
NSLog(#"%f", percent);
NSLog(#"%#", myColor);
self.percentView.backgroundColor = [[UIColor alloc]initWithCGColor: myColor];
self.label.text = [NSString stringWithFormat:#"%.0f", floorf(percent)];
}
+ (Class)layerClass
{
return [OCLayer class];
}
- (void)setPercent:( CGFloat )percent
{
((OCLayer *)self.layer).percent = percent;
}
- (CGFloat )percent
{
return ((OCLayer *)self.layer).percent;
}
- (void)setMyColor:(UIColor *)color {
((OCLayer *)self.layer).myColor = color.CGColor;
}
- (UIColor*)myColor {
return [UIColor colorWithCGColor: ((OCLayer *)self.layer).myColor];
}
#end
#interface OCViewController : UIViewController
#property (weak, nonatomic) IBOutlet OCView *animView;
#end
#import "OCViewController.h"
#import "OCLayer.h"
#interface OCViewController ()
#end
#implementation OCViewController
-(void)viewDidAppear:(BOOL)animated{
[super viewDidAppear:animated];
self.animView.percent = 1;
self.animView.myColor = [UIColor whiteColor];
[UIView animateWithDuration:3.0
animations:^{
self.animView.percent = 20;
self.animView.myColor = [UIColor redColor];
}];
}
- (void)viewDidLoad {
[super viewDidLoad];
}
#end
I have 4 screens that have one almost the same view:
And one screen have the same view but with slightly different UI:
So, my question: Can I use one xib and adapt states (active, inactive) and change ui for different screen? How I can do it?
Here is an example of this kind of class
In Your .m file of custom XIB class if you are using objective-c.
- (void)foo:(NSString*)labelText andButtonText:(NSString*)buttonTitle {
//Do your code here for some screen like change labels and button text
}
- (void)bar:(NSString*)labelText andButtonText:(NSString*)buttonTitle {
//Do your code here for some another screen and change labels and button text
}
In Your .h file of custom XIB class if you are using objective-c.
- (void)foo:(NSString*)labelText andButtonText:(NSString*)buttonTitle;
- (void)bar:(NSString*)labelText andButtonText:(NSString*)buttonTitle;
In your view controller where you want to display the custom UI
Create an instance of your xib or add through interfacebuilder
And On your instance of custom class call the method as required.
Below is a class I've used in one of my project to get a clear understanding.
#import <UIKit/UIKit.h>
#import "DYRateView.h"
#interface LevelAndRankDetails : UIView
#property (nonatomic, strong) IBOutlet UIView* contentView;
#property (nonatomic, strong) IBOutlet UIView* viewContainer;
#property (nonatomic, strong) IBOutlet UILabel* lblLevel;
#property (nonatomic, strong) IBOutlet UILabel* lblRanking;
#property (weak, nonatomic) IBOutlet DYRateView *viewRate;
- (void)setLevel:(NSNumber*)level andRanking:(NSNumber*)ranking;
- (void)setupUI;
#end
.m File
#import "LevelAndRankDetails.h"
#import "AppDelegate.h"
#import "Constants.h"
#implementation LevelAndRankDetails
/*
// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
- (void)drawRect:(CGRect)rect {
// Drawing code
}
*/
- (id)initWithFrame:(CGRect)frame {
if (self = [super initWithFrame:frame]){
[self commonSetup];
}
return self;
}
-(id)initWithCoder:(NSCoder *)aDecoder
{
self = [super initWithCoder:aDecoder];
if (self)
{
[self commonSetup];
}
return self;
}
- (void)layoutSubviews {
[super layoutSubviews];
}
- (void)viewFromNibForClass {
[[NSBundle mainBundle] loadNibNamed:[[self class] description] owner:self options:nil];
[self addSubview:self.contentView];
self.contentView.frame = self.bounds;
}
- (void)commonSetup {
[self viewFromNibForClass];
//For View's Corner Radius
self.contentView.layer.cornerRadius = 12;
self.contentView.layer.masksToBounds = YES;
self.contentView.backgroundColor = kDefaultBackgroundGreyColor;
self.viewContainer.backgroundColor = kDefaultBackgroundGreyColor;//[UIColor clearColor];
self.backgroundColor = kDefaultBackgroundGreyColor;
//self.viewContainer.backgroundColor = UIColorFromRGB(0xBB9657);//[kLearnFromLightColor colorWithAlphaComponent:0.5];
self.viewRate.rate = 0;
self.viewRate.editable = NO;
self.viewRate.delegate = nil;
self.viewRate.alignment = RateViewAlignmentCenter;
self.viewRate.backgroundColor = [UIColor clearColor];
[self.viewRate setEmptyStarImage:[UIImage imageNamed:#"StarEmpty"]];
UIImage* imageFullStar = [[UIImage imageNamed:#"StarFull"] imageTintedWithColor:kSliderDarkYellowColor];
[self.viewRate setFullStarImage:imageFullStar];
self.lblLevel.textColor = [UIColor whiteColor];
self.lblRanking.textColor = [UIColor whiteColor];
//For Teacher label
}
- (void)setupUI {
self.contentView.layer.cornerRadius = 0;
self.contentView.layer.masksToBounds = YES;
self.contentView.backgroundColor = [UIColor clearColor];
self.viewContainer.backgroundColor = [UIColor clearColor];//[UIColor clearColor];
self.backgroundColor = [UIColor clearColor];
}
- (void)setRanking:(CGFloat)ranking {
self.viewRate.rate = ranking;
}
- (void)setLevel:(NSNumber*)level {
self.lblLevel.text = [NSString stringWithFormat:#"Level : %#",level];
}
- (void)setLevel:(NSNumber*)level andRanking:(NSNumber*)ranking {
if (level.integerValue > 0) {
[self setLevel:level];
}
if (ranking.doubleValue > 0) {
CGFloat rankingConverted = ranking.floatValue;
[self setRanking:rankingConverted];
}
}
#end
And this is how you use it in your view controller
LevelAndRankDetails* toolTipCustomView = [[LevelAndRankDetails alloc] initWithFrame:CGRectMake(0, 0, 250, 66)];
toolTipCustomView.backgroundColor = [UIColor blackColor];
[toolTipCustomView setLevel:#(10) andRanking:#(3)];
I have added a custom cell as follows for stepper progress. UI perspective, it looks what I want, but I could not able to figure out how I could able to determine whether or not button has been clicked.
I have inspired via https://github.com/yenbekbay/AYStepperView, but this one has PageViewController which I could not able to add it in the tableCell.
#import "StepperProgressTableViewCell.h"
#import "AYStepperView.h"
static CGFloat const kFormStepperViewHeight = 80;
#interface StepperProgressTableViewCell ()
#property (nonatomic) AYStepperView *stepperView;
#property (nonatomic) NSUInteger currentIndex;
#property (nonatomic) NSUInteger currentStep;
#end
#implementation StepperProgressTableViewCell
- (void)awakeFromNib {
[super awakeFromNib];
// Initialization code
[self setUpViews];
self.currentIndex = 0;
self.currentStep = 0;
}
- (void)setSelected:(BOOL)selected animated:(BOOL)animated {
[super setSelected:selected animated:animated];
}
#pragma mark Private
- (void)setUpViews {
self.stepperView = [[AYStepperView alloc]initWithFrame:CGRectMake(0, 40 , self.frame.size.width, kFormStepperViewHeight)
titles:#[NSLocalizedString(#"Start", nil),
NSLocalizedString(#"Cooking", nil),
NSLocalizedString(#"Ready", nil)]];
self.stepperView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleTopMargin;
self.stepperView.userInteractionEnabled = YES;
[self addSubview:self.stepperView];
self.containerView = [[UIView alloc] initWithFrame:CGRectMake(0, CGRectGetMaxY(self.stepperView.frame), CGRectGetWidth(self.bounds), CGRectGetHeight(self.bounds) - CGRectGetMaxY(self.stepperView.frame))];
[self addSubview:self.containerView];
}
#end
AYStepperView.m
#import "AYStepperView.h"
#import <pop/POP.h>
static UIEdgeInsets const kStepperViewPadding = {
15, 0, 15, 0
};
static CGFloat const kStepperLabelsSpacing = 10;
static CGFloat const kStepperPipeHeight = 5;
#interface AYStepperView ()
#property (nonatomic) UIView *pipeView;
#property (nonatomic) UIView *labelsView;
#property (nonatomic) UIView *pipeBackgroundView;
#property (nonatomic) UIView *pipeFillView;
#property (nonatomic) NSMutableArray *stepLabels;
#end
#implementation AYStepperView
#pragma mark Initialization
- (instancetype)initWithFrame:(CGRect)frame titles:(NSArray *)titles {
self = [super initWithFrame:frame];
if (!self) {
return nil;
}
_titles = titles;
self.backgroundColor = [UIColor colorWithRed:0.98f green:0.98f blue:0.98f alpha:1];
self.tintColor = [UIColor colorWithRed:0.2f green:0.29f blue:0.37f alpha:1];
self.pipeView = [[UIView alloc] initWithFrame:CGRectMake(kStepperViewPadding.left, kStepperViewPadding.top, CGRectGetWidth(self.bounds) - kStepperViewPadding.left - kStepperViewPadding.right, CGRectGetHeight(self.bounds) / 2 - kStepperViewPadding.top)];
[self addSubview:self.pipeView];
self.labelsView = [[UIView alloc] initWithFrame:CGRectMake(kStepperViewPadding.left, CGRectGetMaxY(self.pipeView.frame) + kStepperViewPadding.top, CGRectGetWidth(self.bounds) - kStepperViewPadding.left - kStepperViewPadding.right, CGRectGetHeight(self.bounds) / 2 - kStepperViewPadding.top - kStepperViewPadding.bottom)];
[self addSubview:self.labelsView];
self.pipeBackgroundView = [[UIView alloc] initWithFrame:CGRectMake(0, (CGRectGetHeight(self.pipeView.bounds) - kStepperPipeHeight) / 2, CGRectGetWidth(self.pipeView.bounds), kStepperPipeHeight)];
self.pipeBackgroundView.backgroundColor = [UIColor lightGrayColor];
[self.pipeView addSubview:self.pipeBackgroundView];
CGRect pipeFillViewFrame = self.pipeBackgroundView.frame;
pipeFillViewFrame.size.width = 0;
self.pipeFillView = [[UIView alloc] initWithFrame:pipeFillViewFrame];
self.pipeFillView.backgroundColor = self.tintColor;
[self.pipeView addSubview:self.pipeFillView];
_stepButtons = [NSMutableArray new];
_stepLabels = [NSMutableArray new];
for (NSUInteger i = 0; i < titles.count; i++) {
UIButton *stepButton = [[UIButton alloc] initWithFrame:CGRectMake(0, 0, CGRectGetHeight(self.pipeView.bounds), CGRectGetHeight(self.pipeView.bounds))];
stepButton.center = CGPointMake(CGRectGetWidth(self.pipeView.bounds) * (i + 0.5f) / titles.count, stepButton.center.y);
stepButton.clipsToBounds = YES;
stepButton.tag = i;
stepButton.layer.cornerRadius = CGRectGetHeight(stepButton.bounds) / 2;
stepButton.backgroundColor = [UIColor lightGrayColor];
[self.pipeView addSubview:stepButton];
[self.stepButtons addObject:stepButton];
UILabel *stepLabel = [UILabel new];
stepLabel.font = [UIFont systemFontOfSize:[UIFont smallSystemFontSize]];
stepLabel.textColor = self.tintColor;
stepLabel.textAlignment = NSTextAlignmentCenter;
stepLabel.text = titles[i];
stepLabel.numberOfLines = 0;
stepLabel.frame = (CGRect) {
stepLabel.frame.origin, [stepLabel sizeThatFits:CGSizeMake(CGRectGetWidth(self.pipeView.bounds) / titles.count - kStepperLabelsSpacing, 0)]
};
stepLabel.center = CGPointMake(CGRectGetWidth(self.labelsView.bounds) * (i + 0.5f) / titles.count, CGRectGetHeight(self.labelsView.bounds) / 2);
[self.labelsView addSubview:stepLabel];
[self.stepLabels addObject:stepLabel];
}
_currentStepIndex = 0;
[self completeStepAtIndex:0 until:1 completionBlock:nil];
return self;
}
#pragma mark Public
- (void)updateCurrentStepIndex:(NSUInteger)currentStepIndex completionBlock:(void (^)())completionBlock {
if (currentStepIndex >= self.titles.count || currentStepIndex == self.currentStepIndex) {
if (completionBlock) {
completionBlock();
}
} else {
NSUInteger previousStepIndex = self.currentStepIndex;
_currentStepIndex = currentStepIndex;
if ((NSInteger)currentStepIndex - (NSInteger)previousStepIndex > 0) {
[self completeStepAtIndex:previousStepIndex + 1 until:currentStepIndex + 1 completionBlock:completionBlock];
} else {
[self uncompleteStepAtIndex:previousStepIndex until:currentStepIndex - 1 completionBlock:completionBlock];
}
}
}
#pragma mark Setters
- (void)setTintColor:(UIColor *)tintColor {
_tintColor = tintColor;
self.pipeFillView.backgroundColor = tintColor;
for (UILabel *label in self.stepLabels) {
label.textColor = tintColor;
}
[self.stepButtons[self.currentStepIndex] setBackgroundColor:tintColor];
}
#pragma mark Private
- (void)completeStepAtIndex:(NSUInteger)index until:(NSUInteger)until completionBlock:(void (^)())completionBlock {
if (index == until) {
if (completionBlock) {
completionBlock();
}
} else {
[UIView animateWithDuration:0.2f animations:^{
CGRect pipeFillViewFrame = self.pipeFillView.frame;
NSLog(#"%lu, %lu",until, index);
if(index == _titles.count - 1)
{
pipeFillViewFrame.size.width = CGRectGetWidth(self.pipeBackgroundView.bounds) * (index + 1.0f) / self.titles.count;
}
else
{
pipeFillViewFrame.size.width = CGRectGetWidth(self.pipeBackgroundView.bounds) * (index + 0.5f) / self.titles.count;
}
self.pipeFillView.frame = pipeFillViewFrame;
} completion:^(BOOL finishedWidthAnimation) {
[self completeStepAtIndex:index + 1 until:until completionBlock:completionBlock];
UIView *stepButton = self.stepButtons[index];
stepButton.backgroundColor = self.tintColor;
POPSpringAnimation *scaleAnimation = [POPSpringAnimation animationWithPropertyNamed:kPOPLayerScaleXY];
scaleAnimation.velocity = [NSValue valueWithCGSize:CGSizeMake(3.f, 3.f)];
scaleAnimation.toValue = [NSValue valueWithCGSize:CGSizeMake(1.f, 1.f)];
scaleAnimation.springBounciness = 5.f;
[stepButton.layer pop_addAnimation:scaleAnimation forKey:#"scaleAnimation"];
}];
}
}
- (void)uncompleteStepAtIndex:(NSUInteger)index until:(NSUInteger)until completionBlock:(void (^)())completionBlock {
if (index == until) {
if (completionBlock) {
completionBlock();
}
} else {
if (index > until + 1) {
UIView *stepButton = self.stepButtons[index];
stepButton.backgroundColor = [UIColor lightGrayColor];
POPSpringAnimation *scaleAnimation = [POPSpringAnimation animationWithPropertyNamed:kPOPLayerScaleXY];
scaleAnimation.velocity = [NSValue valueWithCGSize:CGSizeMake(3.f, 3.f)];
scaleAnimation.toValue = [NSValue valueWithCGSize:CGSizeMake(1.f, 1.f)];
scaleAnimation.springBounciness = 5.f;
[stepButton.layer pop_addAnimation:scaleAnimation forKey:#"scaleAnimation"];
}
[UIView animateWithDuration:0.2f animations:^{
CGRect pipeFillViewFrame = self.pipeFillView.frame;
pipeFillViewFrame.size.width = CGRectGetWidth(self.pipeBackgroundView.bounds) * (index + 0.5f) / self.titles.count;
self.pipeFillView.frame = pipeFillViewFrame;
} completion:^(BOOL finishedWidthAnimation) {
[self uncompleteStepAtIndex:index - 1 until:until completionBlock:completionBlock];
}];
}
}
#end
If you want to catch events from a cell to the view controller, the simplest way is to create a protocol and set the view controller as the cell's delegate. I'm sure there are many similar questions here that can help you like this one for example.
Interface is define like this
#interface IGLDemoCustomView : UIView
#property (nonatomic, strong) UIImage *image;
#property (nonatomic, strong) NSString *title;
#end
While Implementation file look like this
#interface IGLDemoCustomView ()
#property (nonatomic, strong) UIImageView *imageView;
#property (nonatomic, strong) UILabel *titleLabel
#end
#implementation IGLDemoCustomView
- (instancetype)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
[self commonInit];
}
return self;
}
- (instancetype)initWithCoder:(NSCoder *)aDecoder
{
self = [super initWithCoder:aDecoder];
if (self) {
[self commonInit];
}
return self;
}
- (void)commonInit
{
[self initView];
}
- (void)initView
{
self.layer.borderColor = [UIColor colorWithRed:0.18 green:0.59 blue:0.69 alpha:1.0].CGColor;
self.layer.borderWidth = 2.0;
self.layer.masksToBounds = YES;
self.backgroundColor = [UIColor whiteColor];
self.alpha = 0.8;
UIImageView *imageView = [[UIImageView alloc] init];
imageView.contentMode = UIViewContentModeCenter;
[self addSubview:imageView];
self.imageView = imageView;
UILabel *titleLabel;
self.titleLabel = [[UILabel alloc]init];
titleLabel.center = self.center; // set proper frame for label
[self addSubview:titleLabel];
}
- (void)setImage:(UIImage *)image
{
_image = image;
self.imageView.image = image;
}
- (void)setString:(NSString *)title
{
self.title=title;
self.titleLabel.text = title;
}
- (void)setFrame:(CGRect)frame
{
[super setFrame:frame];
self.imageView.frame = self.bounds;
self.layer.cornerRadius = frame.size.height / 2.0;
}
#end
When i select image from the drop down menu it shows in the menu, but when i select any text from the drop down menu it doesnt show in the drop down list view.
Any clue will be highly appreciated.
Calling and setting string in the view
IGLDropDownItem *menuButton = strongSelf.dropDownMenu.menuButton;
IGLDemoCustomView *buttonView = (IGLDemoCustomView*)menuButton.customView;
buttonView.title = device.name;
You need to set a frame for the label
- (void)setFrame:(CGRect)frame
{
[super setFrame:frame];
self.imageView.frame = self.bounds;
self.titleLabel.frame = self.bounds;
self.layer.cornerRadius = frame.size.height / 2.0;
}
If you are expecting the text to wrap, you'll need to set the lineBreakMode and set numberOfLines to 0
Like you are having UIImageView you need to have a UILabel inside your UIView too.
#interface IGLDemoCustomView ()
#property (nonatomic, strong) UIImageView *imageView;
#property (nonatomic, strong) UILabel *titleLabel;
#end
- (void)initView
{
self.layer.borderColor = [UIColor colorWithRed:0.18 green:0.59 blue:0.69 alpha:1.0].CGColor;
self.layer.borderWidth = 2.0;
self.layer.masksToBounds = YES;
self.backgroundColor = [UIColor whiteColor];
self.alpha = 0.8;
UIImageView *imageView = [[UIImageView alloc] init];
imageView.contentMode = UIViewContentModeCenter;
[self addSubview:imageView];
self.imageView = imageView;
self.titleLabel = [[UILabel alloc]init];
titleLabel.center = self.center; // set proper frame for label
[self addSubview:titleLabel]
}
And in setString
- (void)setString:(NSString *)title
{
self.title=title;
self.titleLabel.text = title;
}
The problem is that when the button is clicked, it is not updating! it is not hiding or showing the objects like it's written in the code. What am I missing?
viewcontroller.h
#interface ViewController : UIViewController {
BOOL clicked1;
BOOL clicked2;
}
#property (strong, nonatomic) IBOutlet UIImageView *buttonbg1;
#property (strong, nonatomic) IBOutlet UIImageView *buttonbg11;
#property (strong, nonatomic) IBOutlet UIImageView *buttonbg111;
#property (strong, nonatomic) IBOutlet UIButton *exaa1;
#property (strong, nonatomic) IBOutlet UIButton *exab2;
- (IBAction)exaa1:(id)sender;
- (IBAction)exab2:(id)sender;
#end
viewcontroller.m
- (IBAction)exaa1:(id)sender {
clicked1 = YES;
}
- (IBAction)exab2:(id)sender {
clicked2 = YES;
}
- (void)example1 {
[_exaa1 setTitle:#"1111" forState:UIControlStateNormal];
[_exab2 setTitle:#"2222" forState:UIControlStateNormal];
if (clicked1) {
_buttonbg111.hidden = NO;
_buttonbg11.hidden = YES;
_buttonbg1.hidden = YES;
NSLog(#"1");
} else if(clicked2) {
_buttonbg11.hidden = NO;
_buttonbg1.hidden = YES;
_buttonbg111.hidden = YES;
NSLog(#"2");
}
}
*- (IBAction)exaa1:(id)sender {
clicked1 = YES;
[self example1];
}
- (IBAction)exab2:(id)sender {
clicked2 = YES;
[self example1];
}
- (void)example1 {
[_exaa1 setTitle:#"1111" forState:UIControlStateNormal];
[_exab2 setTitle:#"2222" forState:UIControlStateNormal];
if (clicked1) {
_buttonbg111.hidden = NO;
_buttonbg11.hidden = YES;
_buttonbg1.hidden = YES;
NSLog(#"1");
} else if(clicked2) {
_buttonbg11.hidden = NO;
_buttonbg1.hidden = YES;
_buttonbg111.hidden = YES;
NSLog(#"2");
}
}*
You just forget to call your method example1 in your both IBActions Method. YOu just write down [self example1] into both of the IBActions method. And you will get your exact output.
you forgot to call example1 method in both button IBAction methods
Please refer the following corrected code
- (IBAction)exaa1:(id)sender {
clicked1 = YES;
clicked2 = NO;
[self example1];
}
- (IBAction)exab2:(id)sender {
clicked2 = YES;
clicked1 = NO;
[self example1];
}
- (void)example1 {
[_exaa1 setTitle:#"1111" forState:UIControlStateNormal];
[_exab2 setTitle:#"2222" forState:UIControlStateNormal];
if (clicked1) {
_buttonbg111.hidden = NO;
_buttonbg11.hidden = YES;
_buttonbg1.hidden = YES;
NSLog(#"1");
} else if(clicked2) {
_buttonbg11.hidden = NO;
_buttonbg1.hidden = YES;
_buttonbg111.hidden = YES;
NSLog(#"2");
}
}