Swift - 让textview支持特殊标签点击响应(@标签、#标签)

82 篇文章 1 订阅
有使用过新浪微博会发现,微博对发送的消息提供了几个特殊符号标签。
比如:输入“ @+微博用户昵称(即ID)+空格或标点”,那么在这条微博中这个@条目就会表现成超链接形式,点击即可跳转到被@的某人的微博。 
又比如话题标签“ #+关键字+#”。表现形式就是点击后会跳转到包含该关键字的微博的搜索结果页面的超链接。
同样的,直接输入“ http://hangge.com”那么微博中会显示为可点击的网页链接。
原文:Swift - 让textview支持特殊标签点击响应(@标签、#标签)

1,让textview支持特殊符号标签
通常情况下,这些带特殊标签符号内容对于多行文本框( UITextView )来说都是视为普通文本,要想让其支持点击,我们可以借助textview的URL检测功能来实现。
(1)首先遍历文本内容,将各种特殊文本替换成我们自定义的一些  URL scheme。比如:用  mention://hangge 表示  @hangge,用  hash://航歌 表示  #航歌#
(2)通过textview的  UITextFieldDelegate 代理的  shouldInteractWithURL 方法,我们可以捕获到这些自定义的  URL scheme 点击,然后通过判断  URL.scheme 来执行不同的操作。 

2,先看效果图
(1)我们在页面上放置两个  textview,下面一个用来编辑文本。
原文:Swift - 让textview支持特殊标签点击响应(@标签、#标签)

(2)点击“发送”按钮则会将内容在上面一个textview中显示出来,可以看到特殊符号的字段都显示为可点击状态。
原文:Swift - 让textview支持特殊标签点击响应(@标签、#标签)

(3)测试下各个标签的点击响应事件。
    原文:Swift - 让textview支持特殊标签点击响应(@标签、#标签)    原文:Swift - 让textview支持特殊标签点击响应(@标签、#标签)    原文:Swift - 让textview支持特殊标签点击响应(@标签、#标签)

3,实现步骤
(1)对于用来显示的textview,要将其  Detection Links(链接检测)打勾,去掉  Editable(使其不可编辑)。
原文:Swift - 让textview支持特殊标签点击响应(@标签、#标签)

(2)扩展UITextView: UITextFieldExtension.swift
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
import  UIKit
 
extension  UITextView  {
     
     /**
      转换特殊符号标签字段
      */
     func  resolveHashTags(){
         let  nsText: NSString  self .text
         // 使用默认设置的字体样式
         let  attrs = [ NSFontAttributeName  self .font!]
         let  attrString =  NSMutableAttributedString (string: nsText  as  String ,
                                                    attributes:attrs)
         
         //用来记录遍历字符串的索引位置
         var  bookmark = 0
         //用于拆分的特殊符号
         let  charactersSet =  NSCharacterSet (charactersInString:  "@#" )
         
         //先将字符串按空格和分隔符拆分
         let  sentences:[ NSString ] =  self .text.componentsSeparatedByCharactersInSet(
             NSCharacterSet .whitespaceAndNewlineCharacterSet())
         
         for  sentence  in  sentences {
             //如果是url链接则跳过
             if  !verifyUrl(sentence  as  String ) {
                 //再按特殊符号拆分
                 let  words:[ NSString ] = sentence.componentsSeparatedByCharactersInSet(
                     charactersSet)
                 var  bookmark2 = bookmark
                 for  in  0..<words.count{
                     let  word = words[i]
                     let  keyword = chopOffNonAlphaNumericCharacters(word  as  String )
                     if  keyword !=  ""  && i>0{
                         //使用自定义的scheme来表示各种特殊链接,比如:mention:hangge
                         //使得这些字段会变蓝色且可点击
                         
                         //匹配的范围
                         let  remainingRangeLength =  min ((nsText.length - bookmark2 + 1),
                                                        word.length+2)
                         let  remainingRange =  NSRange (location: bookmark2-1,
                                                      length: remainingRangeLength)
                         print (keyword, bookmark2, remainingRangeLength)
                         
                         //获取转码后的关键字,用于url里的值
                         //(确保链接的正确性,比如url链接直接用中文就会有问题)
                         let  encodeKeyword = keyword
                             .stringByAddingPercentEncodingWithAllowedCharacters(
                                 NSCharacterSet . URLQueryAllowedCharacterSet ())!
                         
                         //匹配@某人
                         var  matchRange = nsText.rangeOfString( "@\(keyword)" ,
                                                 options: . LiteralSearch ,
                                                 range:remainingRange)
                         attrString.addAttribute( NSLinkAttributeName ,
                                                 value:  "mention:\(encodeKeyword)" ,
                                                 range: matchRange)
                         
                         //匹配#话题#
                         matchRange = nsText.rangeOfString( "#\(keyword)#" ,
                                     options: . LiteralSearch ,
                                     range:remainingRange)
                         attrString.addAttribute( NSLinkAttributeName ,
                                                 value:  "hash:\(encodeKeyword)" ,
                                                 range: matchRange)
                     }
                     //移动坐标索引记录
                     bookmark2 += word.length + 1
                 }
             }
             
             //移动坐标索引记录
             bookmark += sentence.length + 1
         }
         
         print (nsText.length,bookmark)
         
         //最终赋值
         self .attributedText = attrString
     }
     
     /**
      验证URL格式是否正确
      */
     private  func  verifyUrl(str: String ) ->  Bool  {
         // 创建一个正则表达式对象
         do {
             let  dataDetector = try  NSDataDetector (types:
                 NSTextCheckingTypes ( NSTextCheckingType . Link .rawValue))
             // 匹配字符串,返回结果集
             let  res = dataDetector.matchesInString(str,
                             options:  NSMatchingOptions (rawValue: 0),
                             range:  NSMakeRange (0, str.characters.count))
             // 判断结果(完全匹配)
             if  res.count == 1  && res[0].range.location == 0
                 && res[0].range.length == str.characters.count {
                 return  true
             }
         }
         catch {
             print (error)
         }
         return  false
     }
     
     /**
      过滤部多余的非数字和字符的部分
      比如:@hangge.123 -> @hangge
      */
     func  chopOffNonAlphaNumericCharacters(text: String ) ->  String  {
         let  nonAlphaNumericCharacters =  NSCharacterSet .alphanumericCharacterSet().invertedSet
         let  characterArray = text.componentsSeparatedByCharactersInSet(nonAlphaNumericCharacters)
         return  characterArray[0]
     }
}

(3)测试页面代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
import  UIKit
 
class  ViewController UIViewController UITextViewDelegate  {
 
     //展示文本框
     @IBOutlet  weak  var  displayTextView:  UITextView !
     //编辑文本框
     @IBOutlet  weak  var  editTextView:  UITextView !
     
     override  func  viewDidLoad() {
         super .viewDidLoad()
         
         //设置展示文本框的代理
         displayTextView.delegate =  self
     }
 
     //发送消息
     @IBAction  func  setMessage(sender:  AnyObject ) {
         //设置展示文本框的内容
         displayTextView.text = editTextView.text
         //对内容中的特殊标签字段做处理
         displayTextView.resolveHashTags()
         //清空输入框内容
         editTextView.text =  ""
     }
     
     //展示文本框链接点击响应
     func  textView(textView:  UITextView , shouldInteractWithURL  URL NSURL ,
                   inRange characterRange:  NSRange ) ->  Bool  {
         //判断URL scheme
         switch  URL .scheme {
         case  "hash"  :
             showAlert( "hash" , payload:
                 URL .resourceSpecifier.stringByRemovingPercentEncoding!)
         case  "mention"  :
             showAlert( "mention" , payload:
                 URL .resourceSpecifier.stringByRemovingPercentEncoding!)
         default :
             print ( "这个是普通的url链接" )
         }
         
         return  true
     }
     
     //显示消息
     func  showAlert(tagType: String , payload: String ){
         let  alertController =  UIAlertController (title:  "检测到\(tagType)标签" ,
             message: payload, preferredStyle: . Alert )
         let  cancelAction =  UIAlertAction (title:  "确定" , style: . Cancel , handler:  nil )
         alertController.addAction(cancelAction)
         self .presentViewController(alertController, animated:  true , completion:  nil )
     }
     
     override  func  didReceiveMemoryWarning() {
         super .didReceiveMemoryWarning()
     }
}
源码下载:hangge_1096.zip

原文出自: www.hangge.com   转载请保留原文链接: http://www.hangge.com/blog/cache/detail_1096.html
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值