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];
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.
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:
- ustawienie
canCancelContentTouches
WUIScrollView
naYES
. - Rozszerzenie
UIScrollView
aby nadpisaćtouchesShouldCancelInContentView:(UIView *)view
aby zwrócićYES
Gdyview
jestUIButton
.
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.
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
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.
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.
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.
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:
- Zastąp przycisk de prostym niestandardowym UIView
- umieść flagę "userInterationEnable = yes;" w metodzie init
- W widoku nadpisać metodę UIResponder "dotyka" tutaj możesz wywołać akcję
Czwarty. Ustaw delaysContentTouches
Na YES
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