正如您在問題的標題中指出的那樣,mouseEntered和mouseExited僅在鼠標移動時調用。要明白爲什麼會出現這種情況,我們首先來看看第一次添加NSTrackingAreas的過程。
作爲一個簡單的例子,我們創建一個通常會繪製白色背景的視圖,但是如果用戶將鼠標懸停在視圖上,則會繪製紅色背景。這個例子使用ARC。
@interface ExampleView
- (void) createTrackingArea
@property (nonatomic, retain) backgroundColor;
@property (nonatomic, retain) trackingArea;
@end
@implementation ExampleView
@synthesize backgroundColor;
@synthesize trackingArea
- (id) awakeFromNib
{
[self setBackgroundColor: [NSColor whiteColor]];
[self createTrackingArea];
}
- (void) createTrackingArea
{
int opts = (NSTrackingMouseEnteredAndExited | NSTrackingActiveAlways);
trackingArea = [ [NSTrackingArea alloc] initWithRect:[self bounds]
options:opts
owner:self
userInfo:nil];
[self addTrackingArea:trackingArea];
}
- (void) drawRect: (NSRect) rect
{
[[self backgroundColor] set];
NSRectFill(rect);
}
- (void) mouseEntered: (NSEvent*) theEvent
{
[self setBackgroundColor: [NSColor redColor]];
}
- (void) mouseEntered: (NSEvent*) theEvent
{
[self setBackgroundColor: [NSColor whiteColor]];
}
@end
該代碼有兩個問題。首先,當調用-awakeFromNib時,如果鼠標已經在視圖中,則不調用-mouseEntered。這意味着即使鼠標懸停在視圖上,背景仍然是白色的。這是在一個NSView文檔-addTrackingRect的assumeInside參數中實際提到:所有者:用戶數據:assumeInside:
如果是,將被當光標離開aRect,無論如果光標位於內部aRect生成的第一事件當追蹤矩形被添加時。如果否,當光標離開aRect時,如果光標最初位於aRect內,或者光標最初位於aRect外部時光標進入aRect,則光標離開aRect時將生成第一個事件。
在這兩種情況下,如果鼠標位於跟蹤區域內,在鼠標離開跟蹤區域之前不會生成任何事件。
所以要解決這個問題,當我們添加跟蹤區域時,我們需要確定光標是否位於跟蹤區域內。我們的-createTrackingArea方法因此變成了
- (void) createTrackingArea
{
int opts = (NSTrackingMouseEnteredAndExited | NSTrackingActiveAlways);
trackingArea = [ [NSTrackingArea alloc] initWithRect:[self bounds]
options:opts
owner:self
userInfo:nil];
[self addTrackingArea:trackingArea];
NSPoint mouseLocation = [[self window] mouseLocationOutsideOfEventStream];
mouseLocation = [self convertPoint: mouseLocation
fromView: nil];
if (NSPointInRect(mouseLocation, [self bounds]))
{
[self mouseEntered: nil];
}
else
{
[self mouseExited: nil];
}
}
第二個問題是滾動。當滾動或移動視圖時,我們需要重新計算該視圖中的NSTrackingAreas。這是通過刪除跟蹤區域然後將其添加回來完成的。如您所述,當您滾動視圖時調用-updateTrackingAreas。這是刪除並重新添加區域的地方。
- (void) updateTrackingAreas
{
[self removeTrackingArea:trackingArea];
[self createTrackingArea];
[super updateTrackingAreas]; // Needed, according to the NSView documentation
}
而這應該照顧你的問題。無可否認,每次添加跟蹤區域時需要查找鼠標位置,然後將其轉換爲視圖座標,這種情況會很快變老,所以我建議在NSView上自動處理此類別。你不會總是能夠調用[self mouseEntered:nil]或[self mouseExited:nil],所以你可能想讓這個類別接受幾個塊。如果鼠標位於NSTrackingArea中,則運行一個,如果不是,則運行一個。
有幾件事情要考慮。什麼是超類?你是否覆蓋任何超類方法而不發送超類?然後,這裏是我總是傳遞給trackingArea的選項,以確保鼠標實際上始終被跟蹤:NSTrackingMouseEnteredAndExited | NSTrackingMouseMoved | NSTrackingActiveInKeyWindow – Dimillian
@ Dimillian77我改爲了「NSTrackingMouseEnteredAndExited | NSTrackingMouseMoved | NSTrackingActiveInKeyWindow」,但沒有幫助..同樣的問題。沒有「NSTrackingActiveAlways」,它根本就不起作用。我更新了我的問題,使它更清晰。 –
你需要調用'[super updateTrackingAreas]'。而這段代碼是在NSViews的子類或NSScrollView中? –