UIScrollview z UIButtons - jak odtworzyć springboard?

Próbuję stworzyć interfejs przypominający trampolinę w mojej aplikacji. Próbuję użyć UIButtons dodany do UIScrollView. Problem, w którym uruchamiam, polega na tym, że przyciski nie przekazują żadnych dotknięć do UIScrollView - jeśli spróbuję flick/slide i zdarzy mi się nacisnąć przycisk, to nie rejestruje się w UIScrollView, ale jeśli przesuwam spację między przyciskami, to będzie działać. Przyciski klikają / działają, jeśli ich dotknę.

Czy istnieje właściwość lub ustawienie, które wymusza wysłanie przycisku dotknij zdarzeń do swojego rodzica (superview)? Czy przyciski muszą być dodane do czegoś innego przed dodaniem UIScrollView?

Oto Mój kod:

//init scrolling area
UIScrollView *scrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(0, 0, 480, 480)];
scrollView.contentSize = CGSizeMake(480, 1000);
scrollView.bounces = NO;
scrollView.delaysContentTouches = NO;

//create background image
UIImageView *rowsBackground = [[UIImageView alloc] initWithImage:[self scaleAndRotateImage:[UIImage imageNamed:@"mylongbackground.png"]]];
rowsBackground.userInteractionEnabled = YES;

//create button
UIButton *btn = [[UIButton buttonWithType:UIButtonTypeCustom] retain];
btn.frame = CGRectMake(100, 850, 150, 150);
btn.bounds = CGRectMake(0, 0, 150.0, 150.0);
[btn setImage:[self scaleAndRotateImage:[UIImage imageNamed:@"basicbutton.png"]] forState:UIControlStateNormal];
[btn addTarget:self action:@selector(buttonClick) forControlEvents:UIControlEventTouchUpInside];

//add "stuff" to scrolling area
[scrollView addSubview:rowsBackground];
[scrollView addSubview:btn];

//add scrolling area to cocos2d
//this is just a UIWindow
[[[Director sharedDirector] openGLView] addSubview:scrollView];

//mem-mgmt
[rowsBackground release];
[btn release];
[scrollView release];
Author: GingerHead, 2009-03-16

7 answers

Aby UIScrollView określić różnicę między kliknięciem, które przechodzi do widoku zawartości, a dotknięciem, które zmienia się w machnięcie lub uszczypnięcie, należy opóźnić dotknięcie i sprawdzić, czy palec nie przesunął się podczas tego opóźnienia. Ustawiając delaysContentTouches na NO w powyższym przykładzie, zapobiegasz temu. Dlatego widok przewijania zawsze przekazuje dotyk do przycisku, zamiast go anulować, gdy okaże się, że użytkownik wykonuje gest machnięcia. Spróbuj ustawić delaysContentTouches do YES.

Dobrym pomysłem może być również dodanie wszystkich widoków, które mają być hostowane w widoku przewijania do wspólnego widoku treści i używanie tylko tego jednego widoku jako podglądu podrzędnego widoku przewijania.

 28
Author: Brad Larson,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-06-04 15:41:26

Rozwiązanie, które zadziałało dla mnie to:

  1. ustawienie canCancelContentTouches W UIScrollView na YES.
  2. Rozszerzenie UIScrollView aby nadpisać touchesShouldCancelInContentView:(UIView *)view aby zwrócić YES Gdy view jest UIButton.

Zgodnie z dokumentacją touchesShouldCancelInContentView zwraca " {[2] } aby anulować kolejne wiadomości dotykowe do wyświetlenia, NO aby Widok nadal odbierał te wiadomości. Domyślną zwracaną wartością jest YES, jeśli view nie jest obiektem UIControl; w przeciwnym razie zwraca NO."

Ponieważ UIButton jest UIControl rozszerzenie jest konieczne, aby uzyskać efekt canCancelContentTouches, który umożliwia przewijanie.

 44
Author: Roman Kishchenko,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-06-04 15:42:45

Mam podobny przypadek, że kilka przycisków na UIScrollView, i chcę przewijać te przyciski. Na początku podklasowałem zarówno UIScrollView, jak i UIButton. Zauważyłem jednak, że mój podklasowany uiscrollview nie otrzymał zdarzenia touchesEnded, więc zmieniłem na tylko podklasowy UIButton.


@interface MyPhotoButton : UIButton {
}

- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event;
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event;
- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event;
@end

@implementation MyPhotoButton

- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
    [super touchesMoved:touches withEvent:event];
    [self setEnabled:NO];
    [self setSelected:NO];
}

- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
    [super touchesEnded:touches withEvent:event];
    [self setEnabled:YES];
}

- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event {
    [super touchesCancelled:touches withEvent:event];
    [self setEnabled:YES];
}

@end
 5
Author: Richard Chen,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-04-28 03:56:33

UIScrollView sam obsługuje wiele zdarzeń. Musisz obsługiwać touchesDidEnd i hit test dla przycisków wewnątrz UIScrollView ręcznie.

 1
