NSAttributedString 实现文字遮盖效果

最近接到一个需求,文本长度为2-3个文字,两个文字长度的文本要求中间存在空距,左右顶边,且整体文本长度与三个文字的文本长度保持一致。效果如下:

最简单的实现是让UI把文字做成图片直接使用。第二种则是文本内加空格:

1
[NSString stringWithFormat:@"爱  好:"];

但是这种方法的问题在于由于文字font的存在,有时候,添加空格后文本的长度无法与三个文字的文本长度一致。这时候我们还可以选择第三种方案,保持文字长度一致,再遮盖部分文字,保留显示文字:

1
2
3
4
5
6
居住地:____     职一业:____
爱一好:____ 电一话:____

职一业: -> 职 业:
爱一好: -> 爱 好:
电一话: -> 电 话:

具体实现上,我们通过NSAttributedString的分类方法实现。将原有字符转换为属性字符,并设置文字属性、遮盖范围及遮盖部分的文字属性:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
+ (NSAttributedString *)attributedStringWithString:(NSString *)string attributes:(NSDictionary<NSString *, id> *)attrs maskRange:(NSRange)maskRange maskAttributes:(NSDictionary<NSString *, id> *)maskAttrs
{
NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc] initWithString:string attributes:attrs];

if (NSEqualRanges(maskRange, NSRangeZero)) return attributedString;

NSRange stringRange = NSMakeRangeFromString(string);
if (NSRangeInRange(maskRange, stringRange))
{
[attributedString addAttributes:maskAttrs range:maskRange];
}

return attributedString;
}

在这里,我们先将文字整体转换为指定属性的文字。之后获取文字范围,当遮盖范围在文字范围内则实现遮盖文字效果。获取文字范围和判断遮盖范围是否在文字范围内,我们可以通过在NSValue的分类方法内添加内联函数方法的形式实现:
获取字符串的range:

1
2
3
4
NS_INLINE NSRange NSMakeRangeFromString(NSString *string)
{
return NSMakeRange(0, string.length);
}

判断range1是否包含于range2内:

1
2
3
4
NS_INLINE BOOL NSRangeInRange(NSRange range1, NSRange range2)
{
return (NSLocationInRange(range1.location, range2) && range1.length <= (range2.length - range1.location)) ? YES : NO;
}

同时,我们也可以提供一个便利方法处理此类需求,将原有字符转换为属性字符,并设置文字颜色、文字格式及遮盖范围,遮盖效果默认为透明颜色:

1
2
3
4
+ (NSAttributedString *)attributedStringWithString:(NSString *)string textColor:(UIColor *)color font:(UIFont *)font maskRange:(NSRange)maskRange
{
return [NSAttributedString attributedStringWithString:string attributes:@{NSFontAttributeName:font, NSForegroundColorAttributeName:color} maskRange:maskRange maskAttributes:@{NSForegroundColorAttributeName:[UIColor clearColor]}];
}

为方便代码管理,在具体调用界面,我们可以参考UITableViewNSIndexPath(UITableView), 根据界面需求,为调用界面添加专用的NSAttributeString分类方法:

1
2
3
4
5
6
7
8
@implementation NSAttributedString (AdjustTestTitle)

+ (NSAttributedString *)attributedTitleWithString:(NSString *)string maskRange:(NSRange)maskRange
{
return [NSAttributedString attributedStringWithString:string textColor:[UIColor blackColor] font:[UIFont fontWithName:@"Arial" size:19.f] maskRange:maskRange];
}

@end

最后,在需要调用的位置调用即可:

1
self.leftTitleLabel.attributedText = [NSAttributedString attributedTitleWithString:@“职一业:" maskRange:NSMakeRange(1, 1)];

附,示例代码:https://github.com/ColinHwang/iOS-TextMasked

参考资料:

[1]Apple Inc.NSAttributedString Classs Reference[EB/OL].https://developer.apple.com/library/mac/documentation/Cocoa/Reference/Foundation/Classes/NSAttributedString_Class/index.html ,2016-6-23.