2009-08-15 5 views
6

Скажем, у меня есть этот код:Как сделать кнопку перехвата надписью для перехвата событий?

#import <UIKit/UIKit.h> 

@interface MyView : UIView 
@end 
@implementation MyView 

- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event 
{ 
    // How can I get this to show up even when the button is touched? 
    NSLog(@"%@", [touches anyObject]); 
} 

@end 

@interface TestViewAppDelegate : NSObject <UIApplicationDelegate> 
{ 
    UIWindow *window; 
} 

@end 

@implementation TestViewAppDelegate 

- (void)applicationDidFinishLaunching:(UIApplication *)application 
{ 
    window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; 

    MyView *view = [[MyView alloc] initWithFrame:[window frame]]; 
    [view setBackgroundColor:[UIColor whiteColor]]; 

    UIButton *button = [UIButton buttonWithType:UIButtonTypeRoundedRect]; 
    [button setTitle:@"Hiya!" forState:UIControlStateNormal]; 
    [button setFrame:CGRectMake(100.0, 100.0, 200.0, 200.0)]; 
    [view addSubview:button]; 

    [window addSubview:view]; 
    [window makeKeyAndVisible]; 
} 


- (void)dealloc 
{ 
    [window release]; 
    [super dealloc]; 
} 

@end 

Есть ли способ, чтобы перехватить события прикосновения получать отправляемые на кнопку? В конечном итоге я хотел бы сделать подкласс UIView, который будет сообщать контроллеру своего представления (или делегировать, в зависимости от того, что произойдет), когда он обнаружит салфетки, чтобы он мог «нажать» следующий контроллер представления в стек (подобно домашнему экрану iPhone). Я решил, что это был первый шаг, но я открыт для предложений, если я приближаюсь к этому неправильно.

ответ

1

Благодарим за предложения и содержательные ответы. Я закончил с использованием объяснения, приведенного на странице this: (в разделе «Trick 1: эмуляция фотографий, приложение для прокрутки/масштабирования/прокрутки с помощью единого UIScrollView»).

16

я был бы заинтересован в том, чтобы другие решения, но самый простой способ я знаю, чтобы переопределить любой из этих методов два UIView:

- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event; 
- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event; 

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

return [super hitTest:point withEvent:event]; 

или

return [super pointInside:point withEvent:event]; 
+0

Вы не имеете в виду возвращение [superview hitTest: point withEvent: event]; –

+0

'super' прав, потому что вы хотите вызвать метод родительского класса классов,' superiew' пропустит это. – keegan3d

0

Я считаю, что вы должны создать подкласс UIButton в этом случае и переопределять ответы на UIResponder прикосновения и движения события. Затем вы можете перенаправить их на любой объект, который вы хотели бы предположить, что подкласс UIButton может получить к нему.

В этом случае вы передадите их в супервизор UIButton.

@interface MyButton : UIButton 
@end 

@implementation MyButton 

- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event 
{ 
    [[self superview] touchesMoved:touches withEvent:event]; 
} 

@end 

См UIResponder documentation

+1

UIButton - кластер классов, к сожалению. Это означает, что почти невозможно подклассы. –

+0

Я не знал, что это так плохо. Он упомянул только о подклассе UIView, поэтому я просто собирался с UIButton, так как он использовал его в своем примере кода. – criscokid

4

Instinct бы сказать «подкласс UIButton», но UIButton на самом деле класс кластера (то есть, фактический тип объекта прозрачно меняется в зависимости от того, какую кнопку вы хотите сделать), что делает его чрезвычайно сложным для подкласса. Если вы не переписываете UIButton, вы вряд ли сможете это сделать.

Когда мне нужно было решить почти идентичную проблему, я придумал представление, в котором используется композиция для отображения прокси UIView, но все же допускается перехват касания. Вот как это работает:

@interface MyView : UIView { 
    UIView * visibleView; 
} 

- (id) initWithFrame:(CGRect)frame controlClass:(Class)class; 

@end 


@implementation MyView 

- (id) initWithFrame:(CGRect)frame controlClass:(Class)class { 
    if (self = [super initWithFrame:frame]) { 
    CGRect visibleViewFrame = frame; 
    visibleViewFrame.origin = CGPointZero; 
    visibleView = [[class alloc] initWithFrame:visibleViewFrame]; 
    [visibleView setUserInteractionEnabled:NO]; 
    [self addSubview:visibleView]; 

    [self setUserInteractionEnabled:YES]; 
    [self setBackgroundColor:[UIColor clearColor]]; 
    } 
    return self; 
} 

- (void) dealloc { 
    [visibleView removeFromSuperview]; 
    [visibleView release], visibleView = nil; 
    [super dealloc]; 
} 

- (void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { 
    if (someCondition == YES) { 
    [visibleView touchesBegan:touches withEvent:event]; 
    } 
} 

//and similar methods for touchesMoved:, touchesEnded:, etc 

@end 

Основная идея в том, что вы встраивание кнопку (или любой другой) в класс контейнера (по аналогии с тем, что вы описали в своем вопросе). Тем не менее, вы отключите взаимодействие на кнопке, а это означает, что когда пользователь нажимает кнопку, событие нажатия «провалится» на кнопку и в кнопки, содержащие супервизор (в этом случае ваш экземпляр MyView). Оттуда вы можете обработать касание соответствующим образом. Если вы хотите, чтобы кнопка «отвечала» на ощупь, просто позвольте кнопке сделать это, отправив соответствующее сообщение UIResponder. (Вы можешь необходимость повторного включения userInteractionEnabled на visibleView первый, хотя. Я не уверен в этом.)

Как я уже говорил выше, я использовал этот подход (не именно эту реализацию, но этот шаблон) довольно успешно, когда мне нужно было иметь кнопку на интерфейсе, но и захватить сам объект UITouch.

3

Могу ли я предлагаю использовать этот подход вместо:

UITapGestureRecognizer *tapRecognizer = [[UITapGestureRecognizer alloc] 
               initWithTarget:self 
               action:@selector(tapDetected:)]; 
    tapRecognizer.numberOfTapsRequired = 1; 
    tapRecognizer.numberOfTouchesRequired = 1; 

    [self.view addGestureRecognizer:tapRecognizer]; 

Вы можете сделать это с надтаблицы, нет необходимости создавать собственные элементы пользовательского интерфейса.

+0

Nice, UITapGestureRecognizer отлично поработал с UIView, который содержит несколько UILabel. – joelsand

Смежные вопросы