Scale UIView with the top center as the anchor point?

前端 未结 3 1043
情话喂你
情话喂你 2020-12-23 22:43

I\'m scaling a UIView with CGAffineTransformMakeScale but I want to keep it anchored to it\'s current top center point as it\'s scaled.

I\'ve looked into setting

相关标签:
3条回答
  • 2020-12-23 22:49

    It's an old question, but I faced the same problem and took me a lot of time to get to the desired behavior, expanding a little bit the answer from @Rob Mayoff (I found the solution thanks to his explanation). I had to show a floating-view scaling from a point touched by the user. Depending on screen coords, It could scale down, right, left, up or from the center.

    The first thing to do is to set the center of our floating view in the touch point (It has to be the center, 'cause as Rob explanation):

    -(void)onTouchInView:(CGPoint)theTouchPosition
    {
    self.floatingView.center = theTouchPosition;
    ....
    }
    

    The next issue is to setup the anchor point of the layer, depending on what we want to do (I measured the point relative to the screen frame, and determined where to scale it):

    switch (desiredScallingDirection) {
        case kScaleFromCenter:
        {
            //SCALE FROM THE CENTER, SO
            //SET ANCHOR POINT IN THE VIEW'S CENTER
            self.floatingView.layer.anchorPoint=CGPointMake(.5, .5);
        }
            break;
        case kScaleFromLeft:
            //SCALE FROM THE LEFT, SO
            //SET ANCHOR POINT IN THE VIEW'S LEFT-CENTER
            self.floatingView.layer.anchorPoint=CGPointMake(0, .5);
            break;
        case kScaleFromBottom:
            //SCALE FROM BOTTOM, SO
            //SET ANCHOR POINT IN THE VIEW'S CENTER-BOTTOM
            self.floatingView.layer.anchorPoint=CGPointMake(.5, 1);
            break;
        case kScaleFromRight:
            //SCALE FROM THE RIGHT, SO
            //SET ANCHOR POINT IN THE VIEW'S RIGHT-CENTER
            self.floatingView.layer.anchorPoint=CGPointMake(1, .5);
            break;
        case kScallingFromTop:
            //SCALE FROM TOP, SO
            //SET ANCHOR POINT IN THE VIEW'S CENTER-TOP
            self.floatingView.layer.anchorPoint=CGPointMake(.5, 0);
            break;
        default:
            break;
    
    }
    

    Now, all it's easy. Depending on the effect you want to give to the animation (The idea was a bouncing scaling from 0 to 100%):

    //SETUP INITIAL SCALING TO (ALMOST) 0%
    CGAffineTransform t=CGAffineTransformIdentity;
    t=CGAffineTransformScale(t, .001, .001);
    self.floatingView.transform=t;
    [UIView animateWithDuration:.2
                          delay:0
                        options:UIViewAnimationOptionCurveEaseInOut
                     animations:^{
                         //BOUNCE A LITLE UP!
                         CGAffineTransform t = CGAffineTransformMakeScale(1.1,1.1);
                         self.floatingView.transform=t;
                     } completion:^(BOOL finished) {
                         [UIView animateWithDuration:.1
                                          animations:^{
                                              //JUST A LITTLE DOWN
                                              CGAffineTransform t = CGAffineTransformMakeScale(.9,.9);
                                              self.floatingView.transform = t;
                                          } completion:^(BOOL finished) {
                                              [UIView animateWithDuration:.05
                                                               animations:^{
                                                                   //AND ALL SET
                                                                   self.floatingView.transform  = CGAffineTransformIdentity;
                                                               }
                                               completion:^(BOOL finished) {
                                                   //ALL SET
                                               }];
                         }];
                     }];
    

    That's it. As you can see, the main thing is to setup correctly the view's position and anchor point. Then, it's all piece of cake! Regards, and let the code be with you!

    0 讨论(0)
  • 2020-12-23 23:01

    Take a look at my answer here to understand why your view is moving when you change the anchor point: https://stackoverflow.com/a/12208587/77567

    So, start with your view's transform set to identity. When the view is untransformed, find the center of its top edge:

    CGRect frame = view.frame;
    CGPoint topCenter = CGPointMake(CGRectGetMidX(frame), CGRectGetMinY(frame));
    

    Then the anchor point to the middle of the top edge:

    view.layer.anchorPoint = CGPointMake(0.5, 0);
    

    Now the layer's position (or the view's center) is the position of the center of the layer's top edge. If you stop here, the layer will move so that the center of its top edge is where its true center was before changing the anchor point. So change the layer's position to the center of its top edge from a moment ago:

    view.layer.position = topCenter;
    

    Now the layer stays in the same place on screen, but its anchor point is the center of its top edge, so scales and rotations will leave that point fixed.

    0 讨论(0)
  • 2020-12-23 23:07

    By using an extension

    Scaling an UIView with a specific anchor point while avoiding misplacement:

    extension UIView {
        func applyTransform(withScale scale: CGFloat, anchorPoint: CGPoint) {
            layer.anchorPoint = anchorPoint
            let scale = scale != 0 ? scale : CGFloat.leastNonzeroMagnitude
            let xPadding = 1/scale * (anchorPoint.x - 0.5)*bounds.width
            let yPadding = 1/scale * (anchorPoint.y - 0.5)*bounds.height
            transform = CGAffineTransform(scaleX: scale, y: scale).translatedBy(x: xPadding, y: yPadding)
        }
    }
    

    So to shrink a view to half of its size with its top center as anchor point:

    view.applyTransform(withScale: 0.5, anchorPoint: CGPoint(x: 0.5, y: 0))
    
    0 讨论(0)
提交回复
热议问题