干貨|swift岸梨,富文本編輯器

這一篇我們將實現(xiàn)一個富文本編輯器喜颁,擁有功能:

  • 1、斜體曹阔、下劃線混排半开。
  • 2、圖文混排
  • 3赃份、字體大小寂拆。
  • 4、選擇自定義字體抓韩。
  • 5纠永、制作長圖片分享到微信朋友圈與微信好友。
  • 6谒拴、調(diào)用系統(tǒng)郵件發(fā)送文本尝江。

先來看一下大體的效果吧,還有一些效果將在后面演示:
(寫在最前面彪薛,這個Demo存在大量BUG茂装,我只是通過他來演示一些功能,也許在后面我會做一個完整的APP善延,到時候也會再來寫一遍少态,來說說一些BUG如何處理)。

1.png

富文本編輯器在以前需要使用CoreText來實現(xiàn)易遣,但是不得不說這真的是一個不小的工程彼妻,但是在iOS7發(fā)布以后,apple發(fā)布了TextKit豆茫,通過TextKit我們能夠輕松實現(xiàn)很多從前難以實現(xiàn)的功能侨歉。


1、斜體揩魂、下劃線混排幽邓、字體的增大以及減小
在SB中拖入一個UITextView,此后的所有操作都是對這個TextView中的文字進(jìn)行操作火脉,先來看幾行代碼:
<pre><code>
var string = NSMutableAttributedString(attributedString: self.textview.attributedText)
string.addAttribute(NSObliquenessAttributeName, value: 0.5, range: NSMakeRange(0,5))
</code></pre>

我們來解釋一下這一段代碼:
首先牵舵,我們從TextView中獲取了string柒啤,這個string是NSMutableAttributedString類型的,這個類型繼承自String畸颅,但是呢担巩,從名字上我們就可以看出來這個類型,我們可以給字符串添加不同的屬性没炒,我們回到代碼涛癌。這段代碼的第二句我們通過:

   func addAttribute(name: String, value: AnyObject, range: NSRange)

這個函數(shù)給字符串添加了屬性,這個API的第1送火、2個參數(shù)就是確定添加的屬性類型拳话,在這里我們添加的就是斜體這個屬性,斜體這個屬性的Value參數(shù)填寫0~1之間的數(shù)值漾脂,在這個我們填寫的是0.5.來看第二個參數(shù)假颇,第二個參數(shù)是添加屬性的范圍,填寫的是一個NSRange類型的值骨稿,應(yīng)該不難理解笨鸡。

以上代碼段的功能就是給textview的字符串的第0個字符開始,連續(xù)五個字符添加斜體的效果坦冠。

是不是十分方便形耗?~~~~~是的。

以上內(nèi)容只是為了演示UITextView中的attributedText屬性辙浑,事實上我們不需要這么做(感謝劉大大激涤,告訴我接下來這種做法)。
在TextView中有一個屬性叫做typingAttributes判呕,xcode對這個屬性的解釋是這樣的automatically resets when the selection changes倦踢,意思就是我們對這個屬性進(jìn)行設(shè)置可以改變接下來改變的文字。
也許這樣說侠草,不能讓人太好的理解辱挥,我們在按鈕中添加以下代碼
<pre><code>
@IBAction func Obliqueness(sender: AnyObject) {
textview.typingAttributes[NSObliquenessAttributeName] = (textview.typingAttributes[NSObliquenessAttributeName] as? NSNumber) == 0 ? 0.5 : 0
}

</code></pre>

當(dāng)** NSObliquenessAttributeName**的值為0時,點擊按鈕將將之改變?yōu)?边涕,為1時則相反晤碘。我們點一下試試,神奇的事情發(fā)生啦啦啦啦~~~接下來我們輸入的文字都變成了斜體功蜓。再次點擊則變回正常园爷。

