web-dev-qa-db-fra.com

UIScrollView dans UIScrollView

J'ai un UIScrollView avec un autre UIScrollView à l'intérieur. Ils défilent tous les deux horizontalement et ont pagingEnabled = YES. Supposons que j'ai commencé à faire défiler la vue de défilement interne et atteint la limite la plus à droite. Et si je continue à y faire défiler, alors le scrollView externe commence à se déplacer. Je dois éviter cela. La vue intérieure doit sauter avec effet élastique, l'extérieur doit rester à sa place.

J'espère que c'est clair, mais voici un croquis: enter image description here

J'ai essayé de définir outerView.scrollEnabled = NO; comme ça:

- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView
{
    outerView.scrollEnabled = NO;
}

, et cela fonctionne exactement comme j'ai besoin, si vous souhaitez faire défiler uniquement dans innerView. OuterView ne défile plus. Mais je dois redéfinir scrollEnabled sur YES quelque part pour le cas si je veux faire défiler la vue externe à nouveau. J'ai essayé de le faire ici:

- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
{
    outerView.scrollEnabled = YES;
}

, mais j'obtiens le même problème: après avoir atteint la limite la plus à droite des scrolls innerView externalView au lieu des sauts innerView avec effet élastique.

Des suggestions pour résoudre un problème?

28
Anastasia

MISE À JOUR

Cette solution fonctionne toujours:

@implementation InnerScrollViewController <UIScrollViewDelegate, UIGestureRecognizerDelegate>

- (void)viewDidLoad
{
    UISwipeGestureRecognizer*   swipeGesture = [[[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(handleSwipe:)] autorelease];
    swipeGesture.delegate = self;
    [self.view addGestureRecognizer:swipeGesture];
}

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch
{
    _outerScrollView.scrollEnabled = NO;
    return YES;
}

- (void)handleSwipe:(UIGestureRecognizer*)gestureRecognizer
{

}

- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView
{   
    _outerScrollView.scrollEnabled = NO;
}

- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate
{
    if (!decelerate)
    {
        _outerScrollView.scrollEnabled = YES;
    }
}

- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
{
    _outerScrollView.scrollEnabled = YES;
}

@end

---------------------------------------------- -------------------------

ANCIENNE RÉPONSE: ne fonctionne pas toujours

Voici comment j'ai résolu le problème:

@implementation InnerView

- (id)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        self.delaysContentTouches = NO;
    }
    return self;
}

- (BOOL)touchesShouldBegin:(NSSet *)touches withEvent:(UIEvent *)event inContentView:(UIView *)view
{
    return NO;
}

Si je comprends bien, self.delaysContentTouches = NO; Fait que tous les événements doivent être livrés immédiatement, et - (BOOL)touchesShouldBegin:(NSSet *)touches withEvent:(UIEvent *)event inContentView:(UIView *)view empêche le passage de ces événements par la chaîne de répondeur.

18
Anastasia

Modifiez vos méthodes de la manière suivante:

- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView
{
    if(scrollView == innerView)
        outerView.scrollEnabled = NO;
    else
        outerView.scrollEnabled = YES;
}

- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
{
    if(scrollView == innerView)
    {
         if(innerView.contentOffset.x + innerView.frame.size.width == innerView.contentSize.width)
         {
              outerView.scrollEnabled = NO;
         }
         else
         {
              outerView.scrollEnabled = YES;
         }
    }
}
2
Apurv

J'ai un problème similaire. J'ai trouvé la solution, mais cela ne fonctionne qu'avec innerScrollView.bounces = NO.

@interface PageCtrl ()
    @property (weak, nonatomic) IBOutlet UIScrollView *innerScrollView;
    @property(nonatomic) UIPanGestureRecognizer *panLockScroll;
@end

@implementation PageCtrl
- (void)viewDidLoad {
    // ...
    self.innerScrollView.delegate = self;   

    self.innerScrollView.bounces = NO;   // disable bounces!

    self.panLockScroll = [[UIPanGestureRecognizer alloc]initWithTarget:self action:nil];
    self.panLockScroll.delegate = self;
    [self.innerScrollView addGestureRecognizer:self.panLockScroll];
}

- (BOOL)gestureRecognizer:(UIGestureRecognizer*)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer*)otherGestureRecognizer{
    if( gestureRecognizer == self.panLockScroll && 
        otherGestureRecognizer == self.innerScrollView.panGestureRecognizer ){
        return YES;
    }
    return NO;
}

@end
2
Eol

Cela fonctionne bien pour moi:

- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView
{
  outerScrollView.scrollEnabled = NO;
}

- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
{
  [NSTimer scheduledTimerWithTimeInterval:0.3
                                     target:[NSBlockOperation blockOperationWithBlock:^{ outerScrollView.scrollEnabled = YES; }]
                                   selector:@selector(main)
                                   userInfo:nil
                                    repeats:NO];
}

N'oubliez pas d'adopter UIScrollViewDelegate dans votre déclaration de classe et de définir le délégué de innerScrollView sur self (n'affectez PAS le délégué de externalScrollView)

1
etayluz