1

I have created small project with UIScrollView, UIView and UITextView (hierarchy is also the same.). UIView display as red color and UITextView display as blue color. Then I have added UIFont to with size 14 to UITextView.

Since i want to enalble zoom in/out feature for this, i have added UIScrollViewDelegate to this controller and override viewForZooming method. Then zoom in/out things are working fine except one thing.

When i Zoom IN the screen, i can see Fonts which are in side the UITextView are blurred. I want to keep the font quality according to zoom scale after zoom in finish . So i override scrollViewDidEndZooming and adjust the textView frame size it is not working. After google search i found some answers , but i tried them but couldn't find the solution and most of them are very old answers.

So I kindly requesting from you guys, please, help me to resolve this problem and i really appreciate your feedback and help . I have attached my source code and screenshot for your reference.

Code:


class ViewController: UIViewController {

    var scrollView: UIScrollView!
    var mainView: UIView!
    var textView: UITextView!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        scrollView = UIScrollView(frame: .zero)
        scrollView.translatesAutoresizingMaskIntoConstraints = false
        self.view.addSubview(scrollView)
        NSLayoutConstraint.activate([
            scrollView.widthAnchor.constraint(equalTo: self.view.widthAnchor),
            scrollView.heightAnchor.constraint(equalTo: self.view.heightAnchor),
        ])
        
        mainView = UIView(frame: .zero)
        mainView.translatesAutoresizingMaskIntoConstraints = false
        mainView.backgroundColor = UIColor.red
        scrollView.addSubview(mainView)
        NSLayoutConstraint.activate([
            mainView.widthAnchor.constraint(equalToConstant: 600),
            mainView.heightAnchor.constraint(equalToConstant: 400),
            mainView.centerXAnchor.constraint(equalTo: scrollView.centerXAnchor),
            mainView.centerYAnchor.constraint(equalTo: scrollView.centerYAnchor)
        ])
        
        textView = UITextView(frame: .zero)
        textView.translatesAutoresizingMaskIntoConstraints = false
        textView.backgroundColor = UIColor.blue
        textView.font = UIFont(name: "Thonburi", size: 14)
        textView.text = "Hello World"
        textView.textAlignment = .center
        mainView.addSubview(textView)
        NSLayoutConstraint.activate([
            textView.widthAnchor.constraint(equalToConstant: 200),
            textView.heightAnchor.constraint(equalToConstant: 40),
            textView.centerXAnchor.constraint(equalTo: mainView.centerXAnchor),
            textView.centerYAnchor.constraint(equalTo: mainView.centerYAnchor),
        ])
        
        scrollView.pinchGestureRecognizer?.isEnabled = true
        scrollView.maximumZoomScale = 12.0
        scrollView.minimumZoomScale = 0.2
        scrollView.delegate = self
    }


}

extension ViewController: UIScrollViewDelegate {
    func viewForZooming(in scrollView: UIScrollView) -> UIView? {
        if let viewForZoom = scrollView.subviews.filter({$0.tag == 1}).first {
            return viewForZoom
        } else {
            return scrollView.subviews.first
        }
    }
    
    func scrollViewDidEndZooming(_ scrollView: UIScrollView, with view: UIView?, atScale scale: CGFloat) {
        self.textView.frame = CGRect(origin: textView.frame.origin, size: CGSize(width: textView.frame.width*scale, height: textView.frame.height*scale))
    }
}

Without zoom, just normal screen size enter image description here

Fonts blurring, after zoom in enter image description here

  • See this answer: https://stackoverflow.com/a/65511223/6257435 for an explanation of what's happening. – DonMag Jan 10 '21 at 16:25
  • Yes, i checked that answer, it set as minimum zoom scale to 0.1 and maximum one is 1.0. initially it has large font size and actual size calculated from 0.1 X font size. when it has minimum zoom scale, font display as high quality and compress mode. – Dileepa Chandrasekara Jan 13 '21 at 03:54
  • Yes, but did that help you understand *why* the font is blurred? Your approach of changing the textView's **frame** will not help. To get a crisp font at different zoom scales, you won't be able to use the scrollView's zoom functionality -- you would probably need to build your own "zooming" feature, using a pinch gesture to calculate the scale, and then re-size and re-position the textView ***and*** change its font size. – DonMag Jan 13 '21 at 13:48
  • @DonMag Thanks lot for feedback, but i need to do it using scroll view only not for the pinch gesture. and i want get crisp font but only after finish the zoom event. it means i need to add this logic inside of scrollViewDidEndZooming method in ScrollViewDelegate. After the redraw the textView, should i set zoom scale to 1.0 as well ? if main view has multiple items like bezeir path shape objects, should i redraw all ? – Dileepa Chandrasekara Jan 14 '21 at 06:53
  • There are various ways to mimic the features of a scroll view, without using a scroll view. But, if you really want to use a scroll view, yes... you'll need to re-draw everything, changing the "scale" of the individual elements (changing font size, changing control points for bezier paths, etc) and reset the scroll view's zoomScale to 1.0 – DonMag Jan 14 '21 at 13:03
  • @DonMag plese refer my answer and i was able to successfuly do it – Dileepa Chandrasekara Jan 15 '21 at 14:31

1 Answers1

1

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.