首页 > 编程语言 > 详细

Swift Textkit 图文混排实现

时间:2016-04-08 02:12:56      阅读:553      评论:0      收藏:0      [点我收藏+]

用Swift写了一个Textkit图文混排Demo,类似新浪微博的头条文章编辑功能

?

实现如下功能:

?

  • 支持图片作为附件插入到文本中
  • 监听键盘弹出自动改变滚动属性
  • 自动折行并滚动到折行的位置
  • 支持导出纯文本内容(图片使用img标签包起,方便向服务器端提交)
  • 支持点击后删除图片附件

效果如下:

bubuko.com,布布扣bubuko.com,布布扣

?

源码地址如下:

https://github.com/thierryxing/swift-textkit-demo

?

这个版本刚刚写完,目前还有很多需要改进的地方,希望有兴趣的同学可以和我一块维护

?

贴上部分代码:

class TextKitViewController: UIViewController, UITextViewDelegate, NSTextStorageDelegate  {

    let textStorage:NSTextStorage = NSTextStorage()
    let layoutManger = NSLayoutManager()
    let textViewInset:CGFloat = 10.0
    let toolbarHeight:CGFloat = 50.0
    
    var container:NSTextContainer?
    var textContent:NSMutableAttributedString = NSMutableAttributedString(string: "The NSParagraphStyle class and its subclass NSMutableParagraphStyle encapsulate the paragraph or ruler attributes used by the NSAttributedString classes.", attributes: nil);
    var textView:UITextView?
    var range:NSRange = NSRange.init(location: 0, length: 0)
    var viewWidth:CGFloat? = nil
    var viewHeight:CGFloat? = nil
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        viewWidth = self.view.frame.size.width
        viewHeight = self.view.frame.size.height
        
