Blur Uitextview's Text

How to reduce the quality of the text inside UITextView with Swift

You can drop the quality of the layer by making it rasterized and reducing the scale of it:

let badQualityRatio: CGFloat = 4
textView.layer.shouldRasterize = true
textView.layer.rasterizationScale = UIScreen.main.scale/badQualityRatio

Result:

Result

you can set the rasterizationScale any number between 0 and UIScreen.main.scale

UITextView Fonts are bluring after Zoom IN

Finally, I was able to fix this issue using contentScale , it should be update for UIView and layer of the UIView and subviews and sub-layers of the particular UIView. otherwise, it will not be working.

func scaleView( view: UIView, scale: CGFloat ){
view.contentScaleFactor = scale
for vi in view.subviews {
scaleView(view: vi, scale: scale)
}
}

func scaleLayer( layer: CALayer, scale: CGFloat ){
layer.contentsScale = scale
if layer.sublayers == nil {
return
}
for la in layer.sublayers! {
scaleLayer(layer: la, scale: scale)
}
}

We should call the above two methods for UITextView in scrollViewDidEndZooming (which is inherited from UIScrollViewDelegate) method.

func scrollViewDidEndZooming(_ scrollView: UIScrollView, with view: UIView?, atScale scale: CGFloat) {
scaleView(view: textView, scale: scale)
scaleLayer(layer: textView.layer, scale: scale)
}

But for the zoom-out feature, please don't set scale value directly then quality will lose. So need to keep the threshold value, it should be calculated according to your usage.

Scale UITextView and maintain text clarity

You need to change the UIFont size when you scale up your UITextView.

Otherwise your text will get blurry because you are scaling up the actual frame of the UITextView together with the text but the current UIFont is still a small size so you will see it as pixelated and blurry.

EDIT:
Calculate font size:

Resize font size to fill UITextView?

iOS TextView is saved blurry when scaled

Here's a quick example using a UIView extension from this accepted answer: https://stackoverflow.com/a/51944513/6257435

We'll create a UITextView with a size of 240 x 129. Then add 4 buttons to capture the text view at 1x, 2x, 5x and 10x scale.

It looks like this when running:

Sample Image

and the result...

At 1x scale - 240 x 129 pixels:

Sample Image

At 2x scale - 480 x 258 pixels:

Sample Image

At 5x scale - 1200 x 645 pixels (just showing a portion):

Sample Image

At 10x scale - 2400 x 1290 pixels (just showing a portion):

Sample Image

The extension:

extension UIView {
func scale(by scale: CGFloat) {
self.contentScaleFactor = scale
for subview in self.subviews {
subview.scale(by: scale)
}
}

func getImage(scale: CGFloat? = nil) -> UIImage {
let newScale = scale ?? UIScreen.main.scale
self.scale(by: newScale)

let format = UIGraphicsImageRendererFormat()
format.scale = newScale

let renderer = UIGraphicsImageRenderer(size: self.bounds.size, format: format)

let image = renderer.image { rendererContext in
self.layer.render(in: rendererContext.cgContext)
}

return image
}
}

Sample controller code:

class TextViewCapVC: UIViewController {
let textView = UITextView()
let resultLabel = UILabel()

override func viewDidLoad() {
super.viewDidLoad()

// add a stack view with buttons
let stack = UIStackView()
stack.axis = .vertical
stack.spacing = 12

[1, 2, 5, 10].forEach { i in
let btn = UIButton()
btn.setTitle("Create Image at \(i)x scale", for: [])
btn.setTitleColor(.white, for: .normal)
btn.setTitleColor(.lightGray, for: .highlighted)
btn.backgroundColor = .systemBlue
btn.tag = i
btn.addTarget(self, action: #selector(gotTap(_:)), for: .touchUpInside)
stack.addArrangedSubview(btn)
}

[textView, stack, resultLabel].forEach { v in
v.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(v)
}

let g = view.safeAreaLayoutGuide
NSLayoutConstraint.activate([

// text view 280x240, 20-points from top, centered horizontally
textView.topAnchor.constraint(equalTo: g.topAnchor, constant: 20.0),
textView.centerXAnchor.constraint(equalTo: g.centerXAnchor),
textView.widthAnchor.constraint(equalToConstant: 240.0),
textView.heightAnchor.constraint(equalToConstant: 129.0),

// stack view, 20-points from text view, same width, centered horizontally
stack.topAnchor.constraint(equalTo: textView.bottomAnchor, constant: 20.0),
stack.centerXAnchor.constraint(equalTo: g.centerXAnchor),
stack.widthAnchor.constraint(equalTo: textView.widthAnchor),

// result label, 20-points from stack view
// 20-points from leading/trailing
resultLabel.topAnchor.constraint(equalTo: stack.bottomAnchor, constant: 20.0),
resultLabel.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 20.0),
resultLabel.trailingAnchor.constraint(equalTo: g.trailingAnchor, constant: -20.0),

])

let string = "Test"

let attributes: [NSAttributedString.Key: Any] = [
.foregroundColor: UIColor.blue,
.font: UIFont.italicSystemFont(ofSize: 104.0),
]

let attributedString = NSMutableAttributedString(string: string, attributes: attributes)
textView.attributedText = attributedString

resultLabel.font = .systemFont(ofSize: 14, weight: .light)
resultLabel.numberOfLines = 0
resultLabel.text = "Results:"

// so we can see the view frames
textView.backgroundColor = .yellow
resultLabel.backgroundColor = .cyan

}

@objc func gotTap(_ sender: Any?) {
guard let btn = sender as? UIButton else { return }

let scaleFactor = CGFloat(btn.tag)

let img = textView.getImage(scale: scaleFactor)

var s: String = "Results:\n\n"

let documents = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0]
let fName: String = "\(btn.tag)xScale-\(img.size.width * img.scale)x\(img.size.height * img.scale).png"
let url = documents.appendingPathComponent(fName)
if let data = img.pngData() {
do {
try data.write(to: url)
} catch {
s += "Unable to Write Image Data to Disk"
resultLabel.text = s
return
}
} else {
s += "Could not get png data"
resultLabel.text = s
return
}
s += "Logical Size: \(img.size)\n\n"
s += "Scale: \(img.scale)\n\n"
s += "Pixel Size: \(CGSize(width: img.size.width * img.scale, height: img.size.height * img.scale))\n\n"
s += "File \"\(fName)\"\n\nsaved to Documents folder\n"
resultLabel.text = s

// print the path to documents in debug console
// so we can copy/paste into Finder to get to the files
print(documents.path)
}

}


Related Topics



Leave a reply



Submit