以此類推,我們寫出下劃線式撼、字體的增大以及減小的代碼童社。
<pre><code>
/**
字體減小

:param: sender
*/
@IBAction func fontincrease(sender: AnyObject) {
    self.fontSize -= 2
    self.textview.typingAttributes[NSFontAttributeName] = UIFont.systemFontOfSize((CGFloat)(self.fontSize))
}
/**
字體增大

:param: sender
*/
@IBAction func fontdecase(sender: AnyObject) {
    self.fontSize += 2
    self.textview.typingAttributes[NSFontAttributeName] = UIFont.systemFontOfSize((CGFloat)(self.fontSize))

}
/**
設(shè)置斜體

:param: sender
*/
@IBAction func Obliqueness(sender: AnyObject) {
    textview.typingAttributes[NSObliquenessAttributeName] = (textview.typingAttributes[NSObliquenessAttributeName] as? NSNumber) == 0 ? 0.5 : 0
}
/**
設(shè)置下劃線

:param: sender
*/
@IBAction func underline(sender: AnyObject) {
    self.textview.typingAttributes[NSUnderlineStyleAttributeName] =  (NSUnderlineStyle.StyleSingle.hashValue ) == 0 ? 1 : NSUnderlineStyle.StyleSingle.hashValue
}
/**

</code></pre>

實現(xiàn)方法都是類似的,十分方便的已經(jīng)實現(xiàn)了很多功能著隆,這放在以前是不可能的(其實我不知道以前實現(xiàn)究竟有多復(fù)雜——5础)甘改。


2、插入圖片灭抑。
前面我們知道TextView存在一個屬性叫做attributedText,插入圖片需要做的就是在TextView的這個屬性中添加圖片抵代,上代碼腾节。
<pre><code>
//1
var string = NSMutableAttributedString(attributedString: self.textview.attributedText)
//2
var textAttachment = NSTextAttachment()
textAttachment.image = img
//3
var textAttachmentString = NSAttributedString(attachment: textAttachment)
var countString:Int = count(self.textview.text) as Int
string.insertAttributedString(textAttachmentString, atIndex: countString)
//4
textview.attributedText = string
</code></pre>

  • 1、獲取當(dāng)前的attributedString
  • 2荤牍、新建一個NSTextAttachment案腺,設(shè)置他的圖片屬性
  • 3、將剛剛創(chuàng)建的NSTextAttachment康吵,添加在原本的attributedString的最后面
  • 4劈榨、重定義** textview.attributedText **

以上代碼中出現(xiàn)一個變量img,這個變量就是從系統(tǒng)相冊獲取圖片晦嵌,代碼如下:
<pre><code>
@IBAction func photeSelect(sender: AnyObject) {
var sheet:UIActionSheet
if(UIImagePickerController.isSourceTypeAvailable(UIImagePickerControllerSourceType.Camera)){
sheet = UIActionSheet(title: nil, delegate: self, cancelButtonTitle: "取消", destructiveButtonTitle: nil, otherButtonTitles: "從相冊選擇", "拍照")
}else{
sheet = UIActionSheet(title:nil, delegate: self, cancelButtonTitle: "取消", destructiveButtonTitle: nil, otherButtonTitles: "從相冊選擇")
}
sheet.showInView(self.view)
}
func actionSheet(actionSheet: UIActionSheet, clickedButtonAtIndex buttonIndex: Int) {
var sourceType = UIImagePickerControllerSourceType.PhotoLibrary
if(buttonIndex != 0){
if(buttonIndex==1){ //相冊
sourceType = UIImagePickerControllerSourceType.PhotoLibrary
}else{
sourceType = UIImagePickerControllerSourceType.Camera
}
let imagePickerController:UIImagePickerController = UIImagePickerController()
imagePickerController.delegate = self
imagePickerController.allowsEditing = true//true為拍照同辣、選擇完進(jìn)入圖片編輯模式
imagePickerController.sourceType = sourceType
self.presentViewController(imagePickerController, animated: true, completion: {
})
}
}
</code></pre>

首先是彈出一個alertView,讓你進(jìn)行選擇惭载,選擇以后旱函,將調(diào)用下面的方法,進(jìn)入到相冊進(jìn)行選擇圖片描滔。在這里你需要繼承幾個協(xié)議棒妨,不然在選擇以后不會觸發(fā)下面的方法:UIActionSheetDelegate,UIImagePickerControllerDelegate。同時進(jìn)入相冊你需要添加幾個庫:AssetsLibrary.framework和MobileCoreServices.framework含长。具體代碼解釋在這里就不行進(jìn)解釋券腔,今天我們把重點放在富文本的實現(xiàn)上。當(dāng)你選擇圖片以后拘泞,將促發(fā)以下方法纷纫,這也是前面添加的協(xié)議的功能。
<pre><code>
func imagePickerController(picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [NSObject : AnyObject]){
var string = NSMutableAttributedString(attributedString: self.textview.attributedText)
var img = info[UIImagePickerControllerEditedImage] as! UIImage
img = self.scaleImage(img)

    var textAttachment       = NSTextAttachment()
    textAttachment.image     = img

    var textAttachmentString = NSAttributedString(attachment: textAttachment)
    var countString:Int      = count(self.textview.text) as Int
    string.insertAttributedString(textAttachmentString, atIndex: countString)

    textview.attributedText  = string
    self.textview.becomeFirstResponder()
    picker.dismissViewControllerAnimated(true, completion: nil)
}

</code></pre>
同時在這個函數(shù)中我們給文本插入圖片田弥,插入方法在前面已經(jīng)說過了涛酗。

當(dāng)我們選擇圖片以后你會發(fā)現(xiàn)由于圖片太大,所以在界面上只能顯示一部分偷厦,那么我們就需要壓縮圖片商叹,壓縮方法如下:
<pre><code>
func scaleImage(image:UIImage)->UIImage{
UIGraphicsBeginImageContext(CGSizeMake(self.view.bounds.size.width, image.size.height(self.view.bounds.size.width/image.size.width)))
image.drawInRect(CGRectMake(0, 0, self.view.bounds.size.width, image.size.height
(self.view.bounds.size.width/image.size.width)))
var scaledimage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return scaled image
}
</code></pre>
這個方法將圖片的寬度設(shè)置為屏幕的寬度,高度按比例縮放只泼。

好的~~~~~我們終于實現(xiàn)了插入圖片剖笙,其實在這里有一個很大的問題,就是下面這句話:

<pre><code>
textview.attributedText = string
</code></pre>

我們每次插入圖片都將TextView的內(nèi)容全部改變了一次请唱,這樣的做法弥咪,先不提在大量文字的情況下可能造成的卡頓問題过蹂,同時造成了編排問題,有同學(xué)可能已經(jīng)發(fā)現(xiàn)了聚至,當(dāng)我們用這樣的方法插入圖片以后酷勺,當(dāng)我們再次改變屬性的時候,視圖將會瞬間調(diào)到最上面扳躬,原因就是這句話脆诉。至于如何解決~~~~還沒想到——!


3贷币、選擇字體
改變字體的方法其實和我們設(shè)置斜體击胜,下劃線等是一樣的,方法如下:
<pre><code>
func lovefont(sender:AnyObject){
self.textview.typingAttributes[NSFontAttributeName] = UIFont(name: "1-", size: (CGFloat)(self.fontSize))
}
</code></pre>
那么我們現(xiàn)在的問題就是自定義字體了役纹,畢竟xcode的字體大多不支持中文偶摔,同時中文顯示的時候不那么優(yōu)雅,我們要說的就是自定義字體促脉。

加載自定義字體辰斋,并不是太過復(fù)雜,我在簡書看到這篇文章描述加載自定義字體就感覺寫的很好嘲叔,http://www.reibang.com/p/d728570bdf7b 小伙伴們有興趣的話自行跳轉(zhuǎn)過去看吧亡呵,這里就不重復(fù)介紹了。

4硫戈、制作長圖片分享到微信朋友圈與微信好友锰什。

那么我們需要做的第一步就是制作長圖片,代碼如下:
<pre><code>
func madelongPicture() -> UIImage {

    var image : UIImage!
    UIGraphicsBeginImageContext(self.textview.contentSize)
    var savedContentOffset      = self.textview.contentOffset
    var savedFrame              = self.textview.frame
    self.textview.contentOffset = CGPointZero
    self.textview.frame         = CGRectMake(0, 0, self.textview.contentSize.width, self.textview.contentSize.height)
    self.textview.layer.renderInContext(UIGraphicsGetCurrentContext())
    image                       = UIGraphicsGetImageFromCurrentImageContext()
    self.textview.contentOffset = savedContentOffset
    self.textview.frame         = savedFrame
    UIGraphicsEndPDFContext()
    return image
}

</code></pre>

TextView繼承自ScorllView丁逝,所以我們只需要給TextView進(jìn)行截圖汁胆,就可以制作一張長圖片了,方法如上霜幼。然后我們需要做的就是調(diào)用微信給我們的API嫩码,將圖片分享到朋友圈。

由于分享的話要申請AppId罪既,所以在這里沒有實現(xiàn)這個功能铸题,不過實現(xiàn)的方法并不復(fù)雜。

微信分享的文檔地址:https://open.weixin.qq.com/cgi-bin/showdocument?action=dir_list&t=resource/res_list&verify=1&lang=zh_CN

其實里頭已經(jīng)講的很清楚了琢感,有不明白的親可以留言哦~


5丢间、調(diào)用系統(tǒng)郵件發(fā)送文本

調(diào)用系統(tǒng)郵件,你可以將剛剛寫好的文章或者啥的發(fā)送給好朋友驹针,或者交給老師檢查~~~~~~~首先我們還是得制作長圖片烘挫,制作方法上面已經(jīng)講過了,就不重復(fù)累贅了柬甥,這里講一下如何調(diào)用系統(tǒng)郵件饮六。

首先你得繼承一個協(xié)議:MFMailComposeViewControllerDelegate

然后代碼如下:
<pre><code>
@IBAction func email(sender: AnyObject) {
UIApplication.sharedApplication().keyWindow?.endEditing(true)
var configuredMailComposeViewController = MailComposeViewController()
if canSendMail() {
presentViewController(configuredMailComposeViewController, animated: true, completion: nil)
} else {
showSendMailErrorAlert()
}
}

func MailComposeViewController() -> MFMailComposeViewController {
    let mailComposerVC                 = MFMailComposeViewController()
    mailComposerVC.mailComposeDelegate = self

    mailComposerVC.setToRecipients(nil)
    mailComposerVC.setSubject(nil)
    mailComposerVC.setMessageBody(self.textview.text, isHTML: false)
    var addPic                         = self.madelongPicture()
    var imageData                      = UIImagePNGRepresentation(addPic)
    mailComposerVC.addAttachmentData(imageData, mimeType: "", fileName: "longPicture.png")
    return mailComposerVC
}
func canSendMail() -> Bool {
    return MFMailComposeViewController.canSendMail()
}
func mailComposeController(controller: MFMailComposeViewController!, didFinishWithResult result: MFMailComposeResult, error: NSError!) {
    controller.dismissViewControllerAnimated(true, completion: nil)
}
func showSendMailErrorAlert() {
    let sendMailErrorAlert = UIAlertView(title: "Could Not Send Email", message: "Your device could not send e-mail.  Please check e-mail configuration and try again.", delegate: self, cancelButtonTitle: "OK")
    sendMailErrorAlert.show()
}

</code></pre>

代碼就在上面了其垄,自己感受一下的,解釋不動了卤橄。
效果如下:

1.png

接下來也許會造個輪子绿满,同時解決所有的BUG(至少我能發(fā)現(xiàn)的)。

代碼已上傳Github:https://github.com/superxlx/textDemo

親們窟扑,自己下載代碼感受一下棒口,然后喜歡的換請點個喜歡同時關(guān)注一下我。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末辜膝,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子漾肮,更是在濱河造成了極大的恐慌厂抖,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,948評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件克懊,死亡現(xiàn)場離奇詭異忱辅,居然都是意外死亡,警方通過查閱死者的電腦和手機谭溉,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,371評論 3 385
  • 文/潘曉璐 我一進(jìn)店門墙懂,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人扮念,你說我怎么就攤上這事损搬。” “怎么了柜与?”我有些...
    開封第一講書人閱讀 157,490評論 0 348
  • 文/不壞的土叔 我叫張陵巧勤,是天一觀的道長。 經(jīng)常有香客問我弄匕,道長颅悉,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,521評論 1 284
  • 正文 為了忘掉前任迁匠,我火速辦了婚禮剩瓶,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘城丧。我一直安慰自己延曙,他們只是感情好吭狡,可當(dāng)我...
    茶點故事閱讀 65,627評論 6 386
  • 文/花漫 我一把揭開白布玫氢。 她就那樣靜靜地躺著逆趣,像睡著了一般慧脱。 火紅的嫁衣襯著肌膚如雪昧谊。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,842評論 1 290
  • 那天涯冠,我揣著相機與錄音磁滚,去河邊找鬼。 笑死擦酌,一個胖子當(dāng)著我的面吹牛俱诸,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播赊舶,決...
    沈念sama閱讀 38,997評論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼睁搭,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了笼平?” 一聲冷哼從身側(cè)響起园骆,我...
    開封第一講書人閱讀 37,741評論 0 268
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎寓调,沒想到半個月后锌唾,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,203評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡夺英,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,534評論 2 327
  • 正文 我和宋清朗相戀三年晌涕,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片痛悯。...
    茶點故事閱讀 38,673評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡余黎,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出载萌,到底是詐尸還是另有隱情惧财,我是刑警寧澤,帶...
    沈念sama閱讀 34,339評論 4 330
  • 正文 年R本政府宣布炒考,位于F島的核電站可缚,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏斋枢。R本人自食惡果不足惜帘靡,卻給世界環(huán)境...
    茶點故事閱讀 39,955評論 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望瓤帚。 院中可真熱鬧描姚,春花似錦、人聲如沸戈次。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,770評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽怯邪。三九已至绊寻,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背澄步。 一陣腳步聲響...
    開封第一講書人閱讀 32,000評論 1 266
  • 我被黑心中介騙來泰國打工冰蘑, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人村缸。 一個月前我還...
    沈念sama閱讀 46,394評論 2 360
  • 正文 我出身青樓祠肥,卻偏偏與公主長得像,于是被迫代替她去往敵國和親梯皿。 傳聞我的和親對象是個殘疾皇子仇箱,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,562評論 2 349

推薦閱讀更多精彩內(nèi)容

  • ¥開啟¥ 【iAPP實現(xiàn)進(jìn)入界面執(zhí)行逐一顯】 〖2017-08-25 15:22:14〗 《//首先開一個線程,因...
    小菜c閱讀 6,367評論 0 17
  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 171,796評論 25 707
  • 發(fā)現(xiàn) 關(guān)注 消息 iOS 第三方庫东羹、插件剂桥、知名博客總結(jié) 作者大灰狼的小綿羊哥哥關(guān)注 2017.06.26 09:4...
    肇東周閱讀 12,066評論 4 62
  • 尋找女神的秘密 上篇提到雅典娜原本是一個其貌不揚, 口才普通属提,際遇一般的年輕女子渊额, 為了實現(xiàn)幸福人生, 獲得真愛垒拢,...
    愛在六次元閱讀 379評論 0 0
  • 著急忙慌去做事,在岔路口看見老爺爺和老奶奶正在分別火惊,手舉高求类,直到一起轉(zhuǎn)身走各自的路。兩條路之間隔著竹子屹耐,老奶奶落落...
    睡神YZY閱讀 252評論 0 0