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

Изменение размера UIView, когда оно вращается с преобразованием

Когда мой UIView поворачивается с помощью свойства transform (CGAffineTransformMakeRotation), мне нужно перетащить один из его углов, скажем, вправо, чтобы изменить его размер. Во время этого процесса, когда пользователь перетаскивает угол, угол обзора должен следовать за пальцем пользователя и изменять размер окна, увеличивая 2 стороны (правый и нижний размер для перетаскивания нижнего правого угла).

Не так сложно изменить размер UIView, когда вы можете использовать фреймы и контакты, когда поле не преобразуется. Например, я бы вспомнил начальный кадр и коснулся в UIPanGestureRecognizer handler, прикрепленный к этому изменяемому размеру представлению StateBegan, и в StateChanged я бы вычислил разницу касания X, Y от начального касания и добавила эти значения к начальной ширине кадра и высота.

Однако, когда преобразование применяется, кадр является надежным для повернутого UIView. Таким образом, я могу полагаться только на bounds и center. Я создал этот код, но он почти работает: я могу увеличить изображение пропорционально во всех 4 направлениях, а не в одном.

- (void)handleResizeGesture:(UIPanGestureRecognizer *)recognizer {
    CGPoint touchLocation = [recognizer locationInView:self.superview];
    CGPoint center = self.center;

    switch (recognizer.state) {
        case UIGestureRecognizerStateBegan: {
            deltaAngle = atan2f(touchLocation.y - center.y, touchLocation.x - center.x) - CGAffineTransformGetAngle(self.transform);
            initialBounds = self.bounds;
            initialDistance = CGPointGetDistance(center, touchLocation);
            initialLocation = touchLocation;
            if ([self.delegate respondsToSelector:@selector(stickerViewDidBeginRotating:)]) {
                [self.delegate stickerViewDidBeginRotating:self];
            }
            break;
        }

        case UIGestureRecognizerStateChanged: {

            CGFloat scale = CGPointGetDistance(center, touchLocation)/initialDistance;
            CGFloat minimumScale = self.minimumSize/MIN(initialBounds.size.width, initialBounds.size.height);
            scale = MAX(scale, minimumScale);
            CGRect scaledBounds = CGRectScale(initialBounds, scale, scale);
            self.bounds = scaledBounds;

            [self setNeedsDisplay];

            if ([self.delegate respondsToSelector:@selector(stickerViewDidChangeRotating:)]) {
                [self.delegate stickerViewDidChangeRotating:self];
            }
            break;
        }

        case UIGestureRecognizerStateEnded:
            if ([self.delegate respondsToSelector:@selector(stickerViewDidEndRotating:)]) {
                [self.delegate stickerViewDidEndRotating:self];
            }
            break;

        default:
            break;
    }
}

На рисунке ниже показано повернутое представление с известными значениями (расстояние A, B, x, y, N, M, N-M):

enter image description here

4b9b3361

Ответ 1

Хороший вопрос. Я только что создал класс, который использует что-то подобное. В моем классе вы можете изменить масштаб UIViewA, и он изменит масштаб UIViewB, сохранив тот же коэффициент.

Проверьте маленький белый квадрат в левом верхнем углу:

enter image description here

Этот класс можно найти здесь: https://github.com/sSegev/SSUIViewMiniMe

То, что вы спрашиваете, немного другое. Я изменяю общий размер квадрата, в то время как вы хотите изменить только размер, относящийся к одному из углов, в зависимости от того, как далеко пользователь перетащил его.

Потому что вы не можете нажать на кнопку во время анимации (ну, вы можете, но анимация - просто глазная конфета, а представление уже находится в ней в конечном состоянии). Я использовал CABasicAnimation, что упростило его.

- (void)viewDidAppear:(BOOL)animated
{
        [super viewDidAppear:animated];
        //Rotate the UIView            
    if ([_myRedView.layer animationForKey:@"SpinAnimation"] == nil)
        {
            CABasicAnimation* animation = [CABasicAnimation animationWithKeyPath:@"transform.rotation.z"];
            animation.fromValue = [NSNumber numberWithFloat:0.0f];
            animation.toValue = [NSNumber numberWithFloat: 2*M_PI];
            animation.duration = 50.0f;
            animation.repeatCount = INFINITY;
            [self.myRedView.layer addAnimation:animation forKey:@"SpinAnimation"];
        }
}

 // That the main chunk of code:

- (void)dragBegan:(UIControl *)c withEvent:ev
{
    UITouch *touch = [[ev allTouches] anyObject];
    CGPoint touchPoint = [touch locationInView:_myRedView];
    NSLog(@"Touch x : %f y : %f", touchPoint.x, touchPoint.y);
    if(_myRedView.width/2<touchPoint.x && _myRedView.height/2<touchPoint.y) //Checks for right bottom corner
        {
            _myRedView.width =touchPoint.x;
            _myRedView.height = touchPoint.y;
            dragButton.frame = CGRectMake(0, 0, _myRedView.width, _myRedView.height);
        }
}

Я уверен, что нужна некоторая настройка, но сейчас это выглядит так:

enter image description here                                                                                      *

Довольно круто только для 6 строк кода ha?

Ответ 2

Вместо того, чтобы пытаться изменить фрейм, отрегулируйте свойство scale вашего представления в соответствии с вашими жестами. Это должно соответствующим образом изменить размер вашего представления, не мешая вращению.

Ответ 3

Вставьте свое представление в вид контейнера. Затем преобразуйте контейнер, оставив перетаскиваемый вид неповрежденным. Используйте ту же логику, которую вы использовали для невращающегося вида.