5
votes

I have been trying to implement a Snapchat-like edit text on an image. What I did so far is implement a UILabel in the center of the UIImageView and I added 3 gestures to this UILabel: UIPanGestureRecognizer, UIPinchGestureRecognizer & UIRotationGestureRecognizer.

I have managed to implement the Pan method, but I am having hard time to make the Pinch + Rotation as smooth as they do, I get horrible results T_T

How do you guys think this was made? which components are involved in this & if you have any reading / watching material I could use to accomplish this.

Thanks :)

EDIT:

These are the methods I implemented to handle Pinch & Rotation:

func handlePinch(recognizer: UIPinchGestureRecognizer) {
    if let view = recognizer.view as? UILabel {
        view.transform = CGAffineTransformScale(view.transform, recognizer.scale, recognizer.scale)
    }
}

func handleRotate(recognizer: UIRotationGestureRecognizer) {
    if let view = recognizer.view as? UILabel {
        view.transform = CGAffineTransformRotate(view.transform, recognizer.rotation)
    }
}

Preview video of how the pinch I implemented works: https://drive.google.com/file/d/0B-AVM51jxsvUY2RUUHdWbGo5QlU/view?usp=sharing

enter image description here

4
Show the code of how you do the rotationTeja Nandamuri
@Mr.T Hi, I edited my post and added those. Thanks! :)Erez Hod
What is the issue u r facing ?Teja Nandamuri
@Mr.T First, it doesn't work as smooth as Snapchat's. Also, when I'm pinching to scale, it scales up / down way too much in a very aggressive way. Second, I was wondering which components Snapchat have used to implement this feature.Erez Hod

4 Answers

4
votes

Found a solution, apparently all I needed to do in the Rotation & Pinch is to always reset the view's rotation / scale. For instance, setting my recognizer.scale to 1.0 and recognizer.rotation to 0.0.

Here is an example of my code:

func handlePan(recognizer: UIPanGestureRecognizer) {
    let translation = recognizer.translationInView(view)
    if let view = recognizer.view {
        view.center = CGPoint(x:view.center.x + translation.x,
            y:view.center.y + translation.y)
    }
    recognizer.setTranslation(CGPointZero, inView: view)
}

func handlePinch(recognizer: UIPinchGestureRecognizer) {
    if let view = recognizer.view as? UILabel {
        let pinchScale: CGFloat = recognizer.scale
        view.transform = CGAffineTransformScale(view.transform, pinchScale, pinchScale)
        recognizer.scale = 1.0
    }
}

func handleRotate(recognizer: UIRotationGestureRecognizer) {
    if let view = recognizer.view as? UILabel {
        let rotation: CGFloat = recognizer.rotation
        view.transform = CGAffineTransformRotate(view.transform, rotation)
        recognizer.rotation = 0.0
    }
}
1
votes

For "it scales up / down way too much in a very aggressive way":

You need to handle the pinch gesture scale value according to your need.

From your recogniser method, you get the scale value as:

    var pinchScale: CGFloat = recogniser.scale

You need to modify this value either like decrease it by /10 or /100 as per your need, and use this value in the label transformation instead of using the pangesture scale.

1
votes

The issue you have is that your code takes the current transform and adds another transform based on the current "movement", so you accumulate changes (compound them, really) as you move during a single gesture.

Keep instance variables for rotation, scale, and movement, update the relevant one in each of your gesture recognizer's actions (you'll also need to store the state of each at the beginning of each gesture, so you can apply the delta to the initial state), and create the transform from scratch using those three variables. The transform creating should of course be factorized in a separate function, since you're going to use it several times.

0
votes

I'm not sure if this is exactly what you're looking for (I've never used snapchat), but this could give you some ideas

https://github.com/danielinoa/DIImageView

I'm not sure this one has a pinch gesture, but I'm not entirely sure how you mean it to be used anyway.

Here is a demo of that project: https://www.cocoacontrols.com/controls/diimageview

In general, I recommend checking cocoacontrols every time you venture to implement something like this. There are usually solid examples to get you started, and sometimes, you'll find exactly what you need.