8

How to solve this issue in iOS 13? I am taking screenshot of UITextView content size..Till iOS 12 everything is working fine. But issue with iOS 13 onwards it's not taking full screenshot it's cutting. Below is output picture for less than iOS 12 and after iOS 13. Less than iOS 12

iOS 13

Below is code I'm using to take screenshot of UITextView:

let textView = UITextView()
UIGraphicsBeginImageContextWithOptions(textView.contentSize, textView.isOpaque, 0.0)
let savedContentOffset: CGPoint = textView.contentOffset
let savedFrame: CGRect = textView.frame
textView.frame = CGRect(x: 0, y: 0, width: textView.contentSize.width, height: textView.contentSize.height)
textView.layer.render(in: UIGraphicsGetCurrentContext()!)
let image = UIGraphicsGetImageFromCurrentImageContext()
textView.contentOffset = savedContentOffset
textView.frame = savedFrame
UIGraphicsEndImageContext()

I got the solution for this issue Below is UPDATED WORKING CODE

OPTION 1:- Below code using UILabel

let SCREEN_WIDTH = UIScreen.main.bounds.size.width
let SCREEN_HEIGHT = UIScreen.main.bounds.size.height
func buttonAction() {
    let textView = UITextView()
    textView.frame = CGRect(x: 10, y: 50, width: SCREEN_WIDTH - 20, height: SCREEN_HEIGHT * 2)
    let lab = UILabel(frame: CGRect(x: 0, y: 0, width: SCREEN_WIDTH - 20, height: textView.contentSize.height))
    lab.backgroundColor = UIColor.white
    lab.font = textView.font
    lab.textColor = UIColor.black
    lab.numberOfLines = 0
    lab.text = textView.text
    textView.addSubview(lab)

    UIGraphicsBeginImageContextWithOptions(CGSize(width: SCREEN_WIDTH - 20, height: textView.contentSize.height), _: true, _: 1)
    if let context = UIGraphicsGetCurrentContext() {
        lab.layer.render(in: context)
    }
    let image = UIGraphicsGetImageFromCurrentImageContext()
    UIGraphicsEndImageContext()
    textView.frame = CGRect(x: 10, y: 50, width: SCREEN_WIDTH - 20, height: SCREEN_HEIGHT * 2)
    lab.removeFromSuperview()

}

OPTION 2:- Below code using TempView

let SCREEN_WIDTH = UIScreen.main.bounds.size.width
let SCREEN_HEIGHT = UIScreen.main.bounds.size.height

func buttonAction() {
   let textView = UITextView()
   textView.frame = CGRect(x: 10, y: 50, width: SCREEN_WIDTH - 20, height: SCREEN_HEIGHT * 2)
UIGraphicsBeginImageContextWithOptions(CGSize(width: SCREEN_WIDTH - 20, height: textView.contentSize.height), _: true, _: 1)
if #available(iOS 13, *) {
    // iOS 13 (or newer)
    let tempView = UIView(frame: CGRect(x: 0, y: 0, width: textView.contentSize.width, height: textView.contentSize.height))
    tempView.addSubview(textView)
    if let context = UIGraphicsGetCurrentContext() {
        tempView.layer.render(in: context)
    }
    tempView.removeFromSuperview()
    view.addSubview(textView)
} else {
    // iOS 12 or older
    if let context = UIGraphicsGetCurrentContext() {
        textView.layer.render(in: context)
    }
}

OPTION 3:- Try to use third party library i have used YYTextView https://github.com/ibireme/YYText

