快兩個月沒寫文章了,說是工作比較忙恩溅,歸根結(jié)底還是懶隔箍,哈哈??。
想開源一個點圖標簽的庫脚乡,但其實沒有必要蜒滩,明白原理,大家都可以動手干的奶稠。文末附筆者自己思路下的Demo俯艰,滿足要求的給個star,直接拿過去用哈锌订。
點圖標簽的實現(xiàn)思路
首先將點圖標簽分為蟆炊,圓,文本瀑志,以及控制的方向涩搓。如下圖
先上效果
實現(xiàn):
一、圓
在初始化時確定圓的大小劈猪,一般的點圖標簽就是圓點和和做動畫的陰影圓昧甘,有的也會有大圓部分,其實就是在圓點下方加一個大圓战得,使其有圓環(huán)的效果充边。
- (void)creatCircleView
{ //circleLayer
CGSize circleSize = self.circleSize;
self.circleLayer =[CALayer new];
self.circleLayer.position = CGPointMake(circleSize.width/2, circleSize.height/2);
self.circleLayer.bounds = CGRectMake(0, 0, circleSize.width, circleSize.height);
self.circleLayer.cornerRadius = circleSize.width/2;
[self.layer addSublayer:self.circleLayer];
//circleView
self.circleView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, circleSize.width, circleSize.height)];
self.circleView.layer.cornerRadius = self.circleView.frame.size.width / 2;
self.circleView.layer.masksToBounds = YES;
self.circleView.center = CGPointMake(10, CGRectGetHeight(self.frame)/2.0);
self.circleLayer.position = self.circleView.center;
//bigCircleView
self.bigCircleView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, circleSize.width+2, circleSize.height+2)];
self.bigCircleView.layer.cornerRadius = self.bigCircleView.frame.size.width / 2;
self.bigCircleView.layer.masksToBounds = YES;
self.bigCircleView.center = CGPointMake(10, CGRectGetHeight(self.frame)/2.0);
[self addSubview:self.bigCircleView];
[self addSubview:self.circleView];
//添加動畫
[self circleAnimation:self.circleLayer];
}
二、 文字
文字部分主要是根據(jù)方向畫出對應(yīng)形狀的
path
(畫path
其實是一件很有意思的事情常侦,建立坐標系浇冰,畫出形狀然后標出關(guān)鍵點,用關(guān)鍵點生成path
即可聋亡,有興趣的可以動手試試哈)肘习,然后利用CAShapeLayer
來生成圖層裁剪UILabel
的layer
。CAShapeLayer
的優(yōu)點這里就不細說了坡倔。
//處理label的形狀
- (void)triangle:(UILabel *)label
{
CGFloat angleWidth = 10;
CGFloat labelCornerRadius = 4;
CGFloat lineCornerRadius = 2;
CGFloat arrowCornerRadious = 1;
UIBezierPath * path = [UIBezierPath new];
switch (self.direction)
{
case YLTagDirectionRight:
[path moveToPoint:( CGPoint ) { labelCornerRadius, 0}];
[path addQuadCurveToPoint:( CGPoint ) {0, labelCornerRadius} controlPoint:( CGPoint ) { 0,0}];
[path addLineToPoint :( CGPoint ) { 0, CGRectGetHeight(label.frame)-labelCornerRadius}];
[path addQuadCurveToPoint:( CGPoint ) {labelCornerRadius, CGRectGetHeight(label.frame)} controlPoint:( CGPoint ) { 0, CGRectGetHeight(label.frame)}];
[path addLineToPoint :( CGPoint ) { CGRectGetWidth(label.frame) - angleWidth-lineCornerRadius, CGRectGetHeight(label.frame)}];
[path addQuadCurveToPoint:( CGPoint ) {CGRectGetWidth(label.frame) - angleWidth+lineCornerRadius, CGRectGetHeight(label.frame)-lineCornerRadius} controlPoint:( CGPoint ) { CGRectGetWidth(label.frame)-angleWidth, CGRectGetHeight(label.frame)}];
[path addLineToPoint :( CGPoint ) { CGRectGetWidth(label.frame)-arrowCornerRadious, CGRectGetHeight(label.frame)/2.0+arrowCornerRadious}];
[path addQuadCurveToPoint:( CGPoint ) {CGRectGetWidth(label.frame)-arrowCornerRadious,CGRectGetHeight(label.frame)/2.0-arrowCornerRadious} controlPoint:( CGPoint ) { CGRectGetWidth(label.frame), CGRectGetHeight(label.frame)/2.0}];
[path addLineToPoint :( CGPoint ) { CGRectGetWidth(label.frame) - angleWidth+lineCornerRadius, lineCornerRadius}];
[path addQuadCurveToPoint:( CGPoint ) {CGRectGetWidth(label.frame) - angleWidth-lineCornerRadius, 0} controlPoint:( CGPoint ) { CGRectGetWidth(label.frame)-angleWidth,0}];
[path addLineToPoint :( CGPoint ) { labelCornerRadius, 0}];
break;
case YLTagDirectionLeft:
default:
[path moveToPoint :( CGPoint ) { angleWidth+lineCornerRadius , 0 }];
[path addQuadCurveToPoint:( CGPoint ) { angleWidth-lineCornerRadius,lineCornerRadius} controlPoint:( CGPoint ) {angleWidth , 0}];
[path addLineToPoint :( CGPoint ) { arrowCornerRadious, CGRectGetHeight(label.frame)/2.0-arrowCornerRadious}];
[path addQuadCurveToPoint:( CGPoint ) {arrowCornerRadious, CGRectGetHeight(label.frame)/2.0+arrowCornerRadious} controlPoint:( CGPoint ) { 0, CGRectGetHeight(label.frame)/2.0}];
[path addLineToPoint :( CGPoint ) { angleWidth-lineCornerRadius, CGRectGetHeight(label.frame)-lineCornerRadius}];
[path addQuadCurveToPoint:( CGPoint ) { angleWidth+lineCornerRadius, CGRectGetHeight(label.frame)} controlPoint:( CGPoint ) { angleWidth, CGRectGetHeight(label.frame)}];
[path addLineToPoint :( CGPoint ) { CGRectGetWidth(label.frame)-labelCornerRadius, CGRectGetHeight(label.frame)}];
[path addQuadCurveToPoint:( CGPoint ) { CGRectGetWidth(label.frame), CGRectGetHeight(label.frame)-labelCornerRadius} controlPoint:( CGPoint ) { CGRectGetWidth(label.frame), CGRectGetHeight(label.frame)}];
[path addLineToPoint :( CGPoint ) { CGRectGetWidth(label.frame), labelCornerRadius}];
[path addQuadCurveToPoint:( CGPoint ) { CGRectGetWidth(label.frame)-labelCornerRadius, 0} controlPoint:( CGPoint ) { CGRectGetWidth(label.frame),0}];
[path addLineToPoint :( CGPoint ) { angleWidth, 0}];
break;
}
CAShapeLayer* mask = [CAShapeLayer layer];
mask.path = path.CGPath ;
label.layer.mask = mask;
}
上面的繪制會引發(fā)一個小問題漂佩,由于UILabel
被裁剪的形狀不規(guī)則,一邊是三角形罪塔,一邊是矩形投蝉,所以就導(dǎo)致了文字在被裁剪的UILabel
中看起來不是居中的,為了解決這個問題就自定了一個UILabel
改變了它的Insets
征堪。
三瘩缆、 方向(邊緣處理)
在點擊屏幕邊緣時需要處理??的方向,比如佃蚜,默認方向為左庸娱,但當點擊屏幕右邊緣時着绊,此時的??是不能默認為左的,此時方向為右涌韩,才能保證??不會超出屏幕畔柔,在拿到
text
之后計算方向即可氯夷。其實就是父視圖邊緣的特殊處理臣樱,此Demo種父視圖與屏幕等寬。當然除此以外還要處理標簽移動時腮考,標簽不會超出屏幕雇毫。
//處理完判斷邊界fram,賦值方向
CGFloat selfW = rect.size.width + CGRectGetWidth(self.bigCircleView.frame) + kSpace;
if (CGRectGetWidth(self.superview.frame)>0)
{
if (self.direction == YLTagDirectionLeft)
{
CGFloat maxX = self.circlePoint.x - CGRectGetWidth(_bigCircleView.frame)/2 + selfW;
if (maxX>self.superview.frame.size.width)
{
self.direction = YLTagDirectionRight;
}
}else
{
CGFloat minX = self.circlePoint.x + CGRectGetWidth(_bigCircleView.frame) - selfW;
if (minX<0)
{
self.direction = YLTagDirectionLeft;
}
}
}
詳細代碼見Demo
點圖標簽的核心就是處理圓點踩蔚,文字和方向三者之間的關(guān)系棚放。其實所有的問題都大同小異,學(xué)會拆分問題馅闽,然后解決問題飘蚯。題外話,哈哈??福也。
照例放Demo局骤,僅供參考,如有問題請留言
Demo地址:
https://github.com/yongliangP/YLTagView 用心良苦請 star
如果你覺得對你有幫助請點 喜歡 哦暴凑,也可以關(guān)注 我峦甩,每周至少一篇技術(shù)(雖然現(xiàn)在不能保證更新量了,但會一直更??)现喳。
或者關(guān)注 我的專題 每周至少5篇更新凯傲,多謝支持哈。