123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399 |
- //
- // UIBarButtonItem+RQExtension.m
- // RQCommon
- //
- // Created by 张嵘 on 2018/11/16.
- // Copyright © 2018 张嵘. All rights reserved.
- //
- #import "UIBarButtonItem+RQExtension.h"
- #import <objc/runtime.h>
- NSString const *UIBarButtonItem_badgeKey = @"UIBarButtonItem_badgeKey";
- NSString const *UIBarButtonItem_badgeBGColorKey = @"UIBarButtonItem_badgeBGColorKey";
- NSString const *UIBarButtonItem_badgeTextColorKey = @"UIBarButtonItem_badgeTextColorKey";
- NSString const *UIBarButtonItem_badgeFontKey = @"UIBarButtonItem_badgeFontKey";
- NSString const *UIBarButtonItem_badgePaddingKey = @"UIBarButtonItem_badgePaddingKey";
- NSString const *UIBarButtonItem_badgeMinSizeKey = @"UIBarButtonItem_badgeMinSizeKey";
- NSString const *UIBarButtonItem_badgeOriginXKey = @"UIBarButtonItem_badgeOriginXKey";
- NSString const *UIBarButtonItem_badgeOriginYKey = @"UIBarButtonItem_badgeOriginYKey";
- NSString const *UIBarButtonItem_shouldHideBadgeAtZeroKey = @"UIBarButtonItem_shouldHideBadgeAtZeroKey";
- NSString const *UIBarButtonItem_shouldAnimateBadgeKey = @"UIBarButtonItem_shouldAnimateBadgeKey";
- NSString const *UIBarButtonItem_badgeValueKey = @"UIBarButtonItem_badgeValueKey";
- @implementation UIBarButtonItem (RQExtension)
- @dynamic badgeValue, badgeBGColor, badgeTextColor, badgeFont;
- @dynamic badgePadding, badgeMinSize, badgeOriginX, badgeOriginY;
- @dynamic shouldHideBadgeAtZero, shouldAnimateBadge;
- - (void)badgeInit {
- UIView *superview = nil;
- CGFloat defaultOriginX = 0;
- if (self.customView) {
- superview = self.customView;
- defaultOriginX = superview.frame.size.width - self.badge.frame.size.width/2;
- // Avoids badge to be clipped when animating its scale
- superview.clipsToBounds = NO;
- } else if ([self respondsToSelector:@selector(view)] && [(id)self view]) {
- superview = [(id)self view];
- defaultOriginX = superview.frame.size.width - self.badge.frame.size.width;
- }
- [superview addSubview:self.badge];
-
- // Default design initialization
- self.badgeBGColor = [UIColor redColor];
- self.badgeTextColor = [UIColor whiteColor];
- self.badgeFont = [UIFont systemFontOfSize:12.0];
- self.badgePadding = 6;
- self.badgeMinSize = 8;
- self.badgeOriginX = defaultOriginX;
- self.badgeOriginY = -4;
- self.shouldHideBadgeAtZero = YES;
- self.shouldAnimateBadge = YES;
- }
- #pragma mark - Utility methods
- // Handle badge display when its properties have been changed (color, font, ...)
- - (void)refreshBadge {
- // Change new attributes
- self.badge.textColor = self.badgeTextColor;
- self.badge.backgroundColor = self.badgeBGColor;
- self.badge.font = self.badgeFont;
-
- if (!self.badgeValue || [self.badgeValue isEqualToString:@""] || ([self.badgeValue isEqualToString:@"0"] && self.shouldHideBadgeAtZero)) {
- self.badge.hidden = YES;
- } else {
- self.badge.hidden = NO;
- [self updateBadgeValueAnimated:YES];
- }
- }
- - (CGSize) badgeExpectedSize {
- // When the value changes the badge could need to get bigger
- // Calculate expected size to fit new value
- // Use an intermediate label to get expected size thanks to sizeToFit
- // We don't call sizeToFit on the true label to avoid bad display
- UILabel *frameLabel = [self duplicateLabel:self.badge];
- [frameLabel sizeToFit];
-
- CGSize expectedLabelSize = frameLabel.frame.size;
- return expectedLabelSize;
- }
- - (void)updateBadgeFrame {
- CGSize expectedLabelSize = [self badgeExpectedSize];
-
- // Make sure that for small value, the badge will be big enough
- CGFloat minHeight = expectedLabelSize.height;
-
- // Using a const we make sure the badge respect the minimum size
- minHeight = (minHeight < self.badgeMinSize) ? self.badgeMinSize : expectedLabelSize.height;
- CGFloat minWidth = expectedLabelSize.width;
- CGFloat padding = self.badgePadding;
-
- // Using const we make sure the badge doesn't get too smal
- minWidth = (minWidth < minHeight) ? minHeight : expectedLabelSize.width;
- self.badge.layer.masksToBounds = YES;
- self.badge.frame = CGRectMake(self.badgeOriginX, self.badgeOriginY, minWidth + padding, minHeight + padding);
- self.badge.layer.cornerRadius = (minHeight + padding) / 2;
- }
- // Handle the badge changing value
- - (void)updateBadgeValueAnimated:(BOOL)animated {
- // Bounce animation on badge if value changed and if animation authorized
- if (animated && self.shouldAnimateBadge && ![self.badge.text isEqualToString:self.badgeValue]) {
- CABasicAnimation * animation = [CABasicAnimation animationWithKeyPath:@"transform.scale"];
- [animation setFromValue:[NSNumber numberWithFloat:1.5]];
- [animation setToValue:[NSNumber numberWithFloat:1]];
- [animation setDuration:0.2];
- [animation setTimingFunction:[CAMediaTimingFunction functionWithControlPoints:.4f :1.3f :1.f :1.f]];
- [self.badge.layer addAnimation:animation forKey:@"bounceAnimation"];
- }
-
- // Set the new value
- self.badge.text = self.badgeValue;
-
- // Animate the size modification if needed
- if (animated && self.shouldAnimateBadge) {
- [UIView animateWithDuration:0.2 animations:^{
- [self updateBadgeFrame];
- }];
- } else {
- [self updateBadgeFrame];
- }
- }
- - (UILabel *)duplicateLabel:(UILabel *)labelToCopy {
- UILabel *duplicateLabel = [[UILabel alloc] initWithFrame:labelToCopy.frame];
- duplicateLabel.text = labelToCopy.text;
- duplicateLabel.font = labelToCopy.font;
-
- return duplicateLabel;
- }
- - (void)removeBadge {
- // Animate badge removal
- [UIView animateWithDuration:0.2 animations:^{
- self.badge.transform = CGAffineTransformMakeScale(0, 0);
- } completion:^(BOOL finished) {
- [self.badge removeFromSuperview];
- self.badge = nil;
- }];
- }
- #pragma mark - getters/setters
- - (UILabel*)badge {
- UILabel* lbl = objc_getAssociatedObject(self, &UIBarButtonItem_badgeKey);
- if(lbl==nil) {
- lbl = [[UILabel alloc] initWithFrame:CGRectMake(self.badgeOriginX, self.badgeOriginY, 20, 20)];
- [self setBadge:lbl];
- [self badgeInit];
- [self.customView addSubview:lbl];
- lbl.textAlignment = NSTextAlignmentCenter;
- }
- return lbl;
- }
- - (void)setBadge:(UILabel *)badgeLabel {
- objc_setAssociatedObject(self, &UIBarButtonItem_badgeKey, badgeLabel, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
- }
- // Badge value to be display
- - (NSString *)badgeValue {
- return objc_getAssociatedObject(self, &UIBarButtonItem_badgeValueKey);
- }
- - (void) setBadgeValue:(NSString *)badgeValue {
- objc_setAssociatedObject(self, &UIBarButtonItem_badgeValueKey, badgeValue, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
-
- // When changing the badge value check if we need to remove the badge
- [self updateBadgeValueAnimated:YES];
- [self refreshBadge];
- }
- // Badge background color
- - (UIColor *)badgeBGColor {
- return objc_getAssociatedObject(self, &UIBarButtonItem_badgeBGColorKey);
- }
- - (void)setBadgeBGColor:(UIColor *)badgeBGColor {
- objc_setAssociatedObject(self, &UIBarButtonItem_badgeBGColorKey, badgeBGColor, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
- if (self.badge) {
- [self refreshBadge];
- }
- }
- // Badge text color
- - (UIColor *)badgeTextColor {
- return objc_getAssociatedObject(self, &UIBarButtonItem_badgeTextColorKey);
- }
- - (void)setBadgeTextColor:(UIColor *)badgeTextColor {
- objc_setAssociatedObject(self, &UIBarButtonItem_badgeTextColorKey, badgeTextColor, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
- if (self.badge) {
- [self refreshBadge];
- }
- }
- // Badge font
- - (UIFont *)badgeFont {
- return objc_getAssociatedObject(self, &UIBarButtonItem_badgeFontKey);
- }
- - (void)setBadgeFont:(UIFont *)badgeFont {
- objc_setAssociatedObject(self, &UIBarButtonItem_badgeFontKey, badgeFont, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
- if (self.badge) {
- [self refreshBadge];
- }
- }
- // Padding value for the badge
- - (CGFloat)badgePadding {
- NSNumber *number = objc_getAssociatedObject(self, &UIBarButtonItem_badgePaddingKey);
- return number.floatValue;
- }
- - (void)setBadgePadding:(CGFloat)badgePadding {
- NSNumber *number = [NSNumber numberWithDouble:badgePadding];
- objc_setAssociatedObject(self, &UIBarButtonItem_badgePaddingKey, number, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
- if (self.badge) {
- [self updateBadgeFrame];
- }
- }
- // Minimum size badge to small
- - (CGFloat)badgeMinSize {
- NSNumber *number = objc_getAssociatedObject(self, &UIBarButtonItem_badgeMinSizeKey);
- return number.floatValue;
- }
- - (void)setBadgeMinSize:(CGFloat)badgeMinSize {
- NSNumber *number = [NSNumber numberWithDouble:badgeMinSize];
- objc_setAssociatedObject(self, &UIBarButtonItem_badgeMinSizeKey, number, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
- if (self.badge) {
- [self updateBadgeFrame];
- }
- }
- // Values for offseting the badge over the BarButtonItem you picked
- - (CGFloat)badgeOriginX {
- NSNumber *number = objc_getAssociatedObject(self, &UIBarButtonItem_badgeOriginXKey);
- return number.floatValue;
- }
- - (void)setBadgeOriginX:(CGFloat)badgeOriginX {
- NSNumber *number = [NSNumber numberWithDouble:badgeOriginX];
- objc_setAssociatedObject(self, &UIBarButtonItem_badgeOriginXKey, number, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
- if (self.badge) {
- [self updateBadgeFrame];
- }
- }
- - (CGFloat)badgeOriginY {
- NSNumber *number = objc_getAssociatedObject(self, &UIBarButtonItem_badgeOriginYKey);
- return number.floatValue;
- }
- - (void)setBadgeOriginY:(CGFloat)badgeOriginY {
- NSNumber *number = [NSNumber numberWithDouble:badgeOriginY];
- objc_setAssociatedObject(self, &UIBarButtonItem_badgeOriginYKey, number, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
- if (self.badge) {
- [self updateBadgeFrame];
- }
- }
- // In case of numbers, remove the badge when reaching zero
- - (BOOL)shouldHideBadgeAtZero {
- NSNumber *number = objc_getAssociatedObject(self, &UIBarButtonItem_shouldHideBadgeAtZeroKey);
- return number.boolValue;
- }
- - (void)setShouldHideBadgeAtZero:(BOOL)shouldHideBadgeAtZero {
- NSNumber *number = [NSNumber numberWithBool:shouldHideBadgeAtZero];
- objc_setAssociatedObject(self, &UIBarButtonItem_shouldHideBadgeAtZeroKey, number, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
- if(self.badge) {
- [self refreshBadge];
- }
- }
- // Badge has a bounce animation when value changes
- - (BOOL) shouldAnimateBadge {
- NSNumber *number = objc_getAssociatedObject(self, &UIBarButtonItem_shouldAnimateBadgeKey);
- return number.boolValue;
- }
- - (void)setShouldAnimateBadge:(BOOL)shouldAnimateBadge {
- NSNumber *number = [NSNumber numberWithBool:shouldAnimateBadge];
- objc_setAssociatedObject(self, &UIBarButtonItem_shouldAnimateBadgeKey, number, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
- if(self.badge) {
- [self refreshBadge];
- }
- }
- + (UIBarButtonItem *)rq_systemItemWithTitle:(NSString *)title
- titleColor:(UIColor *)titleColor
- imageName:(NSString *)imageName
- target:(id)target
- selector:(SEL)selector
- textType:(BOOL)textType {
- UIBarButtonItem *item = textType ?
- ({
- /// 设置普通状态的文字属性
- item = [[UIBarButtonItem alloc] initWithTitle:title style:UIBarButtonItemStylePlain target:target action:selector];
- titleColor = titleColor?titleColor:[UIColor whiteColor];
- NSMutableDictionary *textAttrs = [NSMutableDictionary dictionary];
- textAttrs[NSForegroundColorAttributeName] = titleColor;
- textAttrs[NSFontAttributeName] = RQRegularFont(16.0f);
- NSShadow *shadow = [[NSShadow alloc] init];
- shadow.shadowOffset = CGSizeZero;
- textAttrs[NSShadowAttributeName] = shadow;
- [item setTitleTextAttributes:textAttrs forState:UIControlStateNormal];
-
- // 设置高亮状态的文字属性
- NSMutableDictionary *highTextAttrs = [NSMutableDictionary dictionaryWithDictionary:textAttrs];
- highTextAttrs[NSForegroundColorAttributeName] = [titleColor colorWithAlphaComponent:.5f];
- [item setTitleTextAttributes:highTextAttrs forState:UIControlStateHighlighted];
-
- // 设置不可用状态(disable)的文字属性
- NSMutableDictionary *disableTextAttrs = [NSMutableDictionary dictionaryWithDictionary:textAttrs];
- disableTextAttrs[NSForegroundColorAttributeName] = [titleColor colorWithAlphaComponent:.5f];
- [item setTitleTextAttributes:disableTextAttrs forState:UIControlStateDisabled];
-
- item;
- }) : ({
- item = [[UIBarButtonItem alloc] initWithImage:[[UIImage imageNamed:imageName] imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal] style:UIBarButtonItemStylePlain target:target action:selector];
- item;
- });
- return item;
- }
- + (UIBarButtonItem *)rq_customItemWithTitle:(NSString *)title
- font:(UIFont *)font
- titleColor:(UIColor *)titleColor
- imageName:(NSString *)imageName
- target:(id)target
- selector:(SEL)selector
- contentHorizontalAlignment:(UIControlContentHorizontalAlignment)contentHorizontalAlignment
- EdgeInsetsStyle:(RQButtonEdgeInsetsStyle)edgeInsetsStyle
- space:(CGFloat)space {
- UIButton *item = [[UIButton alloc] init];
- titleColor = titleColor?titleColor:[UIColor whiteColor];
- [item setTitle:title forState:UIControlStateNormal];
- [item.titleLabel setFont:font];
- [item setTitleColor:titleColor forState:UIControlStateNormal];
- [item setTitleColor:[titleColor colorWithAlphaComponent:.5f] forState:UIControlStateHighlighted];
- [item setTitleColor:[titleColor colorWithAlphaComponent:.5f] forState:UIControlStateDisabled];
- [item sizeToFit];
- if (item.width < 40) {
- item.width = 40;
- }
- item.contentHorizontalAlignment = contentHorizontalAlignment;
- [item addTarget:target action:selector forControlEvents:UIControlEventTouchUpInside];
- BOOL isURL = [NSString rq_isValidURL:imageName];
- if (isURL) {
- [item sd_setImageWithURL:[NSURL URLWithString:imageName] forState:UIControlStateNormal placeholderImage:RQWebAvatarImagePlaceholder() completed:^(UIImage * _Nullable image, NSError * _Nullable error, SDImageCacheType cacheType, NSURL * _Nullable imageURL) {
- if(image) {
- UIImageView *imageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 30, 30)];
- image = [image scaledToSize:CGSizeMake(30, 30)];
- image = [image imageByRoundCornerRadius:15];
- imageView.image = image;
-
- [item setImage:imageView.image forState:UIControlStateNormal];
- [item layoutButtonWithEdgeInsetsStyle:edgeInsetsStyle imageTitleSpace:space];
- }
- }];
- } else {
- [item setImage:[UIImage rq_imageAlwaysShowOriginalImageWithImageName:imageName] forState:UIControlStateNormal];
- [item layoutButtonWithEdgeInsetsStyle:edgeInsetsStyle imageTitleSpace:space];
- }
-
-
- return [[UIBarButtonItem alloc] initWithCustomView:item];
- }
- /// 返回按钮 带箭头的
- + (UIBarButtonItem *)rq_backItemWithTitle:(NSString *)title
- imageName:(NSString *)imageName
- target:(id)target
- action:(SEL)action
- {
- return [self rq_customItemWithTitle:title font:RQRegularFont_13 titleColor:nil imageName:imageName target:target selector:action contentHorizontalAlignment:UIControlContentHorizontalAlignmentLeft EdgeInsetsStyle:RQButtonEdgeInsetsStyleLeft space:0];
- }
- /// 返回按钮 带箭头的
- + (UIBarButtonItem *)rq_backItemWithImageName:(NSString *)imageName
- target:(id)target
- action:(SEL)action
- {
- return [self rq_customItemWithTitle:@"" font:RQRegularFont_13 titleColor:nil imageName:imageName target:target selector:action contentHorizontalAlignment:UIControlContentHorizontalAlignmentLeft EdgeInsetsStyle:RQButtonEdgeInsetsStyleLeft space:0];
- }
- @end
|