干货|swift,富文本编辑器
这一篇我们将实现一个富文本编辑器,拥有功能:
- 1、斜体、下划线混排。
- 2、图文混排
- 3、字体大小。
- 4、选择自定义字体。
- 5、制作长图片分享到微信朋友圈与微信好友。
- 6、调用系统邮件发送文本。
先来看一下大体的效果吧,还有一些效果将在后面演示:
(写在最前面,这个Demo存在大量BUG,我只是通过他来演示一些功能,也许在后面我会做一个完整的APP,到时候也会再来写一遍,来说说一些BUG如何处理)。
富文本编辑器在以前需要使用CoreText来实现,但是不得不说这真的是一个不小的工程,但是在iOS7发布以后,apple发布了TextKit,通过TextKit我们能够轻松实现很多从前难以实现的功能。
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)
这个函数给字符串添加了属性,这个API的第1、2个参数就是确定添加的属性类型,在这里我们添加的就是斜体这个属性,斜体这个属性的Value参数填写0~1之间的数值,在这个我们填写的是0.5.来看第二个参数,第二个参数是添加属性的范围,填写的是一个NSRange类型的值,应该不难理解。
以上代码段的功能就是给textview的字符串的第0个字符开始,连续五个字符添加斜体的效果。
是不是十分方便?~~~~~是的。
以上内容只是为了演示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时,点击按钮将将之改变为1,为1时则相反。我们点一下试试,神奇的事情发生啦啦啦啦~~~接下来我们输入的文字都变成了斜体。再次点击则变回正常。
以此类推,我们写出下划线、字体的增大以及减小的代码。
<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>
实现方法都是类似的,十分方便的已经实现了很多功能,这放在以前是不可能的(其实我不知道以前实现究竟有多复杂——!)。
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、将刚刚创建的NSTextAttachment,添加在原本的attributedString的最后面
- 4、重定义** textview.attributedText **
以上代码中出现一个变量img,这个变量就是从系统相册获取图片,代码如下:
<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,让你进行选择,选择以后,将调用下面的方法,进入到相册进行选择图片。在这里你需要继承几个协议,不然在选择以后不会触发下面的方法:UIActionSheetDelegate,UIImagePickerControllerDelegate。同时进入相册你需要添加几个库:AssetsLibrary.framework和MobileCoreServices.framework。具体代码解释在这里就不行进解释,今天我们把重点放在富文本的实现上。当你选择图片以后,将促发以下方法,这也是前面添加的协议的功能。
<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>
同时在这个函数中我们给文本插入图片,插入方法在前面已经说过了。
当我们选择图片以后你会发现由于图片太大,所以在界面上只能显示一部分,那么我们就需要压缩图片,压缩方法如下:
<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>
这个方法将图片的宽度设置为屏幕的宽度,高度按比例缩放。
好的~~~~~我们终于实现了插入图片,其实在这里有一个很大的问题,就是下面这句话:
<pre><code>
textview.attributedText = string
</code></pre>
我们每次插入图片都将TextView的内容全部改变了一次,这样的做法,先不提在大量文字的情况下可能造成的卡顿问题,同时造成了编排问题,有同学可能已经发现了,当我们用这样的方法插入图片以后,当我们再次改变属性的时候,视图将会瞬间调到最上面,原因就是这句话。至于如何解决~~~~还没想到——!
3、选择字体
改变字体的方法其实和我们设置斜体,下划线等是一样的,方法如下:
<pre><code>
func lovefont(sender:AnyObject){
self.textview.typingAttributes[NSFontAttributeName] = UIFont(name: "1-", size: (CGFloat)(self.fontSize))
}
</code></pre>
那么我们现在的问题就是自定义字体了,毕竟xcode的字体大多不支持中文,同时中文显示的时候不那么优雅,我们要说的就是自定义字体。
加载自定义字体,并不是太过复杂,我在简书看到这篇文章描述加载自定义字体就感觉写的很好,http://www.jianshu.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,将图片分享到朋友圈。
由于分享的话要申请AppId,所以在这里没有实现这个功能,不过实现的方法并不复杂。其实里头已经讲的很清楚了,有不明白的亲可以留言哦~
5、调用系统邮件发送文本
调用系统邮件,你可以将刚刚写好的文章或者啥的发送给好朋友,或者交给老师检查~~~~~~~首先我们还是得制作长图片,制作方法上面已经讲过了,就不重复累赘了,这里讲一下如何调用系统邮件。
首先你得继承一个协议: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(至少我能发现的)。
代码已上传Github:https://github.com/superxlx/textDemo
亲们,自己下载代码感受一下,然后喜欢的换请点个喜欢同时关注一下我。