Pergunta

I want to prevent a UICollectionViewController from auto rotation when there's a finger on the screen. The finger could move, the device could rotate, but the UICollectionViewController shouldn't rotate whenever the finger is still on screen.

And the UICollectionViewController should rotate immediately when the finger left the screen. As the iPhone photo app does.

Question:

  1. How to detect touch?

    I overwrite the touchBegan:withEvent: etc. in UICollectionView subclass. But when the UICollectionView start scrolling, it calls touchCanceled:withEvent: method.

    If I start scrolling the UICollectionView earlier, the touchBegan:withEvent: does even not fired.

  2. How to prevent auto rotation temporarily?

    I overwrite the shouldAutorotate in my view controller to prevent rotation. But when the finger left the screen, the UICollectionView can't rotate immediately.

Foi útil?

Solução

Try this code, please:

@interface BlockAutorotateViewController ()

@property (nonatomic, strong) UILongPressGestureRecognizer *longPressGestureRecognizer;
@property (nonatomic, strong) UISwipeGestureRecognizer *swipeGestureRecognizer;
@property (nonatomic, assign, getter = isPressed) BOOL pressed;

@end

@implementation BlockAutorotateViewController

- (void)viewDidLoad
{
    [super viewDidLoad];

    self.pressed = NO;

    self.longPressGestureRecognizer = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(myLongPressAction:)];
    self.longPressGestureRecognizer.minimumPressDuration = 0;
    [self.view addGestureRecognizer:self.longPressGestureRecognizer];

    self.swipeGestureRecognizer = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(mySwipeAction:)];
    [self.view addGestureRecognizer:self.swipeGestureRecognizer];

}

- (void)myLongPressAction:(id)sender
{
    if ((self.longPressGestureRecognizer.state == UIGestureRecognizerStateEnded) || (self.longPressGestureRecognizer.state == UIGestureRecognizerStateChanged))  {
        self.pressed = YES;
    }
    else if (self.longPressGestureRecognizer.state == UIGestureRecognizerStateBegan) {
        self.pressed = NO;
        [UIViewController attemptRotationToDeviceOrientation];
    }
    else {
        self.pressed = NO;
    }
}

- (void)mySwipeAction:(id)sender
{
    if ((self.swipeGestureRecognizer.state == UIGestureRecognizerStateBegan) || (self.longPressGestureRecognizer.state == UIGestureRecognizerStateChanged))  {
        self.pressed = YES;
    }
    else if (self.longPressGestureRecognizer.state == UIGestureRecognizerStateEnded) {
        self.pressed = NO;
        [UIViewController attemptRotationToDeviceOrientation];
    }
    else {
        self.pressed = NO;
    }
}

- (BOOL)shouldAutorotate
{
    return (self.isPressed ? NO : YES);
}

@end

Outras dicas

For detecting the touch event, I would recommend using a UIGestureRecognizer rather than overriding the UICollectionViewController's touch events. That way you can be notified of the touch event without interfering with the existing event handling.

You will probably need two custom UIGestureRecognizer classes to implement this, since I don't think UITapGestureRecognizer will meet your needs. You can have one UIGestureRecognizer notify you of finger down events and another notify you when the finger is lifted.

For preventing auto rotation, override shouldAutorotate as you have already done. When your gesture recognizer detects that the finger has been lifted, call [UIViewController attemptRotationToDeviceOrientation] to tell iOS to rotate the UI to the current orientation. (Obviously make sure that shouldAutorotate will now return YES before calling that.)

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top