Author: Rog,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-03-16 14:15:38

OK Oto Twoja odpowiedź:

Podklasa UIButton. (Uwaga: zadzwoń [super ....] na początku każdego obejścia.

  • Dodaj nieruchomość. Jeden z typu BOOL (enabletorestore)
  • Dodaj nieruchomość. Jeden z Typu CGPoint (tzw. startTouchPosition)
  • w przebudzeniu i initWithFrame, Ustaw enableToRestore do isEnabled property)
  • Override " touchesBegan: withEvent:" aby zapisać początek dotyku pozycji.
  • Override " touchesMoved: withEvent: "do sprawdź, czy jest poziome ruch.
  • Jeśli tak, ustaw włączone na nie i wybrany do NO.

Przykładowy kod:

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event 
{
    UITouch *touch = [touches anyObject];

    [super touchesBegan:touches withEvent:event];
    [self setStartTouchPosition:[touch locationInView:self]];
}


//
// Helper Function
//
- (BOOL)isTouchMovingHorizontally:(UITouch *)touch 
{
    CGPoint currentTouchPosition = [touch locationInView:self];
    BOOL      rValue = NO;

    if (fabsf([self startTouchPosition].x - currentTouchPosition.x) >= 2.0) 
    {
        rValue = YES;
    }

    return (rValue);
}

//
// This is called when the finger is moved.  If the result is a left or right
// movement, the button will disable resulting in the UIScrollView being the
// next responder.  The parrent ScrollView will then re-enable the button
// when the finger event is ended of cancelled.
//
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event 
{
    [super touchesMoved:touches withEvent:event];
    if ([self isTouchMovingHorizontally:[touches anyObject]]) 
    {
        [self setEnabled:NO];
        [self setSelected:NO];
    } 
}

Spowoduje to uiscrollview.

Podklasa UIScrollView. (Uwaga: zadzwoń [super ....] na początku każdego obejścia.

  • Override both "touchesEnded: withEvent:" and "touchesancelled: withEvent:"
  • w nadpisaniu Zresetuj wszystkie podviews (i ich podviews) włączone znacznik.
  • Uwaga: użyj kategorii i dodać metodę do UIView:

.

- (void) restoreAllEnables
{
    NSArray   *views = [self subviews];

    for (UIView *aView in views)
    {
        if ([aView respondsToSelector:@selector(restoreEnable)])
        {
            [aView restoreEnable];
        }
    }
}

- (void) touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
    [super touchesEnded:touches withEvent:event];
    [self restoreAllEnables];
}

- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
{
    [super touchesEnded:touches withEvent:event];
    [self restoreAllEnables];
}
  • w kategorii:

.

-(void) restoreEnable
{
    NSArray   *views = [self subviews];

    if ([self respondsToSelector:@selector(enableToRestore)])
    {
        [self setEnabled:[self enableToRestore]];
    }

    for (UIView *aView in views)
    {
        if ([aView respondsToSelector:@selector(restoreEnable)])
        {
            [aView restoreEnable];
        }
    }
}

Edytuj Uwaga: nigdy nie dostałem odpowiedzi 3 do pracy. Podobnie: setDelaysContentTouches: NO (ustawiony w kontrolerze widoku lub gdzieś) ma być ustawiony dla najlepszych wyników w odpowiedzi 4. Zapewnia to bardzo szybką reakcję na przyciski. Ustawienie setDelaysContentTouches: Yes poważnie wpływa (150ms) na czas reakcji na przyciski i sprawia, że lekkie, szybkie dotykanie nie jest możliwe.

 1
Author: Steven Noyes,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-02-26 03:43:44

Inny sposób to:
1. Zastąp przycisk de prostym niestandardowym UIView
2. Umieść flagę " userInterationEnable = yes;" w metodzie init
3. W widoku zastąp metodę UIResponder "touchesEnded" tutaj możesz wywołać akcję, której potrzebujesz jak przycisk.

 0
Author: user41806,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-05-30 17:55:50

Z mojego doświadczenia wynika, że pierwsza odpowiedź, tj. zwykłe ustawienie delaysContentTouches na YES, nie zmienia niczego w odniesieniu do problemu. Przyciski nadal nie będą dostarczać wyników śledzenia do widoku przewijania. Trzecia odpowiedź jest zarówno prosta, jak i bardzo użyteczna. Dzięki sieroaoj!

Jednak, aby trzecia odpowiedź zadziałała, musisz również delaysContentTouches ustawić na YES. W przeciwnym razie metoda touchesEnded zostanie również wywołana do śledzenia w widoku. Dlatego mogę rozwiązać problem poprzez:

  1. Zastąp przycisk de prostym niestandardowym UIView
  2. umieść flagę "userInterationEnable = yes;" w metodzie init
  3. W widoku nadpisać metodę UIResponder "dotyka" tutaj możesz wywołać akcję

Czwarty. Ustaw delaysContentTouches Na YES

 0
Author: Captain Fim,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-11-11 09:12:48