Home > Enterprise >  How to save image and text in UITextView in IOS?
How to save image and text in UITextView in IOS?

Time:10-01

I am adding both text and image in UITextView to part of my app ( similar to the notes app ). The user can write a text and/or then select a picture from the photo library or take a picture ( with image picker).

I managed to add the text and the image into the UITextView. I can save the text but can’t figure out how to save the image. I have looked very similar questions but still having a hard time getting the code. I have tried to do it with userDefaults but apparently it’s not the right way. Maybe documents directory or file path but I don’t know how to do that. Any help will be much appreciate it.

This is the code I have:

class NotesViewController: UIViewController, UITextViewDelegate, UIImagePickerControllerDelegate, UINavigationControllerDelegate {

   @IBOutlet weak var textView: UITextView!
   var pickImage: UIImage!
   var attString = NSAttributedString()

 override func viewDidLoad() {
    super.viewDidLoad()

    textView.delegate = self
    self.isModalInPresentation = true
    textView.keyboardDismissMode = .interactive  // .onDrag
    
    textView.becomeFirstResponder()
    
    textView.textColor = UIColor.self.init(red: 222/255, green: 215/255, blue: 191/255, alpha: 1.0)
    textView.font = UIFont(name: "Trebuchet MS", size: 19)
    textView.backgroundColor = UIColor.clear
    textView.tintColor = UIColor.self.init(red: 141/255, green: 124/255, blue: 85/255, alpha: 1.0)
    
    textView.layer.masksToBounds = false


    if let value = userDefault.value(forKey: myNotes) as? String {

        textView.text = value

    }
    textView.alwaysBounceVertical = true


    }

 func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {

      pickImage = info[UIImagePickerController.InfoKey.originalImage] as? UIImage

      //create and NSTextAttachment and add your image to it.
      let attachment = NSTextAttachment()
      attachment.image = pickImage

      //calculate new size.  (-20 because I want to have a litle space on the right of picture)
      let newImageWidth = (textView.bounds.size.width - 15 )
      let scale = newImageWidth/pickImage.size.width
      let newImageHeight = pickImage.size.height * scale - 20

      //resize this
      attachment.bounds = CGRect.init(x: 0, y: 0, width: newImageWidth, height: newImageHeight)

      //put your NSTextAttachment into and attributedString
      attString = NSAttributedString(attachment: attachment)

      //add this attributed string to the current position.
      textView.textStorage.insert(attString, at: textView.selectedRange.location)
      textView.selectedRange.location  = 1
      
      textView.textColor = UIColor.self.init(red: 222/255, green: 215/255, blue: 191/255, alpha: 1.0)
      textView.font = UIFont(name: "Trebuchet MS", size: 19)
      textView.backgroundColor = UIColor.clear
      textView.tintColor = UIColor.self.init(red: 141/255, green: 124/255, blue: 85/255, alpha: 1.0)
      textView.keyboardDismissMode = .interactive

      picker.dismiss(animated: true, completion: nil)

 }

 func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
       picker.dismiss(animated: true, completion: nil)
    }

 @objc func saveText() {

    userDefault.setValue(textView.text, forKey: myNotes)
    dismiss(animated: true, completion: nil)
  
   }

 }

CodePudding user response:

There are one important you need to know:

  • Everything you customize like add image, add icon, ... you always do on NSAttributedString not the plain text.

So at your func saveText you call:

userDefault.setValue(textView.text, forKey: myNotes)

Means that you store only the plain text from your textView which is textView.text but not storing all the special attributes combine in your textView which is textView.attributedText. That's the main reason you not getting the image with you when saving.

For do that, you need to make two function: One to store your attributed text to UserDefault and one to get from UserDefault to appear

For the first one, which is store your attributed text to UserDefault. We can not save directly NSAttributedString to UserDefault so we need to convert it to Data first and store it.

func saveAttributedTextToUserDefault(attributedText: NSAttributedString, key: String) {
    do {
        let data = try attributedText.data(from: NSRange(location: 0, length: attributedText.length), documentAttributes: [.documentType: NSAttributedString.DocumentType.rtfd])
        UserDefaults.standard.setValue(data, forKeyPath: key)
    } catch {
        print(error)
    }
}

The second one, simply get the data from UserDefault and convert it back to NSAttributedString

func getAttributedTextFromUserDefault(key: String) -> NSAttributedString {
    if let dataValue = UserDefaults.standard.value(forKey: key) as? Data {
        do {
            let attributeText = try NSAttributedString(data: dataValue, documentAttributes: nil)
            return attributeText
        } catch {
            print("error: ", error)
        }

    }

    return NSAttributedString()
}

The usage

override func viewDidLoad() {
    // your others code
    let attributedText = self.getAttributedTextFromUserDefault(key: "test")
    textView.attributedText = attributedText
}

@objc func saveText() {
    // take attributedText and save it
    self.saveAttributedTextToUserDefault(attributedText: textView.attributedText, key: "test")

    dismiss(animated: true, completion: nil)
}
  • Related