When my UIView
is rotated with transform property (CGAffineTransformMakeRotation
), I need to drag one of its corners, say bottom right, to resize it. During this process when user drags the corner, the view's corner must follow user's finger and resize the box by increasing 2 of the sides (right and bottom size for bottom right corner dragging).
It is not so difficult to resize UIView
when you can use frame and touch locations when box is not transformed. For example, I would remember initial frame and touch in UIPanGestureRecognizer
handler
attached to this resizable view on StateBegan, and on StateChanged I would calculate the touch point X, Y difference from initial touch and add those values to initial frame width and height.
However, frame is be reliable for rotated UIView
when transform is applied. Thus I can only rely on bounds
and center
. I created this code but it almost works: I can only enlarge the view proportionally in all 4 directions, not one.
- (void)handleResizeGesture:(UIPanGestureRecognizer *)recognizer {
CGPoint touchLocation = [recognizer locationInView:self.superview];
CGPoint center = self.center;
switch (recognizer.state) {
case UIGestureRecognizerStateBegan: {
deltaAngle = atan2f(touchLocation.y - center.y, touchLocation.x - center.x) - CGAffineTransformGetAngle(self.transform);
initialBounds = self.bounds;
initialDistance = CGPointGetDistance(center, touchLocation);
initialLocation = touchLocation;
if ([self.delegate respondsToSelector:@selector(stickerViewDidBeginRotating:)]) {
[self.delegate stickerViewDidBeginRotating:self];
}
break;
}
case UIGestureRecognizerStateChanged: {
CGFloat scale = CGPointGetDistance(center, touchLocation)/initialDistance;
CGFloat minimumScale = self.minimumSize/MIN(initialBounds.size.width, initialBounds.size.height);
scale = MAX(scale, minimumScale);
CGRect scaledBounds = CGRectScale(initialBounds, scale, scale);
self.bounds = scaledBounds;
[self setNeedsDisplay];
if ([self.delegate respondsToSelector:@selector(stickerViewDidChangeRotating:)]) {
[self.delegate stickerViewDidChangeRotating:self];
}
break;
}
case UIGestureRecognizerStateEnded:
if ([self.delegate respondsToSelector:@selector(stickerViewDidEndRotating:)]) {
[self.delegate stickerViewDidEndRotating:self];
}
break;
default:
break;
}
}
Image below shows the rotated view with known values (A, B, x, y, N, M, N-M distance):
Nice question. I've just created class that uses something similar. In my class you can change the scale of UIViewA and it will change the scale of UIViewB while keeping the same ratio.
Check the small white square on top left:
The class can be found here: https://github.com/sSegev/SSUIViewMiniMe
What you are asking is a bit different. I'm changing the total size of the square while you want to change only the size that is relative to one of the corners based on how far the user dragged it.
Because you can't tap on a button while it's animating (well, you can but the animation is just eye candy and the view is already in it's final state) I used CABasicAnimation which made it easier.
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
//Rotate the UIView
if ([_myRedView.layer animationForKey:@"SpinAnimation"] == nil)
{
CABasicAnimation* animation = [CABasicAnimation animationWithKeyPath:@"transform.rotation.z"];
animation.fromValue = [NSNumber numberWithFloat:0.0f];
animation.toValue = [NSNumber numberWithFloat: 2*M_PI];
animation.duration = 50.0f;
animation.repeatCount = INFINITY;
[self.myRedView.layer addAnimation:animation forKey:@"SpinAnimation"];
}
}
// That's the main chunk of code:
- (void)dragBegan:(UIControl *)c withEvent:ev
{
UITouch *touch = [[ev allTouches] anyObject];
CGPoint touchPoint = [touch locationInView:_myRedView];
NSLog(@"Touch x : %f y : %f", touchPoint.x, touchPoint.y);
if(_myRedView.width/2<touchPoint.x && _myRedView.height/2<touchPoint.y) //Checks for right bottom corner
{
_myRedView.width =touchPoint.x;
_myRedView.height = touchPoint.y;
dragButton.frame = CGRectMake(0, 0, _myRedView.width, _myRedView.height);
}
}
I'm sure that some tweaking is needed but right now it looks like this:
*
Pretty cool for just 6 lines of code ha?
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With