首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >禁用NSView淡出动画用于NSView‘`setHidden:’

禁用NSView淡出动画用于NSView‘`setHidden:’
EN

Stack Overflow用户
提问于 2013-11-08 21:58:13
回答 3查看 1.1K关注 0票数 0

我正在处理一个具有可拖放控件概念的项目,除了NSView在调用setHidden:时使用淡入/退出动画之外,一切都很好。

通过将session.animatesToStartingPositionsOnCancelOrFail = YES;行更改为NO,并使用自定义的动画NSWindow子类实现图像管理单元,我已经能够解决这个问题。看上去很棒,但我知道一定有更简单的方法。

我试过:

  1. NSAnimationContext调用周围使用持续时间为0的setHidden:分组
  2. 使用控件和superview上的各种键(alpha、隐藏、isHidden)设置视图动画字典
  3. 重写控件及其超级视图的animationForKey:

我没有使用CALayers,甚至尝试显式地将wantsLayer:设置为NO。

有人知道如何禁用这个动画,或者有一个比我的动画NSWindow__更简单的解决方案吗?

下面是我简化的、修改过的代码,最基本的内容就是看看我说的是什么。

代码语言:javascript
复制
@implementation NSControl (DragControl)

- (NSDraggingSession*)beginDraggingSessionWithDraggingCell:(NSActionCell <NSDraggingSource> *)cell event:(NSEvent*) theEvent
{
    NSImage* image = [self imageForCell:cell];
    NSDraggingItem* di = [[NSDraggingItem alloc] initWithPasteboardWriter:image];
    NSRect dragFrame = [self frameForCell:cell];
    dragFrame.size = image.size;
    [di setDraggingFrame:dragFrame contents:image];

    NSArray* items = [NSArray arrayWithObject:di];

    [self setHidden:YES];
    return [self beginDraggingSessionWithItems:items event:theEvent source:cell];
}

- (NSRect)frameForCell:(NSCell*)cell
{
    // override in multi-cell cubclasses!
    return self.bounds;
}

- (NSImage*)imageForCell:(NSCell*)cell
{
    return [self imageForCell:cell highlighted:[cell isHighlighted]];
}

- (NSImage*)imageForCell:(NSCell*)cell highlighted:(BOOL) highlight
{
    // override in multicell cubclasses to just get an image of the dragged cell.
    // for any single cell control we can just make sure that cell is the controls cell

    if (cell == self.cell || cell == nil) { // nil signifies entire control
                                            // basically a bitmap of the control
                                            // NOTE: the cell is irrelevant when dealing with a single cell control
        BOOL isHighlighted = [cell isHighlighted];
        [cell setHighlighted:highlight];

        NSRect cellFrame = [self frameForCell:cell];

        // We COULD just draw the cell, to an NSImage, but button cells draw their content
        // in a special way that would complicate that implementation (ex text alignment).
        // subclasses that have multiple cells may wish to override this to only draw the cell
        NSBitmapImageRep* rep = [self bitmapImageRepForCachingDisplayInRect:cellFrame];
        NSImage* image = [[NSImage alloc] initWithSize:rep.size];

        [self cacheDisplayInRect:cellFrame toBitmapImageRep:rep];
        [image addRepresentation:rep];
        // reset the original cell state
        [cell setHighlighted:isHighlighted];
        return image;
    }
    // cell doesnt belong to this control!
    return nil;
}

#pragma mark NSDraggingDestination

- (void)draggingEnded:(id < NSDraggingInfo >)sender
{
    [self setHidden:NO];
}

@end

@implementation NSActionCell (DragCell)

- (void)setControlView:(NSView *)view
{
    // this is a bit of a hack, but the easiest way to make the control dragging work.
    // force the control to accept image drags.
    // the control will forward us the drag destination events via our DragControl category

    [view registerForDraggedTypes:[NSImage imagePasteboardTypes]];
    [super setControlView:view];
}

