Обнаружение, находится ли представление CGAffineTransformed вне границ экрана / UIView - PullRequest
0 голосов
/ 04 апреля 2011

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

Похоже, что перетаскивание не является проблемой, так как я не использую Transform для генерации новой позиции и проверки, если этоновая позиция уберет вид с экрана.

Когда я вращаюсь или масштабируюсь, я использую CGAffineTransform (CGAffineTransformedRotate или CGAffineTransformScale), и я не могу понять, каким будет новый кадр, фактически не применяя его к моему виду.

CGRect  newElementBounds = CGRectApplyAffineTransform(element.bounds, CGAffineTransformScale([[gestureRecognizer view] transform], [gestureRecognizer scale], [gestureRecognizer scale]));


CGRect elementBoundsInSuperView = [element convertRect:newElementBounds toView:[element superview]];

elementBoundsInSuperView - это не тот объект, который я бы ожидал, его нет.

Я также пытался сначала получить границы в SuperView, а затем применить преобразованиеи это тоже неправильно.

CGRect elementBoundsInSuperView = [element convertRect:element.bounds toView:[element superview]];

CGRect  newElementBounds = CGRectApplyAffineTransform(newElementBounds, CGAffineTransformScale([[gestureRecognizer view] transform], [gestureRecognizer scale], [gestureRecognizer scale]));

[представление gestRecognizer] должно совпадать с element .

1 Ответ

2 голосов
/ 01 сентября 2011

Я придумал несколько обработчиков жестов, которые работают так, чтобы представление, которым вы манипулировали, не выходило за пределы указанной вами области. Поддон My View был определен как kscreenEditorSpace, 2048.

Жест Pan просто вызывает calcCenterFromXposition: yPosition: fromBoundsInSuperView: метод для установки центра, если центр выпадает из границ, он просто корректирует и сохраняет элемент в границах

//--------------------------------------------------------------------------------------------------------
//    handlePanGesture
//    Description: Called when scrollView got a DoubleFinger DoubleTap Gesture
//                 We want to Zoom out one ZOOM_STEP.               
//
//--------------------------------------------------------------------------------------------------------
- (void)handlePanGesture:(UIPanGestureRecognizer *)gestureRecognizer {

    UIView *element = [gestureRecognizer view];


    if ([gestureRecognizer state] == UIGestureRecognizerStateBegan ) {
            [[self superview] bringSubviewToFront:self]; 
    }

    if ([gestureRecognizer state] == UIGestureRecognizerStateBegan || [gestureRecognizer state] == UIGestureRecognizerStateChanged) {
            //Front and Center Mr Element! 

            // Find out where we are going
        CGPoint translation = [gestureRecognizer translationInView:[element superview]];
        CGRect elementBoundsInSuperView = [element convertRect:element.bounds toView:[element superview]];
        CGFloat xPosition = CGRectGetMidX(elementBoundsInSuperView) + translation.x;
        CGFloat yPosition = CGRectGetMidY(elementBoundsInSuperView) + translation.y;

        CGPoint newCenter = [self calcCenterFromXposition:xPosition yPosition:yPosition fromBoundsInSuperView:elementBoundsInSuperView];

            //Re position ourselves
        [element setCenter:newCenter];

            //set the translation back to 0 point
        [gestureRecognizer setTranslation:CGPointZero inView:[element superview]];
        [self setNeedsDisplay];
    }

    if ([gestureRecognizer state] == UIGestureRecognizerStateEnded ) {
    }

}

Так что ручка Pinch и Rotation довольно похожи. вместо прямого вызова Calc Center, мы вызываем другой метод, чтобы определить, находимся ли мы в границах.

//--------------------------------------------------------------------------------------------------------
//    handlePinchGesture
//    Description: Called when scrollView got a DoubleFinger DoubleTap Gesture
//                 We want to Zoom out one ZOOM_STEP.               
//
//--------------------------------------------------------------------------------------------------------

- (void)handlePinchGesture:(UIPinchGestureRecognizer *)gestureRecognizer {
    if ([gestureRecognizer state] == UIGestureRecognizerStateBegan ) {

        [[self superview] bringSubviewToFront:self]; 
    }

    if ([gestureRecognizer state] == UIGestureRecognizerStateBegan || [gestureRecognizer state] == UIGestureRecognizerStateChanged) {



        BOOL aSelectedElementOffscreen = FALSE;
            if ([[gestureRecognizer view] pinchOffScreen:[gestureRecognizer scale]]) {
                aSelectedElementOffscreen = TRUE;
            }

        if (!aSelectedElementOffscreen) {

            [gestureRecognizer view].transform = CGAffineTransformScale([[gestureRecognizer view] transform], [gestureRecognizer scale], [gestureRecognizer scale]);

                //Update ourself
            [self contentSizeChanged];  
     }
             [gestureRecognizer setScale:1];
    }

    if ([gestureRecognizer state] == UIGestureRecognizerStateEnded) {

        if (![self becomeFirstResponder]) {
            NSLog(@" %@ - %@ - couldn't become first responder", INTERFACENAME, NSStringFromSelector(_cmd) );
            return;
        }
    }
}
}

Метод удаления с экрана

 //--------------------------------------------------------------------------------------------------------
//    pinchOffScreen
//    Description: Called to see if the Pinch Gesture will cause element to go off screen Gesture
//
//--------------------------------------------------------------------------------------------------------

