I have 1 view with 2 subviews. One of them being 10 times bigger than the other one. I have a gesture recognizer for the big one (which is on top).
I want to be able to scale the big one with the pinch gesture from an anchor point between the fingers. And I want the little one to make that same transform from the same global position anchor point but without changing its own anchor point.
Hope I explain myself. Here is the code:
- (void)twoFingerPinch:(UIPinchGestureRecognizer *)gestureRecognizer
{
//this changes the anchor point of "big" without moving it
[self adjustAnchorPointForGestureRecognizer:gestureRecognizer];
if ([gestureRecognizer state] == UIGestureRecognizerStateBegan || [gestureRecognizer state] == UIGestureRecognizerStateChanged) {
CGAffineTransform transform = CGAffineTransformScale([[gestureRecognizer view] transform], [gestureRecognizer scale], [gestureRecognizer scale]);
float scale = sqrt(transform.a*transform.a+transform.c*transform.c);
//this transforms "big"
[gestureRecognizer view].transform = transform;
//anchor point location in little view
CGPoint pivote = [gestureRecognizer locationInView:little];
CGAffineTransform transform_t = CGAffineTransformConcat(CGAffineTransformMakeTranslation(-pivote.x, -pivote.y), transform);
transform_t = CGAffineTransformConcat(transform_t, CGAffineTransformMakeTranslation(pivote.x, pivote.y));
little.transform = transform_t;
}
[gestureRecognizer setScale:1];
}
But this is not working, the little view keeps jumping around and goes crazy.
EDIT: More info.
Ok, this is the diagram:
The red square is the big view, the dark one is the little one. The dotted square is the main view.
The line: [self adjustAnchorPointForGestureRecognizer:gestureRecognizer]; changes the big views anchor point to the center of the pinch gesture. That works.
As I scale the big view, the small view should scale the same amount and move so it's centered in the big view as it is now. That is, it should scale with the same anchor point as the big view.
I would like to keep those transforms to the little view in a CGAffineTransform, if possible.
Ok, I finally found it. I don't know if it's the better solution, but it works.
- (void)twoFingerPinch:(UIPinchGestureRecognizer *)gestureRecognizer
{
[self adjustAnchorPointForGestureRecognizer:gestureRecognizer];
if ([gestureRecognizer state] == UIGestureRecognizerStateBegan || [gestureRecognizer state] == UIGestureRecognizerStateChanged) {
CGAffineTransform transform = CGAffineTransformScale([[gestureRecognizer view] transform], [gestureRecognizer scale], [gestureRecognizer scale]);
float scale = sqrt(transform.a*transform.a+transform.c*transform.c);
if((scale>0.1)&&(scale<20)) {
[gestureRecognizer view].transform = transform;
CGPoint anchor = [gestureRecognizer locationInView:little];
anchor = CGPointMake(anchor.x - little.bounds.size.width/2, anchor.y-little.bounds.size.height/2);
CGAffineTransform affineMatrix = little.transform;
affineMatrix = CGAffineTransformTranslate(affineMatrix, anchor.x, anchor.y);
affineMatrix = CGAffineTransformScale(affineMatrix, [gestureRecognizer scale], [gestureRecognizer scale]);
affineMatrix = CGAffineTransformTranslate(affineMatrix, -anchor.x, -anchor.y);
little.transform = affineMatrix;
[eagleView setTransform:little.transform];
[gestureRecognizer setScale:1];
}
}
}
That eaglView line, is the real reason why I needed a CGAffineTransform and I couldn't change the anchor. I'm sending it to OpenGL to change the model view transform matrix.
Now it works perfectly with 3 transforms (rotate, scale, translate) at the same time through user feedback.
EDIT
Just a little note: It seems that when I move the view too fast, the eaglView and the UIView get out of sync. So I don't apply the transforms to the UIViews directly, I apply them with the info out of the eaglView. Like this:
- (void)twoFingerPinch:(UIPinchGestureRecognizer *)gestureRecognizer
{
[self adjustAnchorPointForGestureRecognizer:gestureRecognizer];
if ([gestureRecognizer state] == UIGestureRecognizerStateBegan || [gestureRecognizer state] == UIGestureRecognizerStateChanged) {
CGAffineTransform transform = CGAffineTransformScale([[gestureRecognizer view] transform], [gestureRecognizer scale], [gestureRecognizer scale]);
float scale = sqrt(transform.a*transform.a+transform.c*transform.c);
if((scale>0.1)&&(scale<20)) {
//[gestureRecognizer view].transform = transform;
CGPoint anchor = [gestureRecognizer locationInView:little];
anchor = CGPointMake(anchor.x - little.bounds.size.width/2, anchor.y-little.bounds.size.height/2);
CGAffineTransform affineMatrix = little.transform;
affineMatrix = CGAffineTransformTranslate(affineMatrix, anchor.x, anchor.y);
affineMatrix = CGAffineTransformScale(affineMatrix, [gestureRecognizer scale], [gestureRecognizer scale]);
affineMatrix = CGAffineTransformTranslate(affineMatrix, -anchor.x, -anchor.y);
//little.transform = affineMatrix;
[eagleView setTransform:affineMatrix];
[gestureRecognizer setScale:1];
CGAffineTransform transform = CGAffineTransformMakeRotation(eaglView.myRotation*M_PI/180);
transform = CGAffineTransformConcat(CGAffineTransformMakeScale(eaglView.myScale, eaglView.myScale), transform);
transform = CGAffineTransformConcat(transform, CGAffineTransformMakeTranslation(eaglView.myTranslate.x, -eaglView.myTranslate.y));
little.transform = transform;
big.transform = transform;
}
}
}