這一篇我們將實現(xiàn)一個富文本編輯器,擁有功能:
- 1、斜體、下劃線混排。
- 2、圖文混排
- 3、字體大小。
- 4、選擇自定義字體。
- 5、制作長圖片分享到微信朋友圈與微信好友。
- 6、調用系統(tǒng)郵件發(fā)送文本。
先來看一下大體的效果吧,還有一些效果將在后面演示:
(寫在最前面,這個Demo存在大量BUG,我只是通過他來演示一些功能,也許在后面我會做一個完整的APP,到時候也會再來寫一遍,來說說一些BUG如何處理)。
富文本編輯器在以前需要使用CoreText來實現(xiàn),但是不得不說這真的是一個不小的工程,但是在iOS7發(fā)布以后,apple發(fā)布了TextKit,通過TextKit我們能夠輕松實現(xiàn)很多從前難以實現(xiàn)的功能。
1、斜體、下劃線混排、字體的增大以及減小
在SB中拖入一個UITextView,此后的所有操作都是對這個TextView中的文字進行操作,先來看幾行代碼:
<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類型的值,應該不難理解。
以上代碼段的功能就是給textview的字符串的第0個字符開始,連續(xù)五個字符添加斜體的效果。
是不是十分方便?~~~~~是的。
以上內容只是為了演示UITextView中的attributedText屬性,事實上我們不需要這么做(感謝劉大大,告訴我接下來這種做法)。
在TextView中有一個屬性叫做typingAttributes,xcode對這個屬性的解釋是這樣的automatically resets when the selection changes,意思就是我們對這個屬性進行設置可以改變接下來改變的文字。
也許這樣說,不能讓人太好的理解,我們在按鈕中添加以下代碼
<pre><code>
@IBAction func Obliqueness(sender: AnyObject) {
textview.typingAttributes[NSObliquenessAttributeName] = (textview.typingAttributes[NSObliquenessAttributeName] as? NSNumber) == 0 ? 0.5 : 0
}
</code></pre>
當** 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))
}
/**
設置斜體
:param: sender
*/
@IBAction func Obliqueness(sender: AnyObject) {
textview.typingAttributes[NSObliquenessAttributeName] = (textview.typingAttributes[NSObliquenessAttributeName] as? NSNumber) == 0 ? 0.5 : 0
}
/**
設置下劃線
:param: sender
*/
@IBAction func underline(sender: AnyObject) {
self.textview.typingAttributes[NSUnderlineStyleAttributeName] = (NSUnderlineStyle.StyleSingle.hashValue ) == 0 ? 1 : NSUnderlineStyle.StyleSingle.hashValue
}
/**
</code></pre>
實現(xiàn)方法都是類似的,十分方便的已經實現(xiàn)了很多功能,這放在以前是不可能的(其實我不知道以前實現(xiàn)究竟有多復雜——!)。
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、獲取當前的attributedString
- 2、新建一個NSTextAttachment,設置他的圖片屬性
- 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為拍照、選擇完進入圖片編輯模式
imagePickerController.sourceType = sourceType
self.presentViewController(imagePickerController, animated: true, completion: {
})
}
}
</code></pre>
首先是彈出一個alertView,讓你進行選擇,選擇以后,將調用下面的方法,進入到相冊進行選擇圖片。在這里你需要繼承幾個協(xié)議,不然在選擇以后不會觸發(fā)下面的方法:UIActionSheetDelegate,UIImagePickerControllerDelegate。同時進入相冊你需要添加幾個庫:AssetsLibrary.framework和MobileCoreServices.framework。具體代碼解釋在這里就不行進解釋,今天我們把重點放在富文本的實現(xiàn)上。當你選擇圖片以后,將促發(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ù)中我們給文本插入圖片,插入方法在前面已經說過了。
當我們選擇圖片以后你會發(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>
這個方法將圖片的寬度設置為屏幕的寬度,高度按比例縮放。
好的~~~~~我們終于實現(xiàn)了插入圖片,其實在這里有一個很大的問題,就是下面這句話:
<pre><code>
textview.attributedText = string
</code></pre>
我們每次插入圖片都將TextView的內容全部改變了一次,這樣的做法,先不提在大量文字的情況下可能造成的卡頓問題,同時造成了編排問題,有同學可能已經發(fā)現(xiàn)了,當我們用這樣的方法插入圖片以后,當我們再次改變屬性的時候,視圖將會瞬間調到最上面,原因就是這句話。至于如何解決~~~~還沒想到——!
3、選擇字體
改變字體的方法其實和我們設置斜體,下劃線等是一樣的,方法如下:
<pre><code>
func lovefont(sender:AnyObject){
self.textview.typingAttributes[NSFontAttributeName] = UIFont(name: "1-", size: (CGFloat)(self.fontSize))
}
</code></pre>
那么我們現(xiàn)在的問題就是自定義字體了,畢竟xcode的字體大多不支持中文,同時中文顯示的時候不那么優(yōu)雅,我們要說的就是自定義字體。
加載自定義字體,并不是太過復雜,我在簡書看到這篇文章描述加載自定義字體就感覺寫的很好,http://www.lxweimin.com/p/d728570bdf7b 小伙伴們有興趣的話自行跳轉過去看吧,這里就不重復介紹了。
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進行截圖,就可以制作一張長圖片了,方法如上。然后我們需要做的就是調用微信給我們的API,將圖片分享到朋友圈。
其實里頭已經講的很清楚了,有不明白的親可以留言哦~
5、調用系統(tǒng)郵件發(fā)送文本
調用系統(tǒng)郵件,你可以將剛剛寫好的文章或者啥的發(fā)送給好朋友,或者交給老師檢查~~~~~~~首先我們還是得制作長圖片,制作方法上面已經講過了,就不重復累贅了,這里講一下如何調用系統(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>
代碼就在上面了,自己感受一下的,解釋不動了。
效果如下:
接下來也許會造個輪子,同時解決所有的BUG(至少我能發(fā)現(xiàn)的)。
代碼已上傳Github:https://github.com/superxlx/textDemo
親們,自己下載代碼感受一下,然后喜歡的換請點個喜歡同時關注一下我。