键盘弹出来时,改变工具栏的高度,
想要实现键盘和工具栏一起往上移动的效果,
添加动画,调用[self.view layoutIfNeeded];方法即可
image.png
注意:
#UITextView的高度,一定要大于输入文字的高度,不然输入文字的时候会晃动,而且还会显示不全哦。所以富文本的时候高度是个大事。
UITextView *titleView = [[UITextView alloc] initWithFrame:CGRectMake(15, 20, SCREEN_WIDTH-30, 30)];
titleView.font = [UIFont systemFontOfSize:24];
#系统Bug。(UITextView文字和占位文字偏移了10的间距)
titleView.textContainerInset = UIEdgeInsetsMake(0, 0, 0, -10);
titleView.backgroundColor=[UIColor yellowColor];
[self.view addSubview:titleView];
1,解决textView输入内容的时候,光标下沉。
//解决textView输入内容的时候,光标下沉。
self.textField_t.textContainerInset = UIEdgeInsetsMake(5, 0, 0, 0);
2,输入了100行,然后输入第一行内容,那么会自动跑到底部。这句就是为了防止回到底部
//输入了100行,然后输入第一行内容,那么会自动跑到底部。这句就是为了防止回到底部
self.textView_c.layoutManager.allowsNonContiguousLayout = NO;
3,自定义view中textview滚动失效 iOS(自定义view放在了一个VC中)
#解决方法:
在VC中
-(void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
//自定义view中的TextView的scrollEnabled需要在VC加载结束后手动打开一次,不然会把默认YES改为NO。
self.detailView.textView_detail.scrollEnabled = YES;
}
4,添加图片附件
//添加图片附件
NSTextAttachment *attach = [[NSTextAttachment alloc] init];
attach.image = [UIImage imageNamed:@"1.jpg"];
attach.bounds = CGRectMake(0, 0, 100, 100);
//附件是不可变属性字符串
NSAttributedString *attributedString = [NSAttributedString attributedStringWithAttachment:attach];
NSMutableAttributedString *attributedStr = [[NSMutableAttributedString alloc] initWithString:@"点击分手克里斯丁建安费垃圾啊啥都离开房间撒的李开复"];
[attributedStr insertAttributedString:attributedString atIndex:attributedStr.length];
self.textView.attributedText = attributedStr;
5,获取光标位置
#注意:使用时候判断是否为空:
NSRange rg = self.textView.selectedRange;
if (rg.location != NSNotFound)
{
NSLog(@"光标位置:%d",rg.location);
}
7,输入时上下晃动
CGRect line = [textView caretRectForPosition:textView.selectedTextRange.start];
CGFloat overflow = line.origin.y + line.size.height - ( textView.contentOffset.y + textView.bounds.size.height - textView.contentInset.bottom - textView.contentInset.top );
if ( overflow > 0 ) {
// We are at the bottom of the visible text and introduced a line feed, scroll down (iOS 7 does not do it)
// Scroll caret to visible area
CGPoint offset = textView.contentOffset;
offset.y += overflow + 7;
// leave 7 pixels margin
// Cannot animate with setContentOffset:animated: or caret will not appear
[UIView animateWithDuration:.2 animations:^{
[textView setContentOffset:offset];
}];
}
8,UITextView加载HTML数据(左间距没有调试成功,暂用wkwebView.)
- (void)viewDidLoad {
[super viewDidLoad];
UITextView *textView = [[UITextView alloc] initWithFrame:CGRectMake(10, 10, [UIScreen mainScreen].bounds.size.width - 20, [UIScreen mainScreen].bounds.size.height - 20)];
textView.delegate = self;
textView.editable = NO; // 非编辑状态下才可以点击Url]
// textView.fontFloat = 18.;
NSString *textStr=@"<p>现在互联网,断章取义的东西大家最喜欢玩了,本来是个很严肃很励志的一句话,但是把头尾一截,就变得很有趣味了</p><p><br/></p><p>先订一个能达到的小目标(严肃认真脸.jpg)</p><p>比方说我先挣它一个亿(严肃轻松脸.png)</p><p><img src=\"http://img.woshipm.com/TTW_QUESTION_201608_20160829170712_0539.jpg\" title=\"\" width=\"385\" height=\"415\" style=\"width: 385px; height: 415px;\"/></p><p>首尾的强大反差给人一种无奈到好笑的感觉,跟比尔盖茨很有名的那张3秒赚辆兰博基尼有异曲同工之妙。</p><p><br/></p><p>说的随便点吧,就是大家觉得这东西好玩搞笑,极具讽刺性,跟大家的生活现状形成强烈的对比,明明就是苦逼屌丝一辈子赚不到一千万的角儿,却要看着人家定个小目标随便弄他一个亿,我的妈呀,人与人之间的差别距离好几个爹呀。</p><p>互联网现在信息传递快,大家爱自嘲、爱起哄,像这种能够开名人玩笑,为生活补充点乐子的事,而且还能表达一下自己对生活的挖苦、讽刺,所以转了也就转了<br/></p>";
// NSString *linkStr = [textView.text substringWithRange:range];
NSMutableAttributedString *attributedString = [self changeHtmlStringToAttributeString:textStr];
// [attributedString addAttribute:NSLinkAttributeName value:@"http://img.taopic.com/uploads/allimg/111231/6755-11123114022199.jpg" range:NSMakeRange(0, 6)];
textView.attributedText = attributedString;
[self.view addSubview:textView];
#测试
(
self.jq_textView.delegate = self;
self.jq_textView.editable = NO; // 非编辑状态下才可以点击Url]
// textView.fontFloat = 18.;
NSString *textStr=@"<div style=\"margin:75px;\"><h2 style=\"font-size: 13px;color: #888;\">会员权益简介 -----------------</h2><div style=\"padding-left:70px;\"><h2 style=\"font-size: 13px;color: #888;\">会员专享价</h2><h3 style=\"font-size: 13px;color: #999;margin: 30px 35 0 0;\">权益说明</h3><p style=\"font-size: 13px;color: #999;margin: 0 35 15px 0;\">商品促销信息以商品详情页“促销”栏中的信息为准;商品的具体售价以订单结算页价格为准;如您发现活动商品售价或促销信息有异</p><h3 style=\"font-size: 13px;color: #999;margin:10px 35 0 0;\">权益等级</h3><p style=\"font-size: 13px;color: #999;margin: 0 35 15px 0;\">信息以商品详情页“促销”栏</p><h3 style=\"font-size: 13px;color: #999;margin: 10px 35 0 0;\">其他说明</h3><p style=\"font-size: 13px;color: #999;margin: 0 35 15px 0;\">商品促销信息以商品详情页“促销”栏中的信息为准;商品的具体售价以订单结算页价格为准;如您发现活动商品售价或促销信息有异</p></div></div>";
// NSString *linkStr = [textView.text substringWithRange:range];
NSMutableAttributedString *attributedString = [self changeHtmlStringToAttributeString:textStr];
self.jq_textView.attributedText = attributedString;
)
}
-(NSMutableAttributedString *)changeHtmlStringToAttributeString:(NSString *)htmlString{
NSString *newString = htmlString;
//图片自适应宽高,只限制图片的最大显示宽度,这样就能做到自适应
newString =[NSString stringWithFormat:@"<html>"
"<head>"
"</style>"
"<style>*{margin:3px 0px 3px 0px;padding:0 ;max-width:%f;}</style>"
"</head>"
"<body>%@</body>"
"</html>",self.view.frame.size.width-30,newString];
NSData *data = [newString dataUsingEncoding:NSUnicodeStringEncoding];
NSDictionary *options = @{NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType};
NSMutableAttributedString *htmlAttribute = [[NSMutableAttributedString alloc] initWithData:data
options:options
documentAttributes:nil
error:nil];
NSMutableParagraphStyle * paragraphStyle = [[NSMutableParagraphStyle alloc] init];
//设置文字的行间距
[paragraphStyle setLineSpacing:5];
[htmlAttribute addAttribute:NSParagraphStyleAttributeName value:paragraphStyle range:NSMakeRange(0, [htmlAttribute length])];
//设置文字的颜色
[htmlAttribute addAttribute:NSForegroundColorAttributeName value:[UIColor redColor] range:NSMakeRange(0, htmlAttribute.length)];
//设置文字的大小
[htmlAttribute addAttribute:NSFontAttributeName value:[UIFont systemFontOfSize:14] range:NSMakeRange(0, htmlAttribute.length)];
return htmlAttribute;
#测试
(
NSString *newString = htmlString;
NSData *data = [newString dataUsingEncoding:NSUnicodeStringEncoding];
NSDictionary *options = @{NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType};
NSMutableAttributedString *htmlAttribute = [[NSMutableAttributedString alloc] initWithData:data
options:options
documentAttributes:nil
error:nil];
return htmlAttribute;
)
}
9,自定义 UITextView 关键字高亮与点击检测
10,替换属性字符串中的图片为字符
#:属性字符串attributeString
//方法一
// NSMutableString *plainString = [NSMutableString stringWithString:attributeString.string];
// __block NSUInteger base = 0;
// [self enumerateAttribute:NSAttachmentAttributeName inRange:NSMakeRange(0, self.length)
// options:0
// usingBlock:^(LiuqsTextAttachment *value, NSRange range, BOOL *stop) {
// if (value) {
// [plainString replaceCharactersInRange:NSMakeRange(range.location + base, range.length)
// withString:value.emojiTag];
// base += value.emojiTag.length - 1;
// }
// }];
//方法二(推荐)
NSMutableAttributedString *mutableAttributeString = [[NSMutableAttributedString alloc] initWithAttributedString:attributeString];
[mutableAttributeString enumerateAttribute:@"NSAttachment" inRange:NSMakeRange(0, self.length) options:0 usingBlock:^(id _Nullable value, NSRange range, BOOL * _Nonnull stop) {
NSLog(@"value===%@",value);
NSLog(@"range===%@",NSStringFromRange(range));
if ([value isKindOfClass:[NSTextAttachment class]]) {
LiuqsTextAttachment *attachment = (LiuqsTextAttachment *)value;
[mutableAttributeString replaceCharactersInRange:range withString:attachment.emojiTag];
}
}];
return [mutableAttributeString string];
11,清空UItextView的所有内容
self.toolView.jq_inputView.text = @" ";
[self.toolView.jq_inputView deleteBackward]; //删除一个字节
12,UITextView/UITextField检测并过滤Emoji表情符号
当用户切换键盘为Emoji表情时,输入的表情不响应(即表情符号不显示到UITextView或UITextField)。这里可以通过UITextView或UITextField的回调和是否为emoji键盘:
/*
*第一种方法,简单粗暴
*/
- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text
{
// 不让输入表情
if ([textView isFirstResponder]) {
if ([[[textView textInputMode] primaryLanguage] isEqualToString:@"emoji"] || ![[textView textInputMode] primaryLanguage]) {
NSLog(@"输入的是表情,返回NO");
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"警告!" message:@"不能输入表情" delegate:self cancelButtonTitle:@"取消" otherButtonTitles:@"确定",nil];
[alertView show];
return NO;
}
}
return YES;
}
为避免当用户通过中文键盘输入中文“哈哈”后出现可选文字中选中的Emoji笑脸,最后在- (void)textFieldDidEndEditing:(UITextField *)textField方法中统一通过检查最终字符串textField/textView.text的内容,通过Emoji筛unicode编码来判断是否存在Emoji表情,如果存在则提醒用户做修改。
//在输入完成时,调用下面那个方法来判断输入的字符串是否含有表情
- (void)textFieldDidEndEditing:(UITextField *)textField
{
if ([self stringContainsEmoji:textField.text]) {
NSLog(@"含有表情");
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"警告!" message:@"输入内容含有表情,请重新输入" delegate:self cancelButtonTitle:@"取消" otherButtonTitles:@"确定",nil];
[alertView show];
textField.text = @"";
[textField becomeFirstResponder];
}else {
NSLog(@"不含有表情");
}
}
/*
*第二种方法,利用Emoji表情最终会被编码成Unicode,因此,
*只要知道Emoji表情的Unicode编码的范围,
*就可以判断用户是否输入了Emoji表情。
*/
- (BOOL)stringContainsEmoji:(NSString *)string
{
// 过滤所有表情。returnValue为NO表示不含有表情,YES表示含有表情
__block BOOL returnValue = NO;
[string enumerateSubstringsInRange:NSMakeRange(0, [string length]) options:NSStringEnumerationByComposedCharacterSequences usingBlock:^(NSString *substring, NSRange substringRange, NSRange enclosingRange, BOOL *stop) {
const unichar hs = [substring characterAtIndex:0];
// surrogate pair
if (0xd800 <= hs && hs <= 0xdbff) {
if (substring.length > 1) {
const unichar ls = [substring characterAtIndex:1];
const int uc = ((hs - 0xd800) * 0x400) + (ls - 0xdc00) + 0x10000;
if (0x1d000 <= uc && uc <= 0x1f77f) {
returnValue = YES;
}
}
} else if (substring.length > 1) {
const unichar ls = [substring characterAtIndex:1];
if (ls == 0x20e3) {
returnValue = YES;
}
} else {
// non surrogate
if (0x2100 <= hs && hs <= 0x27ff) {
returnValue = YES;
} else if (0x2B05 <= hs && hs <= 0x2b07) {
returnValue = YES;
} else if (0x2934 <= hs && hs <= 0x2935) {
returnValue = YES;
} else if (0x3297 <= hs && hs <= 0x3299) {
returnValue = YES;
} else if (hs == 0xa9 || hs == 0xae || hs == 0x303d || hs == 0x3030 || hs == 0x2b55 || hs == 0x2b1c || hs == 0x2b1b || hs == 0x2b50) {
//想过滤的字符可以在这里做处理
if (![substring isEqualToString:@"®"]) {
returnValue = YES;
}
}
}
}];
return returnValue;
}
13,UITextView插入图片时,通常会想在前后插入换行(\n),但是呢,如果加了行高之类的东西,那么就尴尬了,因为计算的高度会出问题。
#方案一:在图片前后分别再插入一个附件,高度为0或1,宽度为屏幕宽。
#first,尴尬了,附件有个默认的高度,大概10-15左右吧,
这个高度是去不掉的,而且就算高度为0,还是可以点击到附件。
如果想做点击图片放大的话,这又是个难题。
#final,放弃方案一。
#方案二:回归添加换行(\n)
/*
1,取图片前一位,如果是图片,那么就不添加回车,如果不是图片,那么就添加回车。
2,取前一位时注意图片是第一位的情况。
3,经测试得到,一个回车是20的高度。如果有一个回车就在totalImageHeight的基础上添加20。
4,注意属性字符要准备2份,一份用来展示(带回车),一份把图片替换为空(不带回车),因为totalImageHeight已经把回车的高度加上了。计算纯文本就可以了。
5,替换文本后需要重新设置富文本属性,不然会恢复初始化状态,行高间距字体大小都没了。
6,连续两张图片的算一个间距,所以这里要减去有多少个连续的图片,最后测试选择一个连续的两张图-10的间距。
7,换行的模式选择NSLineBreakByCharWrapping,因为这样可以兼容到字母、数字。
举例:paragraphStyle.lineBreakMode = NSLineBreakByCharWrapping;
8, 根据URL找到指定缓存(如果存在的话)
UIImage* image = [[SDImageCache sharedImageCache] imageFromMemoryCacheForKey:url];
9,插入图片原理:看SDWebImage中是否有缓存图片,有则把正则匹配的图片范围直接替换为图片,否则,先默认插入一个宽高均为SCREEN_WIDTH-25的附件,然后SDWebImage异步下载图,下载成功之后,判断找到对应的附件,替换,textView高度减去差值,重新添加到tableview的头部。
*/
14,系统UITextView可以开始识别手机号、网址等。
textView.delegate = self;
textView.dataDetectorTypes = UIDataDetectorTypeLink; //开启识别链接
UIDataDetectorTypePhoneNumber :识别手机号
UIDataDetectorTypeLink :识别链接
UIDataDetectorTypeAll :识别所有
#点击链接会走这个方法
//链接委托(链接最好用一个括号括起来,或者在链接后面加个空格。)
- (BOOL)textView:(UITextView*)textView
shouldInteractWithURL:(NSURL*)URL
inRange:(NSRange)characterRange
{
NSLog(@"URL tap handle:%@", URL);
return YES; //返回yes,点击链接的时候就会自动打开。
}
#点击附件会走这里的方法
/*
附件委托新方法。
返回YES,可以从下面弹出复制图片或保存图片,但是呢,不是很好看。
*/
- (BOOL)textView:(UITextView*)textView
shouldInteractWithTextAttachment:(NSTextAttachment*)textAttachment
inRange:(NSRange)characterRange
interaction:(UITextItemInteraction)interaction
{
//获取附件
CustomTextAttachMent* attachment = (CustomTextAttachMent*)textAttachment;
NSLog(@"%@", attachment.imgURL); //获取原图URL
#这里我使用HJPhotoBrowser做了点击图片放大的功能。
self.clickImgURL = attachment.imgURL;
self.clickImg = attachment.image;
HJPhotoBrowser* photoBrowser = [HJPhotoBrowser new];
photoBrowser.delegate = self;
// photoBrowser.currentImageIndex = indexPath.item;
photoBrowser.imageCount = 1;
photoBrowser.sourceImagesContainerView = self.view;
[photoBrowser show];
return NO;
}
15,UITextView实现左右点击效果
感觉两个手势就搞定了,待定(该博客还没看)
16,UITextView实现富文本
/*
1,取图片前一位,如果是图片,那么就不添加回车,如果不是图片,那么就添加回车。
2,取前一位时注意图片是第一位的情况。
3,经测试得到,一个回车是20的高度。如果有一个回车就在totalImageHeight的基础上添加20。
4,注意属性字符要准备2份,一份用来展示(带回车),一份把图片替换为空(不带回车),因为totalImageHeight已经把回车的高度加上了。计算纯文本就可以了。
5,替换文本后需要重新设置富文本属性,不然会恢复初始化状态,行高间距字体大小都没了。
6,连续两张图片的算一个间距,所以这里要减去有多少个连续的图片,最后测试选择一个连续的两张图-10的间距。
7,换行的模式选择NSLineBreakByCharWrapping,因为这样可以兼容到字母、数字。
举例:paragraphStyle.lineBreakMode = NSLineBreakByCharWrapping;
8, 根据URL找到指定缓存(如果存在的话)
UIImage* image = [[SDImageCache sharedImageCache] imageFromMemoryCacheForKey:url];
9,插入图片原理:看SDWebImage中是否有缓存图片,有则把正则匹配的图片范围直接替换为图片,否则,先默认插入一个宽高均为SCREEN_WIDTH-25的附件,然后SDWebImage异步下载图,下载成功之后,判断找到对应的附件,替换,textView高度减去差值,重新添加到tableview的头部。
10,注意替换SDWebImage下载完成的图片时,要重新创建一个CustomTextAttachMent,不然一张图的时候,第一次进入显示失败。
*/
网友评论