Scale an UIView except one of its subview - ios

I'm scaling an UIView this way:
myView.transform = CGAffineTransformScale(CGAffineTransformIdentity, 0.9, 0.9);
and the view is scaled well, but I want one of its subview to remain unscaled, i.e fullscreen. How to achieve this?

I was able to get Avt's answer to work by using CGAffineTransformInvert:
myView.transform = CGAffineTransformScale(CGAffineTransformIdentity, 0.9, 0.9)
subView.transform = CGAffineTransformInvert(myView.transform)

The only way is to add additional scaling for specific subview
myView.transform = CGAffineTransformScale(CGAffineTransformIdentity, 0.9, 0.9);
specific.transform = CGAffineTransformScale(CGAffineTransformIdentity, 1./0.9, 1./0.9);
probably you will also need to add
myView.clipsToBounds = NO;

Related

Transform UIView from center

I have a UIView in my app that I'd like to give a small scale animation. The animation should be bouncy, as in that it should scale a bit smaller and then back to it's original size.
I found the following Objective-C code:
headerView.transform = CGAffineTransformScale(CGAffineTransformIdentity, 0.9, 0.9);
Now, I added this to my Swift code:
profileView.transform = CGAffineTransform.identity.scaledBy(x: 0.9, y: 0.9)
However, what happens now is that the view transforms with the left, top corner seemingly as the anchor. I'd like the center to be anchor, though. Any ideas as to what I'm doing wrong?
Do not use identity matrix,
try just like this
view.transform = CGAffineTransform(scaleX: 0.9, y: 0.9)

Set a UIView scale transform without effecting other transforms

I have a UIView that I scale down when it is touched and scale back up when the touch is ended or cancelled.
I had been scaling the view like this
Scale down:
CGAffineTransform transform = CGAffineTransformMakeScale(0.95, 0.95);
self.transform = transform;
Scale up:
CGAffineTransform transform = CGAffineTransformMakeScale(1.0, 1.0);
self.transform = transform;
This doesn't preserve any other transform. I know I can use this to preserve the old transforms:
Scale down:
CGAffineTransform transform = CGAffineTransformScale(self.transform, 0.95, 0.95);
self.transform = transform;
Scale up:
CGAffineTransform transform = CGAffineTransformScale(self.transform, 1.0, 1.0);
self.transform = transform;
But of course here the scale up has no effect- plus there is potential to have cumulative scale down animations applied. Basically I want a way to apply the scale transform absolutely without affecting any other transform. Is there a way to do this? I don't think using 1.0/0.95 for the scale up factor, because it is possible the view could receive two touches before one is cancelled or ended.
I think I am asking the same thing as this question: Applying just the scale component of a CGAffineTransform to a UIView but I don't think the answers here will work for me.
I am targeting iOS 7 and above.
I am not sure if this is exactly what you are looking for but for me I need the scale to be absolutely consistent all the time so I modify the matrix directly.
CATransform3D transform = layer.transform;
if (makeSmaller)
{
// Scale to 0.9
transform.m11 = 0.9f;
transform.m22 = 0.9f;
}
// Cell needs to grow to normal size
else if (restoreToOriginal)
{
// Scale to 1.0 again
transform.m11 = 1.0f;
transform.m22 = 1.0f;
}
// Set the desired Y translation
transform.m42 = desiredffset;
layer.transform = transform;

UIView Perspective feature

I've got a view and I would like to scale this view as like below image. How do we achieve this?
Thanks,
Mahesh
You need to rotate your view's layer. Something like this,
CALayer *layer = yourView.layer;
CATransform3D rotationTransform = CATransform3DIdentity;
rotationTransform.m24 = 1.0 / -350;
rotationTransform = CATransform3DRotate(rotationTransform, 60*M_PI/180, 1.0, 0.0, -0.1);
[layer setTransform: rotationTransform];
Check out this guide to understand CALayer's geometry and how it works.

Custom UIView scaling using CGAffineTransformScale

