NSSplitView - 如何在视图完成大小调整后收到通知?

时间:2013-05-18 00:41:06

标签: objective-c macos nssplitview

我需要知道任何NSSplitView子视图的帧何时发生了变化,但只有在它们完成大小调整之后才会知道。

目前我在NSSplitView子类中使用它:

[[NSNotificationCenter defaultCenter] addObserver: self
                                      selector: @selector(didResize:)
                                      name: NSSplitViewDidResizeSubviewsNotification
                                      object: self];

但我遇到的问题是,当分割视图被调整大小或包含窗口改变它的帧大小时,这会发送数百个通知。这对性能产生了很大的不利影响!

一旦拆分视图改变了框架(不添加任何开销或杂乱 - 如果调整大小已经停止,则经常检查计时器并不是我想要的解决方案),我怎么能分辨出来。

4 个答案:

答案 0 :(得分:1)

如果您不想对每个更改做出响应,我认为您需要使用某种计时方法。我想这样的事情应该会很好用。只要在.1秒内再次调用该方法,第一行将取消第二行。

-(void)splitViewDidResizeSubviews:(NSNotification *)notification {
    [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(respondToSubviewChange) object:nil];
    [self performSelector:@selector(respondToSubviewChange) withObject:nil afterDelay:.1];
}

-(void)respondToSubviewChange {
    NSLog(@"here");
   // Do your work here.
}

顺便说一句,如果此代码所在的类是拆分视图的委托,那么您不需要注册此通知,它会自动注册。

编辑后:

我确实找到了另一种不使用任何计时机制的方法,但我不知道它有多强大。它依赖于splitView:constrainMinCoordinate:ofSubviewAt:在你在分隔符中的mouseDown时调用的事实,并且再次使用mouseUp。当应用程序第一次启动时(或者当分割视图所在的窗口被加载,或者某些东西 - 我没有用多个窗口测试它时)它也被调用一次。因此,将“timesCalled”设置为-1(而不是0)是为了让逻辑在应用程序启动时忽略第一次调用。此后,if子句在委托方法的每个其他调用(将在mouseUp上)的计算结果为true。

- (CGFloat)splitView:(NSSplitView *)splitView constrainMinCoordinate:(CGFloat)proposedMin ofSubviewAt:(NSInteger)dividerIndex {
    static int timesCalled = -1;
    if (timesCalled % 2 == 1) {
        NSLog(@"Do stuff");
        // Do your work here.
    }
    timesCalled ++;
    return 0 // 0 allows you to minimize the subview all the way to 0;
}

答案 1 :(得分:0)

您可以从子类中的窗格拆分器中查找mouseDown mouseDragged和mouseUp事件。此时,您可以使用它来发布子类的通知。 您可以检查现有的NSSplitView子类,如古老的RBSplitView,看看它们是否已经完成了您想要的操作。

答案 2 :(得分:0)

仅实施此委托方法。 当我实现其他调整大小的委托方法时,结果搞砸了。

每次鼠标移动时都会调用此方法,并在释放鼠标时再次调用此方法。

- (void)splitViewDidResizeSubviews:(NSNotification *)notification {

if (notification.object == self.contentSplitView){ //get the right splitview

    static CGFloat last = 0; //keep tracks with widths
    static BOOL didChangeWidth = NO; //used to ignore height changes

    CGFloat width_new = self.tableview_images.frame.size.width; //get the new width
    if (last == width_new && didChangeWidth){ //
        [self.tableview_images reloadData];

        NSLog(@"finish!");
        didChangeWidth = NO;

    } else {


        if (last != width_new){
            if (last != 0){
                didChangeWidth = YES;
            }
        }
    }
    last = width_new;

}

}

答案 3 :(得分:0)

viewDidEndLiveResize 在窗口调整大小和分隔线拖动后在 NSSplitView 上调用。您可以使用它发送自定义通知。

extension Notification.Name {
    static public let didEndLiveResize = Notification.Name("didEndLiveReze")
}

class SplitView: NSSplitView
{
    override func viewDidEndLiveResize() {
        super.viewDidEndLiveResize()
        NotificationCenter.default.post(name: .didEndLiveResize, object: self)
    }
}