#概要
iOSのtabはbadge表示できるが、UIViewにはbadgeのAPIがないので、core animation使って簡単に作ってみました。
CAShapeLayer で丸い円をbadgeの円を描く. CATextLayerで数字を表示するだけ。badgeNumberを0に設定した時に
fade out効果もつけました
#code
UIView+Badge.h
@interface UIView (Badge)
/**
* viewにbadgeを追加する 0<badgeNumber<=99
* 注:0は表示しない.最大99まで表示、99超えた場合は99を表示する
*/
- (void)setBadgeNumber:(NSUInteger)badgeNumber;
@end
UIView+Badge.m
#import "UIView+Badge.h"
#import <objc/runtime.h>
static CGFloat const adjustPosition = 0.2f;
static CGFloat const kBorderWidth = 1;
static CGFloat const kBackgroundCircleWidth = 20;
static CGFloat const kCircleCornerRadius = 100;
static CGFloat const kBadgeFontSize = 15;
static NSUInteger const kBadgeNumberLimit = 99;
static const char *kUIViewBadgeLayerKey = "UIViewBadgeLayerKey";
static const char *kUIViewBadgeTextLayerKey = "UIViewBadgeTextLayerKey";
@implementation UIView (Badge)
- (void)setBadgeNumber:(NSUInteger)badgeNumber {
if (badgeNumber == 0) { // badge layerを削除
[self p_deleteBadgeLayers];
return;
}
CATextLayer *badgeTextLayer = [self p_badgeTextLayer];
if (!badgeTextLayer) {
[self p_configureBadgeLayers];
badgeTextLayer = [self p_badgeTextLayer];
}
badgeNumber = MIN(badgeNumber, kBadgeNumberLimit);
badgeTextLayer.string = @(badgeNumber).stringValue;
}
- (void)p_configureBadgeLayers {
// badgeのborder layer 生成
CAShapeLayer *borderLayer = [CAShapeLayer layer];
borderLayer.bounds = CGRectMake(0, 0, kBorderWidth, kBorderWidth);
// view内の位置調整
borderLayer.path = [UIBezierPath bezierPathWithRoundedRect:borderLayer.bounds
cornerRadius:kCircleCornerRadius].CGPath;
borderLayer.fillColor = [UIColor blackColor].CGColor;
// badgeの丸いbackground layer生成
CAShapeLayer *backgroundLayer = [CAShapeLayer layer];
backgroundLayer.bounds = CGRectMake(0, 0, kBackgroundCircleWidth, kBackgroundCircleWidth);
backgroundLayer.path = [UIBezierPath bezierPathWithRoundedRect:backgroundLayer.bounds
cornerRadius:kCircleCornerRadius].CGPath;
backgroundLayer.fillColor = [UIColor redColor].CGColor;
// badge数字を表示するためのtext layer生成
CATextLayer *textLayer = [CATextLayer layer];
textLayer.frame = backgroundLayer.frame;
textLayer.contentsScale = [UIScreen mainScreen].scale;
textLayer.wrapped = YES;
UIFont *font = [UIFont systemFontOfSize:kBadgeFontSize];
CGFontRef fontRef = CGFontCreateWithFontName((__bridge CFStringRef)font.fontName);
textLayer.font = fontRef;
CFRelease(fontRef);
textLayer.fontSize = font.pointSize;
textLayer.alignmentMode = kCAAlignmentCenter;
CALayer *badgeLayer = [CALayer layer];
badgeLayer.bounds = CGRectMake(0, 0, kBorderWidth, kBorderWidth);
// view内の位置調整
CGFloat positionAdjustment = adjustPosition * self.frame.size.width;
badgeLayer.position = CGPointMake(self.frame.size.width - positionAdjustment, positionAdjustment);
[badgeLayer addSublayer:borderLayer];
[badgeLayer addSublayer:backgroundLayer];
[badgeLayer addSublayer:textLayer];
[self.layer addSublayer:badgeLayer];
[self p_setBadgeLayer:badgeLayer];
[self p_setBadgeTextLayer:textLayer];
}
- (void)p_deleteBadgeLayers {
if ([self p_badgeLayer]) {
CALayer *badgeLayer = [self p_badgeLayer];
CABasicAnimation *opacityAnimation = [CABasicAnimation animationWithKeyPath:@"opacity"];
[opacityAnimation setToValue:[NSNumber numberWithFloat:0.0]];
[opacityAnimation setFromValue:[NSNumber numberWithFloat:1.0]];
[opacityAnimation setDuration:0.2];
[opacityAnimation setTimingFunction:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn]];
opacityAnimation.delegate = self;
badgeLayer.opacity = 0.0;
[badgeLayer addAnimation:opacityAnimation forKey:@"opacityAnimation"];
}
}
- (void)p_setBadgeLayer:(CALayer *)badgeLayer {
objc_setAssociatedObject(self, kUIViewBadgeLayerKey, badgeLayer, OBJC_ASSOCIATION_ASSIGN);
}
- (CALayer *)p_badgeLayer {
return objc_getAssociatedObject(self, kUIViewBadgeLayerKey);
}
- (void)p_setBadgeTextLayer:(CATextLayer *)badgeTextLayer {
objc_setAssociatedObject(self, kUIViewBadgeTextLayerKey, badgeTextLayer, OBJC_ASSOCIATION_ASSIGN);
}
- (CATextLayer *)p_badgeTextLayer {
return objc_getAssociatedObject(self, kUIViewBadgeTextLayerKey);
}
#pragma mark - CAAnimation delegate
- (void)animationDidStop:(CAAnimation *)animation finished:(BOOL)flag {
CALayer *badgeLayer = [self p_badgeLayer];
[badgeLayer removeFromSuperlayer];
[self p_setBadgeLayer:nil];
[self p_setBadgeTextLayer:nil];
}
@end