Aslam
  • 231
  • 1
  • 3
  • 15
  • Did you try the newer `UIGraphicsImageRenderer`? [Screenshot in Swift iOS?](https://stackoverflow.com/questions/25444609/screenshot-in-swift-ios) – Cœur Oct 24 '19 at 01:39

5 Answers5

2

Don't draw the layer, use the attributedText instead

let size = self.textView.contentSize
UIGraphicsBeginImageContextWithOptions(size, self.textView.isOpaque, 0)
//the textView has 8 margin
textView.attributedText.draw(in: CGRect.init(x: 0, y: 0, width: size.width - 16, height: size.height))
let image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
Code Farmer
  • 194
  • 5
  • Thanks for reply.Actually i want draw on layer.bcoz i have to add images also in that textview.. – Aslam Oct 16 '19 at 06:21
  • Use NSTextAttachment to add images,the attributedText also can draw correctly – Code Farmer Oct 16 '19 at 09:15
  • ya i agree.but our requirement is different..images can drag,resize,rotate,expand..all these i cant do using NSTextAttachment.. – Aslam Oct 17 '19 at 02:25
0

The following worked for me

extension UITextView {
/**
 Convert TextView to UIImage
 */
 func toImage() -> UIImage? {
    UIGraphicsBeginImageContextWithOptions(self.bounds.size, self.isOpaque, 0.0)
    defer { UIGraphicsEndImageContext() }
    if let context = UIGraphicsGetCurrentContext() {
        self.layer.render(in: context)
        let image = UIGraphicsGetImageFromCurrentImageContext()
        return image
    }
    return nil
  }
}

Use:

UIImageWriteToSavedPhotosAlbum(self.textView.toImage()!,self, nil, nil)
Hiền Đỗ
  • 526
  • 6
  • 14
0

Seems that the issue is with the layer for me setting the content size for the layer worked. before the render in context set the layer frame property with the size required this will draw the complete content in the image. hope this helps

0

To get this to work, I had to use a UILabel when rendering.

It's configured with the same constraints/font/text as the textview, and when rendering - set the text in the label, hide the textview and show the label, and vice versa. Perhaps a little less complicated for me since the view I am rendering is not on the screen, but might still be an option.

Edd677
  • 13
  • 3
  • Thanx for you reply..Using uilabel its working..But i have to use TextView only because need to mulitple images.that images can drag,resize,expand then need to take screenshot..I think using UILabel not able to achieve our requirement..Can you suggest any other solution for this – Aslam Oct 19 '19 at 02:25
0

Try to use UIlabel or TempView or Third party library Below is Working code

OPTION 1:- Below code using UILabel

let SCREEN_WIDTH = UIScreen.main.bounds.size.width
let SCREEN_HEIGHT = UIScreen.main.bounds.size.height
func buttonAction() {
    let textView = UITextView()
    textView.frame = CGRect(x: 10, y: 50, width: SCREEN_WIDTH - 20, height: SCREEN_HEIGHT * 2)

    let lab = UILabel(frame: CGRect(x: 0, y: 0, width: SCREEN_WIDTH - 20, height: textView.contentSize.height))
    lab.backgroundColor = UIColor.white
    lab.font = textView.font
    lab.textColor = UIColor.black
    lab.numberOfLines = 0
    lab.text = textView.text
    textView.addSubview(lab)

    UIGraphicsBeginImageContextWithOptions(CGSize(width: SCREEN_WIDTH - 20, height: textView.contentSize.height), _: true, _: 1)
    if let context = UIGraphicsGetCurrentContext() {
        lab.layer.render(in: context)
    }
    let image = UIGraphicsGetImageFromCurrentImageContext()
    UIGraphicsEndImageContext()

    textView.frame = CGRect(x: 10, y: 50, width: SCREEN_WIDTH - 20, height: SCREEN_HEIGHT * 2)
    lab.removeFromSuperview()

}

OPTION 2:- Below code using TempView

let SCREEN_WIDTH = UIScreen.main.bounds.size.width
let SCREEN_HEIGHT = UIScreen.main.bounds.size.height

func buttonAction() {
   let textView = UITextView()
   textView.frame = CGRect(x: 10, y: 50, width: SCREEN_WIDTH - 20, height: SCREEN_HEIGHT * 2)
   UIGraphicsBeginImageContextWithOptions(CGSize(width: SCREEN_WIDTH - 20, height: textView.contentSize.height), _: true, _: 1)

   if #available(iOS 13, *) {
    // iOS 13 (or newer)
    let tempView = UIView(frame: CGRect(x: 0, y: 0, width: textView.contentSize.width, height: textView.contentSize.height))
    tempView.addSubview(textView)
    if let context = UIGraphicsGetCurrentContext() {
        tempView.layer.render(in: context)
    }
    tempView.removeFromSuperview()
    view.addSubview(textView)
 } else {
    // iOS 12 or older
    if let context = UIGraphicsGetCurrentContext() {
        textView.layer.render(in: context)
    }
}

OPTION 3:- Try to use third party library i have used YYTextView https://github.com/ibireme/YYText

Aslam
  • 231
  • 1
  • 3
  • 15