I am applying pan gesture on UILabel
. I use one finger scale to increase and decrease the size of the UILabel
.
I tried using scale
to add and subtract value from font size, but I am not getting the exact result.
@objc
func handleRotateGesture(_ recognizer: UIPanGestureRecognizer) {
let touchLocation = recognizer.location(in: self.superview)
let center = self.center
switch recognizer.state {
case .began:
self.deltaAngle = CGFloat(atan2f(Float(touchLocation.y - center.y), Float(touchLocation.x - center.x))) - CGAffineTransformGetAngle(self.transform)
self.initialBounds = self.bounds
self.initialDistance = CGPointGetDistance(point1: center, point2: touchLocation)
case .changed:
let angle = atan2f(Float(touchLocation.y - center.y), Float(touchLocation.x - center.x))
let angleDiff = Float(self.deltaAngle) - angle
self.transform = CGAffineTransform(rotationAngle: CGFloat(-angleDiff))
if let label = self.contentView as? UILabel {
var scale = CGPointGetDistance(point1: center, point2: touchLocation) / self.initialDistance
let minimumScale = CGFloat(self.minimumSize) / min(self.initialBounds.size.width, self.initialBounds.size.height)
scale = max(scale, minimumScale)
let scaledBounds = CGRectScale(self.initialBounds, wScale: scale, hScale: scale)
var pinchScale = scale
pinchScale = round(pinchScale * 1000) / 1000.0
var fontSize = label.font.pointSize
if(scale > minimumScale){
if (self.bounds.height > scaledBounds.height) {
// fontSize = fontSize - pinchScale
label.font = UIFont(name: label.font.fontName, size: fontSize - pinchScale)
}
else{
// fontSize = fontSize + pinchScale
label.font = UIFont(name: label.font.fontName, size: fontSize + pinchScale)
}
} else {
label.font = UIFont( name: label.font.fontName, size: fontSize)
}
print("PinchScale -- \(pinchScale), FontSize = \(fontSize)")
self.bounds = scaledBounds
} else {
var scale = CGPointGetDistance(point1: center, point2: touchLocation) / self.initialDistance
let minimumScale = CGFloat(self.minimumSize) / min(self.initialBounds.size.width, self.initialBounds.size.height)
scale = max(scale, minimumScale)
let scaledBounds = CGRectScale(self.initialBounds, wScale: scale, hScale: scale)
self.bounds = scaledBounds
}
self.setNeedsDisplay()
default:
break
}
}
However, we can achieve this using UIPinchGestureRecognizer
. But how can we do the same effect with UIPanGestureRecognizer
? Any help would be appreciated. Thanks.
Right now you're adding and removing points to the label's current font size. I'd suggest a simpler pattern, more consistent with what you're doing elsewhere, namely just capturing the the initial point size at the start of the gesture and then, as the user's finger moves, apply a scale to that saved value. So, I'd suggest:
Define property to save the initial font size:
var initialPointSize: CGFloat = 0
In the .began
of the gesture, capture the current size
initialPointSize = (contentView as? UILabel)?.font?.pointSize ?? 0
In the .changed
, adjust the font size:
let pinchScale = (scale * 1000).rounded() / 1000 label.font = label.font.withSize(initialPointSize * pinchScale)
As an aside, I'm not sure that it's necessary to round the scale
to three decimal places, but you had that in your original code snippet, so I preserved that.
Personally, I'd follow the same basic pattern with the transform
:
Define a properties to capture the starting angle and the view's current transform
:
var initialAngle: CGFloat = 0 var initialTransform: CGAffineTransform = .identity
In the .began
, capture the current the starting angle and existing transform:
initialAngle = atan2(touchLocation.y - center.y, touchLocation.x - center.x) initialTransform = transform
In the .changed
, update the transform
:
let angle = atan2(touchLocation.y - center.y, touchLocation.x - center.x) transform = initialTransform.rotated(by: angle - initialAngle)
This saves you from reverse engineering the angle associated with the current transform with CGAffineTransformGetAngle
and instead just apply rotated(by:)
to the saved transform.
So this, like the point size and the bounds, represents a consistent pattern: Capture the starting value in .began
and just apply whatever change you need in .changed
.
A few unrelated observations:
All those self.
references are not needed. It just adds noise that makes it harder to read the code.
All of those casts between CGFloat
and Float
are not needed. If you use the atof2
function instead of atof2f
, they all just work with CGFloat
without any casting. Eg, instead of
let angle = atan2f(Float(touchLocation.y - center.y), Float(touchLocation.x - center.x)) let angleDiff = Float(self.deltaAngle) - angle self.transform = CGAffineTransform(rotationAngle: CGFloat(-angleDiff))
You can just do:
let angle = atan2(touchLocation.y - center.y, touchLocation.x - center.x) transform = CGAffineTransform(rotationAngle: angle - deltaAngle)
You actually don't need any of those casts that are currently sprinkled throughout the code snippet.
All of those bounds.size.width
and bounds.size.height
can just be bounds.width
and bounds.height
respectively, again removing noise from the code.
When adjusting the font size, rather than:
label.font = UIFont(name: label.font.fontName, size: fontSize)
You should just use:
label.font = label.font.withSize(fontSize)
That way you preserve all of the essential characteristics of the font (the weight, etc.), and just adjust the size.
In your if let label = contentView as? UILabel
if let label = contentView as? UILabel
test, the same five lines of code in your else
clause appear in the if
clause, too. You should just move those common lines before the if
- else
statement, and then you can lose the else
clause entirely, simplifying your code.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.