Подтвердить что ты не робот

Шкала UIView с верхним центром в точке крепления?

Я масштабирую UIView с CGAffineTransformMakeScale, но я хочу, чтобы он привязывал к нему текущую верхнюю центральную точку по мере ее масштабирования.

Я посмотрел в настройке view.layer.anchorPoint, но я считаю, что нужно использовать это в сочетании с установкой view.layer.position для учета изменений в точке привязки.

Если бы кто-нибудь мог указать мне в правильном направлении, я был бы очень благодарен!

4b9b3361

Ответ 1

Взгляните на мой ответ здесь, чтобы понять, почему ваш взгляд движется, когда вы меняете опорную точку: fooobar.com/questions/442189/...

Итак, начните с вашего преобразования преобразования, установленного в идентификатор. Когда представление нетрансформировано, найдите центр его верхнего края:

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

Затем точка привязки к середине верхнего края:

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

Теперь слой position (или вид center) - это положение центра верхнего края слоя. Если вы остановитесь здесь, слой будет перемещаться так, чтобы центр его верхнего края находился там, где находился его истинный центр, прежде чем менять опорную точку. Так измените слой position на центр его верхнего края с момента создания:

view.layer.position = topCenter;

Теперь слой остается в одном месте на экране, но его опорная точка является центром его верхнего края, поэтому масштабирование и вращение оставят эту точку неподвижной.

Ответ 2

Swift 5.1

Масштабирование UIView с определенной опорной точкой, избегая неправильный монтаж:

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)
    }
}

Таким образом, чтобы уменьшить вид до половины его размера с верхним центром в качестве точки привязки:

view.applyTransform(withScale: 0.5, anchorPoint: CGPoint(x: 0.5, y: 0))

Ответ 3

Это старый вопрос, но я столкнулся с той же проблемой и взял у меня много времени, чтобы достичь желаемого поведения, немного расширив ответ от @Rob Mayoff (я нашел решение благодаря его объяснению). Я должен был показать масштабирование с плавающим видом из точки, затронутой пользователем. В зависимости от экранных коордов, он может уменьшаться вниз, вправо, влево, вверх или от центра.

Первое, что нужно сделать, - это установить центр нашего плавающего представления в точке касания (он должен быть центром, потому что объяснение Роба):

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

Следующий вопрос является установка точка привязки слоя, в зависимости от того, что мы хотим сделать (я измерил точку относительно рамки экрана, и определить, где масштабировать его):

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

}

Теперь все просто. В зависимости от эффекта, который вы хотите отдать анимации (идея была отскоком масштабирования от 0 до 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
                                           }];
                     }];
                 }];

Что это. Как вы можете видеть, главное - правильно настроить позицию представления и точку привязки. Затем все это кусок пирога! С уважением, и пусть код будет с вами!

Ответ 4

Swift 4.2

Это работает для меня:

public extension UIView {

    func applyTransform(withScale scale: CGFloat, anchorPoint: CGPoint) {
        let xPadding = (scale - 1) * (anchorPoint.x - 0.5) * bounds.width
        let yPadding = (scale - 1) * (anchorPoint.y - 0.5) * bounds.height
        transform = CGAffineTransform(scaleX: scale, y: scale).translatedBy(x: xPadding, y: yPadding)
    }
}