- (BOOL)trackMouse:(NSEvent *)theEvent inRect:(NSRect)cellFrame ofView:(NSView *)controlView untilMouseUp:(BOOL)untilMouseUp
{
    BOOL result = NO;
    NSPoint currentPoint = theEvent.locationInWindow;
    BOOL done = NO;
    BOOL trackContinously = [self startTrackingAt:currentPoint inView:controlView];

    BOOL mouseIsUp = NO;
    NSEvent *event = nil;
    while (!done)
    {
        NSPoint lastPoint = currentPoint;

        event = [NSApp nextEventMatchingMask:(NSLeftMouseUpMask|NSLeftMouseDraggedMask)
                                   untilDate:[NSDate distantFuture]
                                      inMode:NSEventTrackingRunLoopMode
                                     dequeue:YES];

        if (event)
        {
            currentPoint = event.locationInWindow;

            // Send continueTracking.../stopTracking...
            if (trackContinously)
            {
                if (![self continueTracking:lastPoint
                                         at:currentPoint
                                     inView:controlView])
                {
                    done = YES;
                    [self stopTracking:lastPoint
                                    at:currentPoint
                                inView:controlView
                             mouseIsUp:mouseIsUp];
                }
                if (self.isContinuous)
                {
                    [NSApp sendAction:self.action
                                   to:self.target
                                 from:controlView];
                }
            }

            mouseIsUp = (event.type == NSLeftMouseUp);
            done = done || mouseIsUp;

            if (untilMouseUp)
            {
                result = mouseIsUp;
            } else {
                // Check if the mouse left our cell rect
                result = NSPointInRect([controlView
                                        convertPoint:currentPoint
                                        fromView:nil], cellFrame);
                if (!result)
                    done = YES;
            }

            if (done && result && ![self isContinuous])
                [NSApp sendAction:self.action
                               to:self.target
                             from:controlView];
            else {
                done = YES;
                result = YES;

                // this bit-o-magic executes on either a drag event or immidiately following timer expiration
                // this initiates the control drag event using NSDragging protocols
                NSControl* cv = (NSControl*)self.controlView;
                NSDraggingSession* session = [cv beginDraggingSessionWithDraggingCell:self
                                                                                event:theEvent];
                // Note that you will get an ugly flash effect when the image returns if this is set to yes
                // you can work around it by setting NO and faking the release by animating an NSWindowSubclass with the image as the content
                // create the window in the drag ended method for NSDragOperationNone
                // there is [probably a better and easier way around this behavior by playing with view animation properties.
                session.animatesToStartingPositionsOnCancelOrFail = YES;
            }

        }
    }
    return result;
}

#pragma mark - NSDraggingSource Methods
- (NSDragOperation)draggingSession:(NSDraggingSession *)session sourceOperationMaskForDraggingContext:(NSDraggingContext)context
{
    switch(context) {
        case NSDraggingContextOutsideApplication:
            return NSDragOperationNone;
            break;

        case NSDraggingContextWithinApplication:
        default:
            return NSDragOperationPrivate;
            break;
    }
}

- (void)draggingSession:(NSDraggingSession *)session endedAtPoint:(NSPoint)screenPoint operation:(NSDragOperation)operation
{
    // now tell the control view the drag ended so it can do any cleanup it needs
    // this is somewhat hackish
    [self.controlView draggingEnded:nil];
}

@end
EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2013-11-12 00:08:45

好的。我发现我看到的动画不是控件,也不是超级视图,也不是控件的窗口。看来,animatesToStartingPositionsOnCancelOrFail会导致NSDraggingSession创建一个窗口(用QuartzDebug观察到)并将拖动图像放入其中,并且这个窗口在执行setHidden:调用之前(也就是在拖动操作结束之前)会返回原点并逐渐消失。

不幸的是,它创建的窗口不是NSWindow,因此在NSWindow上创建类别不会禁用淡入动画。

其次,我所知道的获取窗口句柄的公共方式没有,所以我不能尝试直接操作窗口实例。

看来,我的解决办法可能是最好的方法,毕竟它与AppKit为您做的事情相差不远。

如果有人知道如何在这个窗口上获得句柄,或者它是什么类,我会有兴趣知道.

票数 0
EN

Stack Overflow用户

发布于 2013-11-10 10:21:45

必须在视图层次结构中的某个位置启用一个层,否则就不会有淡出动画。以下是我禁用这些动画的方法:

代码语言:javascript
复制
@interface NoAnimationImageView : NSImageView

@end

@implementation NoAnimationImageView

+ (id)defaultAnimationForKey: (NSString *)key
{
    return nil;
}

@end
票数 1
EN

Stack Overflow用户

发布于 2013-11-11 17:52:00

通过设置视图动画字典已经尝试过的解决方案应该可以工作。但不是为了你提到的钥匙而是为了下面。在第一次触发动画之前在某个地方使用它。如果你必须在窗口或视野中做,或者两者都做,我不知道。

代码语言:javascript
复制
NSMutableDictionary *animations = [NSMutableDictionary dictionaryWithDictionary:[[theViewOrTheWindow animator] animations];
[animations setObject:[NSNull null] forKey: NSAnimationTriggerOrderIn];
[animations setObject:[NSNull null] forKey: NSAnimationTriggerOrderOut];
[[theViewOrTheWindow animator] setAnimations:animations];

或者,如果键在那里,也只需删除它们(可能不是这样,因为它们是隐式/默认的):

代码语言:javascript
复制
NSMutableDictionary *animations = [NSMutableDictionary dictionaryWithDictionary:[[theViewOrTheWindow animator] animations];
[animations removeObjectForKey:NSAnimationTriggerOrderIn];
[animations removeObjectForKey:NSAnimationTriggerOrderOut];
[[theViewOrTheWindow animator] setAnimations:animations];
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/19869265

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档