1
votes

I'm having a problem with scale transformation I have to apply to UIViews on Swift (but it's the same in objective-c too)

I'm applying a CGAffineTransformMakeScale() to multiples views during a gestureRecognizer.

It's like a loop for a cards deck. I remove the one on top and the X others behind scale up and a new one is added in the back.

The first iteration works as expected. But when I try to swipe the new front one, all the cards reset to their initial frame size because i'm trying to apply a new transform, which seems to cancel the previous one and reset the view to its initial state.

How can I apply definitely/commit the first transform change to be able to apply a new one after that based on the UIView resulting new size ?

I tried a UIView.commitAnimations() but no change.

EDIT :

Here's a simple example to understand what I try to do :

Imagine I have an initial UIView of 100x100

I have a shrink factor of 0.95, which means next views behind will be 95x95, then 90.25, then 85.73, etc

If I remove the top one (100x100), I want to scale up the others, so the 95x95 will become 100x100, etc
This is done by applying the inverse of the shrink factor, here 1.052631...

First time I apply the inverse factor, all views are correctly resized.
My problem is, when I trigger again by a swipe on the new front UIView a new resize of all views (So, for example, the 90.25x90.25 which became 95x95 should now scale to 100x100).
At this moment, the same CGAffineTransformMakeScale() is apply to all views, which all instantly reset to their original frame size (so the now 95x95 reset to 90.25x90.25, and then begin to apply the transformation on this old size).

As suggested here or elsewhere, using UIView.commitAnimations() in the end of each transformation don't change anything, and using a CGAffineTransformConcat() is like powering over and over the scaling by himself and of course views become insanely big...

I hope I made myself more clear, that's not easy to explain, don't hesitate to ask if something is wrong here.

1
One way I can think of is to adjust the frames of the card instead of using CGAffineTransforms. Or possibly, you might need to apply a CGTransformConcat(view.transform, newScaleTransform) ?Zhang
I've thought about using CGTransformConcat, but the problem is that makes a huge transform (like a power^2 of my scale factor). And I'd like to avoid to recalculate a new factor each time to be able to add it to the previous one. A "commit" of the previous then applying the same factor would be much easier to do.Sylver
You may be misunderstanding what CGTransformConcat does. It sounds like you're expecting it to take more storage, when what it really does is mathematically concatenate the two transforms (via a matrix multiply), so the data size remains the same.David Berry
I've edited and added a concrete example of what I'm trying to do, hope this will help.Sylver

1 Answers

0
votes

After a lot of reading and consulting colleagues who know better than me about iOS programmation, here's my conclusion :

  • Applying a CGAffineTransformMakeScale() only modify visually a view but not its properties, and since it's difficult (and costly) to modify afterward the bounds and/or frame of a view, I should avoid to try to make a transform, update bounds, make another transform, etc.

  • Applying the same CGAffineTransformMakeScale() only reset the effect and not apply to the previous one.

  • Applying a CGAffineTransformScale() with the same values on top of the previous CGAffineTransformMakeScale() (or with a CGAffineTransformConcat()) has some unpredictable effect and will be very difficult to calculate precisely the new values to apply each time to get the effect I want.

The best way I can go with this is only applying one CGAffineTransformMakeScale() that I will keep updating scales values all along the view's life. It implies now for me to rework all my implementation logic in reverse, but that's the easiest way to do this right.

Thanks all for your tips.