这两天在搞给tabbar或常规控件添加小圆点、数字文本、纯文本的需求。使用了Masnory这个库对常规控件添加约束有一个巨大的坑,就是无法及时获取到常规控件的x和y。但是可以及时获取到常规控件的w和h。
这就导致了如果使用masnory约束之后的控件,无法把什么红点、文字文本、数字文本直接作为子视图添加到目标控件上,列位看官请耐心的看下去。
如果是常规控件的常规操作的话是可以把小红点作为子视图直接添加到目标空间上的,但是在iOS开发中我们经常会遇到常规控件有切圆角等一些操作,尤其是不规则圆角,那么我们使用了UIBezierPath和CAShaperlayer结合的方式对目标控件做了切圆角操作。这就使得目标控件的layer层经过了.mask的操作,对layer层进行了切割,使得目标控件的右上角无法渲染任何子视图。故而我这里无法将之作为子视图直接添加到目标控件上。
于是我们换一个思路,生成一个与目标控件同样大小的view,添加到目标控件的父视图上,把目标控件盖起来,然后,再把小红点什么的添加到新生成的view上。
先来看看效果:
我在这里封装了两个category分别针对tabbar和常规控件
代码如下:
UITabBar+XLRedBadge.h
//
// UITabBar+XLRedBadge.h
// Protostar
//
// Created by 磊怀王 on 2018/12/4.
//
NS_ASSUME_NONNULL_BEGIN
@interface UITabBar (XLRedBadge)
/** 显示小红点
* index 表示这是第几个tabbaritem
*/
- (void)showBadgeOnItemIndex:(int)index;
/**
* 隐藏小红点
* index 表示这是第几个tabbaritem
*/
- (void)hideBadgePointOnItemIndex:(int)index;
/**
* 展示纯数字 文本 提示框
* redNum 数字文本 可以是 : 88 99+ 等
* index 确定是哪个tabbaritem
*/
- (void)showBadgeWithNum:(int)redNum itemInedx:(int)index;
/**
* 隐藏纯数字文本 提示框
*/
- (void)hidenBadgeWithNumItemIndex:(int)index;
/**
* 展示文字文本提示框
* text @"开宝箱" 文本
* index 确定是哪个tabbaritem
*/
- (void)showBadgeWithText:(NSString *)text itemInedx:(int)index;
/**
* 隐藏纯文本本提示框
*/
- (void)hidenBadgeWithTextItemIndex:(int)index;
@end
NS_ASSUME_NONNULL_END
UITabBar+XLRedBadge.m
//
// UITabBar+XLRedBadge.m
// Protostar
//
// Created by 磊怀王 on 2018/12/4.
//
#import "UITabBar+XLRedBadge.h"
//该参数表示 底部有几个tabbaritem
#define TabbarItemNums 3.0
@implementation UITabBar (XLRedBadge)
//显示小红点
- (void)showBadgeOnItemIndex:(int)index{
//移除之前的小红点
[self removeBadgeOnItemIndex:index];
//新建小红点
UIView *badgeView = [[UIView alloc]init];
badgeView.backgroundColor = [UIColor redColor];
badgeView.tag = 888 + index;
CGRect tabFrame = self.frame;
//确定小红点的位置
float percentX = (index + 0.55) / TabbarItemNums;
CGFloat x = ceilf(percentX * tabFrame.size.width);
CGFloat y = ceilf(0.08 * tabFrame.size.height);
badgeView.frame = CGRectMake(x, y, 12, 12);//圆形大小为10
[self addRedPointToTab:badgeView];
[self addSubview:badgeView];
}
//隐藏小红点
- (void)hideBadgePointOnItemIndex:(int)index{
//移除小红点
[self removeBadgeOnItemIndex:index];
}
//移除小红点
- (void)removeBadgeOnItemIndex:(int)index{
//按照tag值进行移除
for (UIView *subView in self.subviews) {
if (subView.tag == 888+index) {
[subView removeFromSuperview];
}
}
}
//展示数字文本
- (void)showBadgeWithNum:(int)redNum itemInedx:(int)index{
UILabel * numLab = [[UILabel alloc] init];
numLab.tag = 999 + index;
CGRect tabFrame = self.frame;
//文本框位置
float percentX = (index + 0.53) / TabbarItemNums;
CGFloat x = ceilf(percentX * tabFrame.size.width);
CGFloat y = ceilf(0.02 * tabFrame.size.height);
numLab.frame = CGRectMake(x, y, 20, 20);//圆形大小为10
[self addSubview:numLab];
[self addTextOfNumToTabbar:@"99+" targetView:numLab];
}
//隐藏数字文本
- (void)hidenBadgeWithNumItemIndex:(int)index{
for (UIView *subView in self.subviews) {
if (subView.tag == 999 + index) {
[subView removeFromSuperview];
}
}
}
//展示文本
- (void)showBadgeWithText:(NSString *)text itemInedx:(int)index{
UILabel * numLab = [[UILabel alloc] init];
numLab.tag = 777 + index;
CGRect tabFrame = self.frame;
//文本框位置
float percentX = (index + 0.55) / TabbarItemNums;
CGFloat x = ceilf(percentX * tabFrame.size.width);
CGFloat y = -8;
numLab.frame = CGRectMake(x, y, 20, 20);//圆形大小为10
[self addSubview:numLab];
[self addTextOfStringToTabbar:@"哈哈哈" targetView:numLab];
}
//隐藏文字文本
- (void)hidenBadgeWithTextItemIndex:(int)index{
for (UIView *subView in self.subviews) {
if (subView.tag == 777 + index) {
[subView removeFromSuperview];
}
}
}
@end
UIView+XLCustomCircularBead.h
//
// UIView+XLCustomCircularBead.h
// goldline
//
// Created by 磊怀王 on 2018/11/29.
// Copyright © 2018 磊怀王. All rights reserved.
//
#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN
@interface UIView (XLCustomCircularBead)
/**
* 设置控件 圆角带边框
* targetview 目标控件
* cornerRadius 圆角尺寸
* borderColor 边框颜色
* borderWidth 边框宽度
*/
- (void)XLCustomCirclarWithBorad:(UIView *)targetView
cornerRadius:(CGFloat)cornerRadius
borderColor:(UIColor *)borderColor
borderWidth:(CGFloat)borderWidth;
/**
* 绘制圆形控件
* targetView 目标控件
* cornerRadius 圆角尺寸
*/
- (void)XLCustomCirclar:(UIView *)targetView;
/**
* 绘制全圆角控件
* targetView 目标控件
* cornerRadius 圆角尺寸
*/
- (void)XLCustomViewAllBeadCircular:(UIView *)targetView
cornerRadius:(CGFloat)cornerRadius;
/**
* 绘制单边圆角
* targetview 目标控件
* cornerRadius 圆角尺寸
* corners 单边类型
*/
- (void)XLCustomViewSingleBeadCircular:(UIView *)targetView
cornerRadius:(CGFloat)cornerRadius
roundingCorners:(UIRectCorner)corners;
/**
* 给tabbar控件添加小红点
* targetview 目标控件
*/
- (void)addRedPointToTab:(UIView *)targetView;
/**
* 给 tabbar 添加 数字文本提示框
* target 目标控件
* text 文本
*/
- (void)addTextOfNumToTabbar:(NSString *)text
targetView:(UILabel *)targetV;
/**
* 给tabbar 添加 文字文本提示框
* target 目标控件
* text 文本
*/
- (void)addTextOfStringToTabbar:(NSString *)text
targetView:(UILabel *)targetV;
/**
* 给常规控件 右上角添加小红点
* targetview 目标控件
* block 需要添加约束的block 注意:该参数使得添加的约束与目标控件的约束一致即可。如果是给button上添加约束则
需使得该block中的button也要实现目标控件的方法。
* 注:移除小红点需要设置目标控件的tag值 小红点以7000作为tag基值,用户使用过程中可随意设置tag值
*/
- (void)addRedPointCionven:(UIView *)targetView
mas_makeConstraints:(void(^)(UIButton * tempV,NSNumber * helfH))block;
/**
* 移除常规控件小红点
* targetV : 目标控件
*/
- (void)removeRedPoint:(UIView *)targetV;
/** 给常规控件 添加纯数字提示框
* numText 可以是任意数字 88 or 99+
* targetV 目标控件
* 需要添加约束的 block
* 注:移除纯数字需要设置目标控件的tag值 小红点以8000作为tag基值,用户使用过程中可随意设置tag值
*/
- (void)addTextOfNumToCionven:(UIView *)targetView
textNum:(NSString *)numText
mas_makeConstraints:(void(^)(UIView * tempV))block;
/**
移除数字文本提示框
@param targetV 目标控件
*/
- (void)removeNumText:(UIView *)targetV;
/**
* 给常规控件 添加纯文本提示框
* targetv 目标控件
* textStr 目标文本
* block 需要添加约束的block 注意:该参数使得添加的约束与目标控件的约束一致即可。如果是给button上添加约束则
需使得该block中的button也要实现目标控件的方法。
注:移除文本需要设置目标控件的tag值 小红点以9000作为tag基值,用户使用过程中可随意设置tag值
*/
- (void)addTextOfStringToCionven:(UIView *)targetV
textString:(NSString *)textStr
mas_makeConstraints:(void(^)(UIButton * tempV,NSNumber * height))block;
/**
移除文本提示框
@param targetV 目标控件
*/
- (void)removeStrText:(UIView *)targetV;
@end
NS_ASSUME_NONNULL_END
UIView+XLCustomCircularBead.m
//
// UIView+XLCustomCircularBead.m
// goldline
//
// Created by 磊怀王 on 2018/11/29.
// Copyright © 2018 磊怀王. All rights reserved.
//
#import "UIView+XLCustomCircularBead.h"
@implementation UIView (XLCustomCircularBead)
- (void)XLCustomViewSingleBeadCircular:(UIView *)targetView cornerRadius:(CGFloat)cornerRadius roundingCorners:(UIRectCorner)corners{
// 创建贝塞尔曲线,指定绘制区域、角和角半径
UIBezierPath *bezierPath = [UIBezierPath bezierPathWithRoundedRect:targetView.bounds byRoundingCorners:corners cornerRadii:CGSizeMake(cornerRadius, cornerRadius)];
// 初始化shapeLayer
CAShapeLayer *shapeLayer = [CAShapeLayer layer];
// 设置绘制路径
shapeLayer.path = bezierPath.CGPath;
// 将shapeLayer设置为targetview的layer的mask(遮罩)
targetView.layer.mask = shapeLayer;
}
- (void)XLCustomViewAllBeadCircular:(UIView *)targetView cornerRadius:(CGFloat)cornerRadius{
// 创建贝塞尔曲线,指定绘制区域、角和角半径
// 绘制4个角,指定角半径
UIBezierPath *bezierPath = [UIBezierPath bezierPathWithRoundedRect:targetView.bounds cornerRadius:cornerRadius];
// 绘制圆
// bezierPath = [UIBezierPath bezierPathWithOvalInRect:imageView2.bounds];
// 初始化shapeLayer
CAShapeLayer *shapeLayer = [CAShapeLayer layer];
// 设置绘制路径
shapeLayer.path = bezierPath.CGPath;
// 将shapeLayer设置为targetview的layer的mask(遮罩)
targetView.layer.mask = shapeLayer;
}
- (void)XLCustomCirclar:(UIView *)targetView{
// 绘制圆
UIBezierPath *bezierPath = [UIBezierPath bezierPathWithOvalInRect:targetView.bounds];
// 初始化shapeLayer
CAShapeLayer *shapeLayer = [CAShapeLayer layer];
// 设置绘制路径
shapeLayer.path = bezierPath.CGPath;
// 将shapeLayer设置为targetview的layer的mask(遮罩)
targetView.layer.mask = shapeLayer;
}
- (void)XLCustomCirclarWithBorad:(UIView *)targetView cornerRadius:(CGFloat)cornerRadius borderColor:(UIColor *)borderColor borderWidth:(CGFloat)borderWidth{
CAShapeLayer *maskLayer = [CAShapeLayer layer];
maskLayer.frame = CGRectMake(0, 0, targetView.frame.size.width, targetView.frame.size.height);
CAShapeLayer *borderLayer = [CAShapeLayer layer];
borderLayer.frame = CGRectMake(0, 0, targetView.frame.size.width, targetView.frame.size.height);
borderLayer.lineWidth = borderWidth;
borderLayer.strokeColor = borderColor.CGColor;
borderLayer.fillColor = [UIColor clearColor].CGColor;
UIBezierPath *bezierPath = [UIBezierPath bezierPathWithRoundedRect:targetView.bounds cornerRadius:cornerRadius];
maskLayer.path = bezierPath.CGPath;
borderLayer.path = bezierPath.CGPath;
[targetView.layer insertSublayer:borderLayer atIndex:0];
[targetView.layer setMask:maskLayer];
}
// 给target添加小红点
- (void)addRedPointToTab:(UIView *)targetView{
UIBezierPath * path = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(0, 0, 10, 10)];
CAShapeLayer * shaperLayer = [CAShapeLayer layer];
shaperLayer.backgroundColor = [UIColor redColor].CGColor;
shaperLayer.path = path.CGPath;
[self addWhiteBorad:targetView bezierPath:path];
targetView.layer.mask = shaperLayer;
}
//给tabbar 添加文本 提示
- (void)addTextOfNumToTabbar:(NSString *)text targetView:(UILabel *)targetV{
targetV.backgroundColor = [UIColor redColor];
targetV.text = text;
targetV.textColor = [UIColor whiteColor];
targetV.font = [UIFont systemFontOfSize:13];
targetV.textAlignment = NSTextAlignmentCenter;
CGSize size = [text sizeWithAttributes:@{NSFontAttributeName:targetV.font}];
targetV.frame = CGRectMake(targetV.frame.origin.x, targetV.frame.origin.y, size.width + 10, CGRectGetHeight(targetV.frame));
[self XLCustomViewAllBeadCircular:targetV cornerRadius:CGRectGetHeight(targetV.frame) / 2];
UIBezierPath *bezierPath = [UIBezierPath bezierPathWithRoundedRect:targetV.bounds cornerRadius:CGRectGetHeight(targetV.frame) / 2];
[self addWhiteBorad:targetV bezierPath:bezierPath];
}
// 给tabbar 添加 文字文本 提示
- (void)addTextOfStringToTabbar:(NSString *)text targetView:(UILabel *)targetV{
targetV.text = text;
targetV.textColor = [UIColor whiteColor];
targetV.font = [UIFont systemFontOfSize:10];
targetV.textAlignment = NSTextAlignmentCenter;
CGSize size = [text sizeWithAttributes:@{NSFontAttributeName:targetV.font}];
targetV.frame = CGRectMake(targetV.frame.origin.x, targetV.frame.origin.y, size.width + 10, CGRectGetHeight(targetV.frame));
CGFloat circelR = CGRectGetHeight(targetV.frame) / 2;
// 创建贝塞尔曲线,指定绘制区域、角和角半径
UIBezierPath *bezierPath = [UIBezierPath bezierPathWithRoundedRect:targetV.bounds byRoundingCorners:UIRectCornerTopLeft | UIRectCornerTopRight | UIRectCornerBottomRight cornerRadii:CGSizeMake(circelR, circelR)];
// 初始化shapeLayer
CAShapeLayer *shapeLayer = [CAShapeLayer layer];
// 设置绘制路径
shapeLayer.path = bezierPath.CGPath;
//渐变图层
CAGradientLayer * gradientLayer = [CAGradientLayer layer];
gradientLayer.frame = CGRectMake(0, 0, CGRectGetWidth(targetV.frame), CGRectGetHeight(targetV.frame));
gradientLayer.startPoint = CGPointMake(0, 1);
gradientLayer.endPoint = CGPointMake(1, 0);
gradientLayer.colors = @[(__bridge id)[UIColor colorWithHex:0xFF578C].CGColor,(__bridge id)[UIColor colorWithHex:0xFF0E00].CGColor];
gradientLayer.locations = @[@(0.3f)];
CALayer * baseLayer = [CALayer layer];
[baseLayer addSublayer:gradientLayer];
[baseLayer setMask:shapeLayer];
[targetV.layer insertSublayer:baseLayer atIndex:0];
}
// 给常规控件添加小红点
- (void)addRedPointCionven:(UIView *)targetView mas_makeConstraints:(void(^)(UIButton * tempV,NSNumber * helfH))block{
UIButton * rempBtn = [[UIButton alloc] initWithFrame:CGRectMake(0, 0, CGRectGetWidth(targetView.frame), CGRectGetHeight(targetView.frame))];
[targetView.superview addSubview:rempBtn];
rempBtn.tag = 7000 + targetView.tag;
UIImageView * redView = [[UIImageView alloc] initWithFrame:CGRectMake(CGRectGetWidth(targetView.frame) - ScaleSize(5), -ScaleSize(5), ScaleSize(10), ScaleSize(10))];
redView.backgroundColor = [UIColor redColor];
[rempBtn addSubview:redView];
[self XLCustomCirclarWithBorad:rempBtn cornerRadius:ScaleSize(10) / 2 borderColor:[UIColor whiteColor] borderWidth:2];
block(rempBtn,[NSNumber numberWithFloat:ScaleSize(10) / 2]);
}
- (void)removeRedPoint:(UIView *)targetV{
for (UIView * subView in targetV.superview.subviews) {
if (subView.tag - 7000 == targetV.tag) {
[subView removeFromSuperview];
break;
}
}
}
//给常规控件右上角添加纯数字提示框
- (void)addTextOfNumToCionven:(UIView *)targetView textNum:(NSString *)numText mas_makeConstraints:(void(^)(UIView * tempV))block{
//创建 文本提示框
UILabel * labV = [[UILabel alloc] init];
labV.backgroundColor = [UIColor redColor];
labV.tag = 8000 + targetView.tag;
labV.text = numText;
labV.textColor = [UIColor whiteColor];
labV.font = kPingFangMedium(13);
labV.textAlignment = NSTextAlignmentCenter;
CGSize size = [numText sizeWithAttributes:@{NSFontAttributeName:labV.font}];
labV.frame = CGRectMake(0, 0, size.width + ScaleSize(10), ScaleSize(18));
[targetView.superview addSubview:labV];
block(labV);
[self XLCustomViewAllBeadCircular:labV cornerRadius:ScaleSize(9)];
UIBezierPath *bezierPath = [UIBezierPath bezierPathWithRoundedRect:labV.bounds cornerRadius:ScaleSize(9)];
[self addWhiteBorad:labV bezierPath:bezierPath];
}
- (void)removeNumText:(UIView *)targetV{
for (UIView * subView in targetV.superview.subviews) {
if (subView.tag - 8000 == targetV.tag) {
[subView removeFromSuperview];
break;
}
}
}
//给常规控件右上角添加纯文本提示框
- (void)addTextOfStringToCionven:(UIView *)targetV textString:(NSString *)textStr mas_makeConstraints:(void(^)(UIButton * tempV,NSNumber * height))block{
UIButton * tempBtn = [[UIButton alloc] initWithFrame:CGRectMake(0, 0, CGRectGetWidth(targetV.frame), CGRectGetHeight(targetV.frame))];
[targetV.superview addSubview:tempBtn];
tempBtn.tag = 9000 + targetV.tag;
UILabel * titleLab = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 100, 20)];
titleLab.text = textStr;
titleLab.textColor = [UIColor whiteColor];
titleLab.font = [UIFont systemFontOfSize:10];
titleLab.textAlignment = NSTextAlignmentCenter;
[tempBtn addSubview:titleLab];
CGSize size = [textStr sizeWithAttributes:@{NSFontAttributeName:titleLab.font}];
CGFloat x = CGRectGetWidth(targetV.frame) - 5;
titleLab.frame = CGRectMake(x, -10, size.width + 10, 14);
CGFloat circelR = 7;
// 创建贝塞尔曲线,指定绘制区域、角和角半径
UIBezierPath *bezierPath = [UIBezierPath bezierPathWithRoundedRect:titleLab.bounds byRoundingCorners:UIRectCornerTopLeft | UIRectCornerTopRight | UIRectCornerBottomRight cornerRadii:CGSizeMake(circelR, circelR)];
// 初始化shapeLayer
CAShapeLayer *shapeLayer = [CAShapeLayer layer];
// 设置绘制路径
shapeLayer.path = bezierPath.CGPath;
//渐变图层
CAGradientLayer * gradientLayer = [CAGradientLayer layer];
gradientLayer.frame = CGRectMake(0, 0, CGRectGetWidth(titleLab.frame), CGRectGetHeight(titleLab.frame));
gradientLayer.startPoint = CGPointMake(0, 1);
gradientLayer.endPoint = CGPointMake(1, 0);
gradientLayer.colors = @[(__bridge id)[UIColor colorWithHex:0xFF578C].CGColor,(__bridge id)[UIColor colorWithHex:0xFF0E00].CGColor];
gradientLayer.locations = @[@(0.3f)];
CALayer * baseLayer = [CALayer layer];
[baseLayer addSublayer:gradientLayer];
[baseLayer setMask:shapeLayer];
[titleLab.layer insertSublayer:baseLayer atIndex:0];
block(tempBtn,[NSNumber numberWithInteger:ScaleSize(14)]);
}
- (void)removeStrText:(UIView *)targetV{
for (UIView * subView in targetV.superview.subviews) {
if (subView.tag - 9000 == targetV.tag) {
[subView removeFromSuperview];
break;
}
}
}
/** 添加白色边框 */
- (void)addWhiteBorad:(UIView *)targetV bezierPath:(UIBezierPath *)path{
CAShapeLayer * boraderLayer = [CAShapeLayer layer];
boraderLayer.frame = CGRectMake(0, 0, targetV.bounds.size.width, targetV.bounds.size.height);
boraderLayer.lineWidth = 2;
boraderLayer.strokeColor = [UIColor whiteColor].CGColor;
boraderLayer.fillColor = [UIColor clearColor].CGColor;
boraderLayer.path = path.CGPath;
[targetV.layer insertSublayer:boraderLayer atIndex:0];
}
@end
我这里说明一下,这些类别适合那些使用了masnory约束了的项目和控件
如果哪位大佬能说明一下如何及时获取到经过masnory约束后的常规控件的x和y,请留言给我,万分感谢
我的qq:2849765859 我是磊怀