        self.addKeyboardNotification()
        self.initTextView()
        self.initToolbar()
    }
    
    func addKeyboardNotification(){
        NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(keyboardShow), name: UIKeyboardWillShowNotification, object: nil)
        NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(keyboardHide), name: UIKeyboardWillHideNotification, object: nil)
    }
    
    func initTextView(){
        container = NSTextContainer(size:CGSizeMake(viewWidth!, CGFloat.max))
        container!.widthTracksTextView = true;
        layoutManger.addTextContainer(container!)
        textStorage.addLayoutManager(layoutManger)
        textStorage.delegate = self
        
        textView = UITextView(frame: self.view.bounds, textContainer: container);
        textView?.autoresizingMask = UIViewAutoresizing.FlexibleHeight
        textView?.scrollEnabled = true;
        textView?.textContainerInset = UIEdgeInsetsMake(textViewInset, textViewInset, 0, textViewInset)
        textView?.keyboardDismissMode = UIScrollViewKeyboardDismissMode.OnDrag;
        textView?.dataDetectorTypes = UIDataDetectorTypes.None
        textView?.delegate = self
        textView?.editable = true
        textView?.selectable = true
        self.view.addSubview(textView!)
        
        textStorage.setAttributedString(textContent);
    }
    
    func initToolbar(){
        let numberToolbar = UIToolbar(frame: CGRectMake(0, 0, self.view.frame.size.width, toolbarHeight))
        numberToolbar.barStyle = UIBarStyle.Default
        numberToolbar.items = [
            UIBarButtonItem(title: "Insert Picture", style: UIBarButtonItemStyle.Plain, target: self, action: #selector(insertPicture)),
            UIBarButtonItem(title: "Export Plain Text", style: UIBarButtonItemStyle.Plain, target: self, action: #selector(exportPlainText))]
        numberToolbar.sizeToFit()
        textView!.inputAccessoryView = numberToolbar
    }
    
    
    //MARK: Toolbar function
    /**
     insert picture in textview
     */
    func insertPicture(){
        textStorage.beginEditing()
        let image = GMImage(data: UIImagePNGRepresentation(UIImage(named: "testImage")!)!)
        // set remote url, cause you may want to send it to server
        image?.remoteUrl = "http://7xjlg5.com1.z0.glb.clouddn.com/1.png"
        let imgAttachment = NSTextAttachment(data: nil, ofType: nil)
        let imageWidth = viewWidth!-textViewInset*3
        let blankString = NSMutableAttributedString(string: "\n\n", attributes: nil)
        imgAttachment.image = image
        imgAttachment.bounds = CGRectMake(0, 0, imageWidth, image!.size.height*(imageWidth/image!.size.width))
        
        let imgAttachmentString = NSAttributedString(attachment:imgAttachment)
        
        if range.location==0 || range.location>textContent.length {
            textContent.appendAttributedString(blankString)
            textContent.appendAttributedString(imgAttachmentString)
            textContent.appendAttributedString(blankString)
        }else{
            textContent.insertAttributedString(blankString, atIndex: range.location)
            textContent.insertAttributedString(imgAttachmentString, atIndex: range.location+blankString.length)
            textContent.insertAttributedString(NSMutableAttributedString(string: "\n\n", attributes: nil), atIndex: range.location+imgAttachmentString.length+blankString.length)
        }
        textStorage.setAttributedString(textContent)
        textStorage.endEditing()
        textView!.scrollRangeToVisible(NSMakeRange(textView!.attributedText.length, 0))
    }
    
    func exportPlainText(){
        let exportTextStorage = NSTextStorage()
        exportTextStorage.setAttributedString(textContent)
        exportTextStorage.enumerateAttribute(NSAttachmentAttributeName, inRange: NSMakeRange(0, textStorage.length), options:.LongestEffectiveRangeNotRequired) { (value, range, stop) in
            if (value != nil) {
                if value is NSTextAttachment{
                    let attachment = value as! NSTextAttachment
                    let imgTag = "<img src=‘\((attachment.image as! GMImage).remoteUrl)‘/>"
                    exportTextStorage.replaceCharactersInRange(range, withString: imgTag)
                }
            }
        }
        NSLog("%@", exportTextStorage.string)
    }
    
    
    // MARK: textView Delegate
    func textViewDidChange(textView: UITextView) {
        textContent = textView.attributedText.mutableCopy() as! NSMutableAttributedString
    }
    
    func textView(textView: UITextView, shouldChangeTextInRange range: NSRange, replacementText text: String) -> Bool {
        textView.scrollRangeToVisible(range)
        return true;
    }
    
    func textViewDidChangeSelection(textView: UITextView) {
        range = textView.selectedRange;
        if textStorage.length>=range.location-1{
        if let _:NSTextAttachment = textStorage.attribute(NSAttachmentAttributeName, atIndex: range.location-1, effectiveRange: nil) as? NSTextAttachment{
                confirmDeleteImage(NSMakeRange(range.location-3, 3))
                textView.selectedRange = NSMakeRange(1, 1)
            }
        }
    }
    
    func confirmDeleteImage(range:NSRange){
        textView?.resignFirstResponder()
        let alertController = UIAlertController(title: "Delete this image?", message:"", preferredStyle: .ActionSheet)
        let cancelAction = UIAlertAction(title: "Cancel", style: UIAlertActionStyle.Cancel, handler: nil)
        let okAction = UIAlertAction(title: "OK", style: UIAlertActionStyle.Default, handler: { (action: UIAlertAction!) in
            self.textStorage.beginEditing()
            self.textContent.deleteCharactersInRange(range)
            self.textStorage.setAttributedString(self.textContent)
            self.textStorage.endEditing()
        })
        alertController.addAction(cancelAction)
        alertController.addAction(okAction)
        self.presentViewController(alertController, animated: true, completion: nil)
    }
    
    
    // MARK: keyboard Event handle
    func keyboardShow(noti:NSNotification){
        let userInfo:Dictionary = noti.userInfo!
        let keyboardSize = userInfo[UIKeyboardFrameBeginUserInfoKey]!.CGRectValue.size
        textView?.frame = CGRectMake(0, 0, viewWidth!, viewHeight! - keyboardSize.height - 10)
    }
    
    func keyboardHide(noti:NSNotification){
        textView?.frame = self.view.bounds
    }
    
    
    // MARK: lifecycle
    deinit{
        NSNotificationCenter.defaultCenter().removeObserver(self)
    }
    
    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }
}

?

Swift Textkit 图文混排实现

原文:http://thierry-xing.iteye.com/blog/2289374

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!