- (BOOL)pinchOffScreen:(CGFloat)scale {

    // Save Our Current Transform incase we go off Screen
CGAffineTransform elementOrigTransform = [self transform];
    //Apply our Transform
self.transform = CGAffineTransformScale([self transform],  scale,  scale);
    // Get our new Bounds in the SuperView
CGRect newElementBoundsInSuperView = [self convertRect:self.bounds toView:[self superview]];

    //Find out where we are in the SuperView 
CGFloat xPosition = CGRectGetMidX( newElementBoundsInSuperView);
CGFloat yPosition = CGRectGetMidY( newElementBoundsInSuperView);

    //See if we are off the Screen
BOOL offScreen = [self calcOffEditorFromXposition:xPosition yPosition:yPosition fromBoundsInSuperView: newElementBoundsInSuperView];

    // We just wanted to Check. Revert to where we were
self.transform = elementOrigTransform;
return offScreen;

}

Поворот дескриптора аналогичен повороту, у нас есть вспомогательный метод, чтобы посмотреть, не повернули ли мы за пределы экрана.

//--------------------------------------------------------------------------------------------------------
//    handleRotationGesture
//    Description: Called when we get a rotation gesture
//                 toggle the scroll/zoom lock
//
//--------------------------------------------------------------------------------------------------------

- (void) handleRotationGesture:(UIRotationGestureRecognizer *)gestureRecognizer{
    UIView *element = [gestureRecognizer view];

    if ([gestureRecognizer state] == UIGestureRecognizerStateBegan ) {
                [[self superview] bringSubviewToFront:self]; 
    }

    if ([gestureRecognizer state] == UIGestureRecognizerStateBegan || [gestureRecognizer state] == UIGestureRecognizerStateChanged) {


        BOOL aSelectedElementOffscreen = FALSE;
            if ([element rotateOffScreen:[gestureRecognizer rotation]]) {
                aSelectedElementOffscreen = TRUE;
            }

        if (!aSelectedElementOffscreen) {

            [gestureRecognizer view].transform = CGAffineTransformRotate([element transform], [gestureRecognizer rotation]);


                //Update ourself
            [self contentSizeChanged];  

        }
        [gestureRecognizer setRotation:0];
    }
    if ([gestureRecognizer state] == UIGestureRecognizerStateEnded) {
    }
}
}

Метод поворота за пределами экрана

//--------------------------------------------------------------------------------------------------------
//    rotateOffScreen
//    Description: Called to see if the Rotation Gesture will cause element to go off screen Gesture
//
//--------------------------------------------------------------------------------------------------------

- (BOOL)rotateOffScreen:(CGFloat)rotation {

    // Save Our Current Transform incase we go off Screen
CGAffineTransform elementOrigTransform = [self transform];
    //Apply our Transform
self.transform = CGAffineTransformRotate([self transform], rotation);
    // Get our new Bounds in the SuperView
CGRect newElementBoundsInSuperView = [self convertRect:self.bounds toView:[self superview]];

    //Find out where we are in the SuperVire 
CGFloat xPosition = CGRectGetMidX( newElementBoundsInSuperView);
CGFloat yPosition = CGRectGetMidY( newElementBoundsInSuperView);

    //See if we are off the Screen
BOOL offScreen = [self calcOffEditorFromXposition:xPosition yPosition:yPosition fromBoundsInSuperView: newElementBoundsInSuperView];

    // We just wanted to Check. Revert to where we were
self.transform = elementOrigTransform;

return offScreen;

}

Методы вспомогательного позиционирования экрана Calc

#pragma mark -
#pragma mark === Calc Screen Positioning  ===
#pragma mark
//--------------------------------------------------------------------------------------------------------
//    calcCenterFromXposition: yPosition: fromBoundsInSuperView:
//    Description: calculate the center point in the element's super view from x, y
//
//--------------------------------------------------------------------------------------------------------
-(CGPoint) calcCenterFromXposition: (CGFloat) xPosition yPosition:(CGFloat) yPosition fromBoundsInSuperView:(CGRect) elementBoundsInSuperView{


    // Ge the Height/width based on SuperView Bounds
CGFloat elementWidth = CGRectGetWidth(elementBoundsInSuperView); 
CGFloat elementHeight = CGRectGetHeight(elementBoundsInSuperView);

    //Determine our center.x from the new x
if (xPosition < elementWidth/2) {
    xPosition = elementWidth/2;
} else if (xPosition + elementWidth/2  > kscreenEditorSpace) {
    xPosition = kscreenEditorSpace - elementWidth/2;
}   
    //Determine our center.y from the new y
if (yPosition < elementHeight/2) {
    yPosition = elementHeight/2;
} else if (yPosition + elementHeight/2  > kscreenEditorSpace) {
    yPosition = kscreenEditorSpace - elementHeight/2;
} 
return (CGPointMake(xPosition, yPosition));
}

//--------------------------------------------------------------------------------------------------------
//    calcOffEditorFromXposition: yPosition: fromBoundsInSuperView:
//    Description: Determine if moving the element to x, y will it be off the editor screen
//
//--------------------------------------------------------------------------------------------------------
-(BOOL) calcOffEditorFromXposition: (CGFloat) xPosition yPosition:(CGFloat) yPosition fromBoundsInSuperView:(CGRect) elementBoundsInSuperView{

BOOL offScreen = NO;

    // Ge the Height/width based on SuperView Bounds
CGFloat elementWidth = CGRectGetWidth(elementBoundsInSuperView); 
CGFloat elementHeight = CGRectGetHeight(elementBoundsInSuperView);

    // Off Screen on Left
if (xPosition < elementWidth/2) {
    offScreen = YES;
} 
    //Off Screen Right
if (xPosition + elementWidth/2  > kscreenEditorSpace) {
    offScreen = YES;;
}

    // Off Screen Top
if (yPosition < elementHeight/2) {
    offScreen = YES;
} 

    //Off Screen Bottom
if (yPosition + elementHeight/2  > kscreenEditorSpace) {
    offScreen = YES;
}

return (offScreen);
}
...