如上图所示,Safari浏览器地址栏输入文字时,下方会自动弹出一个类似于菜单的下拉列表,用于展示关联的内容。
他是怎么实现的呢?
首先可以肯定的,这个下拉列表不是使用菜单做的,因为菜单会有焦点的问题,弹出菜单会抢占输入的焦点,同时移动safari的时候,这个下拉列表是跟着safari移动的,而菜单是会消失的。
这个下拉列表是safari浏览器的子窗口,子窗口不会抢占输入焦点,同时也可以随着主窗口一块移动。
窗口的默认样式是上方两个角是直角,下方两个角是圆角,而这个子窗口四个角都是圆角,所以我们还要定制子窗口的四个角为圆角。
下拉列表的内容展示就简单了,我们可以用table view来展示,同时捕获table view的鼠标事件来实现选择的高亮以及鼠标的点击事件。
NSSearchFiled的delegate函数controlTextDidChange:可以捕获NSSearchFiled内容的改变
- (void)controlTextDidChange: (NSNotification *)aNotification { NSString *searchString = [self.searchField stringValue]; }
NSSearchFiled的delegate函数control:textView:doCommandBySelector:,可以捕获键盘的命令操作,比如左移,右移,回车事件。如果返回TRUE,那么delegate负责处理键盘的事件,如果返回NO,那么由父类默认处理。
* SYXMenuWindowController类实现菜单窗口的主体功能,包括窗口的弹出,窗口的关闭,table view的展示, 实现table view鼠标事件的delegate函数等。
* BorderlessWindow这个类是NSWindow类的派生类,主要是产生一个没有边框的窗体,并将窗体contentView的superView设成RoundWindowFrameView(RoundWindowFrameView重定义了View的drawRect可以将view设置成四个角都是圆形)
* DetectingTableView这个类是NSTableView的派生类,用于监听table view上的鼠标进入、移出、移动事件以及点击事件。我们监听到鼠标进入table view以及在table view上移动,通过调用selectRowIndexes的方式来改变选择行的颜色。鼠标移出table view,通过调用deselectAll来取消选择。另外,当我们焦点在SearchFiled,键盘按下方向键的向下时,也是通过selectedRow获取table view当前选择的行,并且通过selectRowIndexes函数选择当前选择行的下一行来实现向下键选择下一行的操作。