为什么文本字段中的闪烁光标会导致调用drawRect?

Tob*_*ias 5 macos cocoa objective-c appkit

我的程序中有以下视图层次结构设置.

Window
+ContentView (Subview of Window)
++MyCustomView (Subview of ContentView)
++MyCustomOpaqueView (Subview of ContentView)
+++TextField (Subview of MyCustomOpaqueView)
Run Code Online (Sandbox Code Playgroud)

当用户单击TextField时,其中的光标开始闪烁.在每次闪烁时,在MyCustomView上调用drawRect.没什么大不了的,但我想知道为什么?

在MyCustomOpaqueView中,我实现了isOpaque,

- (BOOL)isOpaque {return YES;}
Run Code Online (Sandbox Code Playgroud)

如果传递给drawRect的NSRect被一个不透明的视图完全遮挡,我认为这会阻止消息传递给MyCustomView中的drawRect,但是当光标闪烁时,MyCustomView仍然会发送一个完全在不透明视图后面的NSRect的drawRect消息.

我错过了一个关键概念还是闪烁光标的怪癖?


Tob*_*ias 2

根据 Josh Caswell 的推荐自行解决此答案。


我在 CocoaHeads 会议上问过这个问题。我收到了查看 NSView 的 hitTest 的建议。因此,在我的两个自定义视图上,我重写了 NSView 的 hittest 函数,如下所示:

- (NSView*) hitTest:(NSPoint)aPoint {
    static int depth = 1;
    NSLog([NSString stringWithFormat:@"%%%dd ENTER %%@ - hitTest", depth], 
          depth, [[self class] description]);
    depth++;
    NSView *hitView = [super hitTest:aPoint];
    depth--;
    NSLog([NSString stringWithFormat:@"%%%dd EXIT %%@ - hitTest: %%@", depth], 
          depth, [[self class] description], [[hitView class] description]);
    return hitView;
}
Run Code Online (Sandbox Code Playgroud)

下面是输出:

MyCustomView 是 contentView 的子视图。
MyOpaqueCustomView (OCV) 是 contentView 的子视图。

1 ENTER OCV - hitTest
1 EXIT OCV - hitTest: NSTextField
1 ENTER OCV - hitTest
1 EXIT OCV - hitTest: NSTextField
1 ENTER OCV - hitTest
1 EXIT OCV - hitTest: NSTextView
MyCustomView - Dirty Rect: {{49, 189}, {127, 28} //!!Focus Ring Around Text Field
OCV - Dirty Rect: : {{49, 189}, {127, 28}}
testTextField isOpaque? Yes
1 ENTER OCV - hitTest
1 EXIT OCV - hitTest: NSTextView
MyCustomView - Dirty Rect: {{64, 194}, {1, 17}}
1 ENTER OCV - hitTest
1 EXIT OCV - hitTest: NSTextView
1 ENTER OCV - hitTest
1 EXIT OCV - hitTest: NSTextField
1 ENTER MyCustomView - hitTest
1 EXIT MyCustomView - hitTest: MyCustomView
MyCustomView - Dirty Rect: {{64, 194}, {1, 17}} //!!EVERY BLINK
MyCustomView - Dirty Rect: {{64, 194}, {1, 17}}
MyCustomView - Dirty Rect: {{64, 194}, {1, 17}}
MyCustomView - Dirty Rect: {{64, 194}, {1, 17}}
Run Code Online (Sandbox Code Playgroud)

MyCustomView 是 contentView 的子视图。
MyOpaqueCustomView (OCV) 是 MyCustomView 的子视图。

1 ENTER MyCustomView - hitTest
1 ENTER OCV - hitTest
1 EXIT OCV - hitTest: NSTextField
1 EXIT MyCustomView - hitTest: NSTextField
1 ENTER MyCustomView - hitTest
1 ENTER OCV - hitTest
1 EXIT OCV - hitTest: NSTextField
1 EXIT MyCustomView - hitTest: NSTextField
1 ENTER MyCustomView - hitTest
1 ENTER OCV - hitTest
1 EXIT OCV - hitTest: NSTextView
1 EXIT MyCustomView - hitTest: NSTextView
OCV - Dirty Rect: : {{49, 189}, {127, 28}} //!!FOCUS RING
testTextField isOpaque? Yes
1 ENTER MyCustomView - hitTest
1 ENTER OCV - hitTest
1 EXIT OCV - hitTest: NSTextView
1 EXIT MyCustomView - hitTest: NSTextView
1 ENTER MyCustomView - hitTest
1 ENTER OCV - hitTest
1 EXIT OCV - hitTest: NSTextView
1 EXIT MyCustomView - hitTest: NSTextView
1 ENTER MyCustomView - hitTest
1 ENTER OCV - hitTest
1 EXIT OCV - hitTest: NSTextField
1 EXIT MyCustomView - hitTest: NSTextField
//!!BLINKING HERE - But no dirtyRects.
Run Code Online (Sandbox Code Playgroud)

所以看起来对 hitTest 的响应定义了哪些视图将被重绘。