我们玩过QQ和新浪微博的人应该都知道,当我们按@的人的名字的时候都会出现一个背景,那这个是怎么去实现的呢?
其实就是用到了textView的几个属性和方法,首先我们自定义一个UITextView的类,然后在这个类中我们去重写touchesBegan方法
然后我们要知道的是selectedRange这个属性就是去设置textView的设置的范围,然后去翻TextView的相关的方法我们会找到这么一个方法
这个方法就是去根据选中的文本范围然后去返回相应的矩形框大小,这里为什么是一个数组,因为我们要考虑到这么一种情况,那就是我们
选中的范围正好已经有一半在行尾了,最后一半在另一行的开头,这样就会返回的是多个范围了。
这里需要注意的是UITextRange我们是无法去创建的,点进这个类,我们可以看到下面这个图,里面所有的属性都是readonly的,
我们可能会想用KVC赋值但是我们再去看UITextPosition,发现是空的,里面没有任何属性,说明我们无法去创建
通过猜测实际我们会发现我们改变了selectedRange之后就相当于也改变了selectedTextRange。
#import "ZXTextView.h"
@implementation ZXTextView
- (instancetype)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
self.editable=NO;
}
return self;
}
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
NSLog(@"触摸了");
//获取触摸对象
UITouch * touch = [touches anyObject];
//触摸点
CGPoint point = [touch locationInView:self];
//我们自己去设置范围
self.selectedRange = NSMakeRange(0, 4);
//获取选中范围内的矩形框
NSArray * rects = [self selectionRectsForRange:self.selectedTextRange];
//清空选中的范围
self.selectedRange=NSMakeRange(0, 0);
NSLog(@"%@",rects);
for(UITextSelectionRect *selectionRect in rects)
{
CGRect rect = selectionRect.rect;
//因为通过打印rects可知道rect中是有一些是没有用的,宽度为0的或者可能还会有高度为0的
if(rect.size.width==0||rect.size.width==0)
{
continue;
}
//判断我们点击的那个点是否在rect中,如果在的话就插入这个view
if(CGRectContainsPoint(rect, point))
{
UIView * cover = [[UIView alloc]init];
cover.backgroundColor = [UIColor greenColor];
cover.frame = rect;
cover.tag=10;
[self insertSubview:cover atIndex:0];
}
break;
}
}
//移除这个view
-(void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
for(UIView * childView in self.subviews)
{
if(childView.tag==10)
{
[childView removeFromSuperview];
}
}
}
//这里就是如果我们长按的时候选中了一段文字,触摸事件就会被取消也调用下面的方法
-(void)touchesCancelled:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
for(UIView * childView in self.subviews)
{
if(childView.tag==10)
{
[childView removeFromSuperview];
}
}
}
打印rects的值如下所示
效果图如下所示