I'm trying to dynamically create views (UIImageView and UITextView) at runtime by user request and then allow the user to move and resize them. I've got everything working great, except for the resizing. I tried using the pinch gesture recognizer, but find it too clumsy for what I want. Therefore, I would like to use sizing handles. I believe I could put a pan gesture recognizer on each handle, and adjust the view frame as one of them is moved.
The problem is, I'm not quite sure how to create the sizing handles. I would indicate all the things I've tried, but truthfully, I'm not quite sure where to start. I do have a few ideas...
1) Possibly use coregraphics to draw boxes or circles on the corners and sides? Would I create a new layer and draw them on that? Not sure.
2) Stick a little image of a box or circle on each corner?
3) XIB file with the handles already placed on it?
Any suggestions appreciated. I just need to be pointed in the right direction.
Edit: Something like what Apple uses in Pages would be perfect!
First, I suggest create a custom View subclass to UIView, you will handle all of the behavior here. Let's call it ResizableView.
In the custom view, You need to draw layer or view for these dot at corner and add PangestureRecognized to them.Then you can track the location of these dot using recognizer.locationInView()
when user drag them, which you will use to calculate the scale of View.Here is the code you can refer to:
func rotateViewPanGesture(recognizer: UIPanGestureRecognizer) {
touchLocation = recognizer.locationInView(self.superview)
let center = CalculateFunctions.CGRectGetCenter(self.frame)
switch recognizer.state {
case .Began:
initialBounds = self.bounds
initialDistance = CalculateFunctions.CGpointGetDistance(center, point2: touchLocation!)
case .Changed:
//Finding scale between current touchPoint and previous touchPoint
let scale = sqrtf(Float(CalculateFunctions.CGpointGetDistance(center, point2: touchLocation!)) / Float(initialDistance!))
let scaleRect = CalculateFunctions.CGRectScale(initialBounds!, wScale: CGFloat(scale), hScale: CGFloat(scale))
self.bounds = scaleRect
self.refresh()
case:.Ended:
self.refresh()
default:break
Step by step
touchLocation
location of the Pangesture
center
is the center of ResizableView
initialBounds
is the initial bounds of the ResizableView when PanGesture begin.
initailDistance
is the distance between the center of the ResizableView of touchPoint of the dot the user is dragging.
Then you can calculate the scale
given initialDistance
, center
, touch location
Now you have scaled the view as You want. You also need to refresh the position of these dot at corner accordingly, that's what refresh()
for, you need to implement it yourself.
CalculateFunctions
I tend to define some helpFunctions to help me calculate.
CalculateFunctions.CGPointGetDistance
is used to calculate the distance between center of the view and touch location.
CalculateFunctions.CGRectScale
return the scaled CGRect given the the scale you just calculated.
CalculateFunctions.CGRectGetCenter
return the center point of a CGRect
That's just a rough idea. Actually there are many Libraries you can refer to.
Some suggestions:
- SPUserResizableView
This is a ResizableView exactly what you want, but it was written in ObjC and hasn't been updated for a long time. But you can refer to it.
- JLStickerTextView This may not fit your requirement very well as it is for text(edit, resize, rotate with one finger) However, this one is written in Swift, a good example for you.
If you have any questions, feel free to post it.Good Luck:-)