iosswiftuilabelpinchzoomuipinchgesturerecognizer

Resize font along with frame of label using pinch gesture on UILabel?


Increase or decrease font size smoothly whenever user resize label using pinch gesture on it.

Note


extension String {
    func height(withConstrainedWidth width: CGFloat, font: UIFont) -> CGFloat {
        let constraintRect = CGSize(width: width, height: .greatestFiniteMagnitude)
        let boundingBox = self.boundingRect(with: constraintRect, options: .usesLineFragmentOrigin, attributes: [NSAttributedStringKey.font: UIFont(name: font.fontName, size: font.pointSize)!], context: nil)
        return ceil(boundingBox.height)
    }

    func width(withConstrainedHeight height: CGFloat, font: UIFont) -> CGFloat {
        let constraintRect = CGSize(width: .greatestFiniteMagnitude, height: height)
        let boundingBox = self.boundingRect(with: constraintRect, options: .usesLineFragmentOrigin, attributes: [NSAttributedStringKey.font: UIFont(name: font.fontName, size: font.pointSize)!], context: nil)
        return ceil(boundingBox.width)
    }
}

func resizeLabelToText(textLabel : UILabel)
{
    let labelFont = textLabel.font
    let labelString = textLabel.text
    let labelWidth : CGFloat = labelString!.width(withConstrainedHeight: textLabel.frame.size.height, font: labelFont!)
    let labelHeight : CGFloat = labelString!.height(withConstrainedWidth: labelWidth, font: labelFont!)

    textLabel.frame = CGRect(x: textLabel.frame.origin.x, y: textLabel.frame.origin.y, width: labelWidth, height: labelHeight)
    textLabel.font = labelFont
}

func pinchedRecognize(_ pinchGesture: UIPinchGestureRecognizer) {
    guard pinchGesture.view != nil else {return}

    if (pinchGesture.view is UILabel) {
        let selectedTextLabel = pinchGesture.view as! UILabel

        if pinchGesture.state == .began || pinchGesture.state == .changed {
            let pinchScale = round(pinchGesture.scale * 1000) / 1000.0
            if (pinchScale < 1) {
                selectedTextLabel.font = selectedTextLabel.font.withSize(selectedTextLabel.font.pointSize - pinchScale)
            }
            else {
                selectedTextLabel.font = selectedTextLabel.font.withSize(selectedTextLabel.font.pointSize + pinchScale)
            }
            resizeLabelToText(textLabel: selectedTextLabel)
        }
    }
}

Solution

  • I solved the problem with following code which is working fine with every aspect which are mentioned in question, similar to Snapchat and Instagram:

    var pointSize: CGFloat = 0
    @objc func pinchRecoginze(_ pinchGesture: UIPinchGestureRecognizer) {
        guard pinchGesture.view != nil else {return}
    
        let view = pinchGesture.view!
        if (pinchGesture.view is UILabel) {
            let textLabel = view as! UILabel
    
            if pinchGesture.state == .began {
                let font = textLabel.font
                pointSize = font!.pointSize
    
                pinchGesture.scale = textLabel.font!.pointSize * 0.1
            }
            if 1 <= pinchGesture.scale && pinchGesture.scale <= 10  {
                textLabel.font = UIFont(name: textLabel.font!.fontName, size: pinchGesture.scale * 10)
    
                resizeLabelToText(textLabel: textLabel)
            }
        }
    }
    
    func resizeLabelToText(textLabel : UILabel) {
        let labelSize = textLabel.intrinsicContentSize
        textLabel.bounds.size = labelSize
    }