I'm learning to develop for iOS, and as part of education process I have created custom UIView which uses drawRect to draw it's contents (Core Graphics + UIBezierPath based). Everthing works as expected, view is dynamic and renders it's contents depending on it's width/height. Now I want to add dissolve animation which should look like scaling from 100% to 0%. I have written this code to do it:
[UIView animateWithDuration:1 delay:0
options: UIViewAnimationOptionBeginFromCurrentState
animations: ^{
for (CardView *cardView in self.cardsViews) {
cardView.transform = CGAffineTransformScale(CGAffineTransformIdentity, 0.01, 0.01);
}} completion:nil];
However, this code DOES NOT scales my view from 100% to 0%. It just makes cards to dissapear (at most). I have tried many ways of doing scaling, but only effect I have reached so far is zooming from 0% to 100%. This my view does perfectly, but not reverse scaling... Also, it DOES NOT scales up/down even if I try to apply non-animated transformation such as:
cardView.transform = CGAffineTransformScale(CGAffineTransformIdentity, 0.5, 0.5);
I see that my view look changes A BIT, but not scales to 50%, that's for sure. When I try to apply exactly same animation logic to UILabel, it works perfectly! What have I missed developing custom UIView? Why scaling view may malfunction?
Thanks a lot in advance!
UPDATE #1 This code makes my view exactly twice as big and than scales it back to original size:
[UIView animateWithDuration:5 delay:0
options: UIViewAnimationOptionBeginFromCurrentState
animations: ^{
for (CardView *cardView in self.cardsViews) {
cardView.transform = CGAffineTransformMakeScale(0.5, 0.5);
}
} completion:nil];
It is simple 100% to 0% using CGAffineTransformScale:
cardView.view.transform =CGAffineTransformScale(CGAffineTransformIdentity, 1.1, 1.1);
[UIView animateWithDuration:0.3/1.5 animations:^{
cardView.view.transform = CGAffineTransformScale(CGAffineTransformIdentity, 0.1, 0.1);
} completion:^(BOOL finished)
{
NSLog(#" Animation complet Block");
}];
What you can try is setting the contentMode of the view to UIViewContentModeRedraw and adding another animation option - UIViewAnimationOptionAllowAnimatedContent - in animateWithDuration method.
Swift scaling from 120% to 100%:
logoView.transform = CGAffineTransform(scaleX: 1.2, y: 1.2)
UIView.animate(withDuration: 0.55, delay: 0.1, options: [.curveEaseOut], animations: {
self.logoView.transform = .identity
self.view.layoutIfNeeded()
}, completion: { _ in
})

Smooth horizontal flip using CATransform3DMakeRotation

I have set up the following animation to rotate between views of different sizes. The midpoint of the animation seems to have a flicker as the new, taller view comes into view. Is there anything I can do to smoothen the transition.
newView.layer.transform = CATransform3DMakeRotation(M_PI_2, 0.0, 1.0, 0.0);
[UIView animateWithDuration:0.5
delay:0
options:UIViewAnimationOptionCurveLinear
animations:^{oldView.layer.transform = CATransform3DMakeRotation(M_PI_2, 0.0, -1.0, 0.0);}
completion:^(BOOL finished) {
[oldView removeFromSuperview];
[UIView animateWithDuration:0.5
delay:0
options:UIViewAnimationOptionCurveLinear
animations:^{newView.layer.transform = CATransform3DMakeRotation(M_PI_2, 0.0, 0.0, 0.0);}
completion:nil];
}];
Got this working thanks to this thread, so I thought I'd share my to-from 3D transform using the m34 matrix.
UIView *toView = // show this
UIView *fromView = // hide this one
// set up from
CATransform3D fromViewRotationPerspectiveTrans = CATransform3DIdentity;
fromViewRotationPerspectiveTrans.m34 = -0.003; // 3D ish effect
fromViewRotationPerspectiveTrans = CATransform3DRotate(fromViewRotationPerspectiveTrans, M_PI_2, 0.0f, -1.0f, 0.0f);
// set up to
CATransform3D toViewRotationPerspectiveTrans = CATransform3DIdentity;
toViewRotationPerspectiveTrans.m34 = -0.003;
toViewRotationPerspectiveTrans = CATransform3DRotate(toViewRotationPerspectiveTrans, M_PI_2, 0.0f, 1.0f, 0.0f);
toView.layer.transform = toViewRotationPerspectiveTrans;
[UIView animateWithDuration:1.0
delay:0
options:UIViewAnimationOptionCurveLinear
animations:^{fromView.layer.transform = fromViewRotationPerspectiveTrans; }
completion:^(BOOL finished) {
[fromView removeFromSuperview];
[UIView animateWithDuration:1.0
delay:0
options:UIViewAnimationOptionCurveLinear
animations:^{toView.layer.transform = CATransform3DMakeRotation(M_PI_2, 0.0, 0.0, 0.0);}
completion:nil];
}];
I was halfway there, but the missing piece, setting the m34 cell value of the transformation matrix, did the trick.
As David pointed out, your code doesn't make sense as written. You're setting the final rotation of your newView to a rotation around nothing, which will PROBABLY be equivalent to the identity matrix, but I'm not sure.
Here's what I would try (I'm tired, so let's see if I can explain this coherently...)
Animate the oldView from 0 to pi/2 as animation step 1. Set the newView to -pi/2 before beginning the second animation (rotated 90 degrees the other way.)
In the completion method, remove the old view and start an animation to set the new view's rotation back to zero. That will cause the new view to look like it's continuing to flip around in a 180 degree flip.
Here's the tricky part. Calculate the difference in size (horizontal and vertical) between the old and new views. Add (concatenate) a scale transform along with the rotation, so that when the first part of the rotation is finished, it is scaled to the average of the old and new size. Pseudocode might look like this:
//Scale to apply to oldView for the first part of the animation:
scale height = ((oldView.size.height+newView.size.height)/2) / oldView.size.height
scale width = ((oldView.size.width+newView.size.width)/2) / oldView.size.width
/*
Before beginning the second part of the animation, rotate newView to -pi/2,
and scale it by an amount that makes it the same size that oldView will be
at the end of the first animation (the average of the sizes of both views)
*/
newView scale height = ((oldView.size.height+newView.size.height)/2) /
newView.size.height
newView scale width = ((oldView.size.width+newView.size.width)/2) /
newView.size.width
in the completion block, remove oldView from it's superview,
and animate newView back to the identity transform.
If my approach is right, at the end of the first animation, oldView should be scaled to a size halfway between the sizes of oldView and newView.
The second animation, triggered in the completion block of the first, will start out with newView being the same size that oldView was scaled to at the end of the first animation. The second animation will end with the new view rotating into place and scaling back to it's original size.

Resources