【问题标题】:Drawing selection box (rubberbanding, marching ants) in Cocoa, ObjectiveC在 Cocoa,Objective C 中绘制选择框(橡皮筋,行军蚂蚁)
【发布时间】:2013-12-03 17:38:05
【问题描述】:

我目前使用鼠标事件实现了一个简单的选择框,并在鼠标拖动时重绘了一个矩形。这是我的代码:

-(void)drawRect:(NSRect)dirtyRect
{
if (!NSEqualRects(self.draggingBox, NSZeroRect))
{
    [[NSColor grayColor] setStroke];
    [[NSBezierPath bezierPathWithRect:self.draggingBox] stroke];
}
}

#pragma mark Mouse Events

- (void)mouseDown:(NSEvent *)theEvent
{
    NSPoint pointInView = [self convertPoint:[theEvent locationInWindow] fromView:nil];
    self.draggingBox = NSMakeRect(pointInView.x, pointInView.y, 0, 0);
    [self setNeedsDisplay:YES];
}

- (void)mouseDragged:(NSEvent *)theEvent
{
    NSPoint pointInView = [self convertPoint:[theEvent locationInWindow] fromView:nil];
    _draggingBox.size.width = pointInView.x - (self.draggingBox.origin.x);
    _draggingBox.size.height = pointInView.y - (self.draggingBox.origin.y);
    [self setNeedsDisplay:YES];
}

- (void)mouseUp:(NSEvent *)theEvent
{
    self.draggingBox = NSZeroRect;
    [self setNeedsDisplay:YES];
}

参考:http://cocoadev.com/HowToCreateWalkingAnts

问题:

这是最有效的方法吗?如果视图很复杂,在主视图上绘制透明视图而不是在鼠标拖动期间不断重绘视图会更有效吗(http://www.cocoabuilder.com/archive/cocoa/99877-drawing-selection-rectangle.html)?这是怎么做到的?我似乎找不到任何例子。

【问题讨论】:

    标签: objective-c macos cocoa nsview


    【解决方案1】:

    如果您愿意,您可以使用 QuartzCore 为您制作“行军蚂蚁”的动画。这也使您完全摆脱了手动绘制橡皮筋选择框的世界。您只需定义定义该框的路径,并让 Core Animation 负责绘制该框并为其设置动画。

    在 XIB 的“View Effects”Inspector 中,打开“Core Animation”,然后你可以这样做:

    #import <QuartzCore/QuartzCore.h>
    #import "CustomView.h"
    
    @interface CustomView ()
    
    @property (nonatomic) NSPoint startPoint;
    @property (nonatomic, strong) CAShapeLayer *shapeLayer;
    
    @end
    
    @implementation CustomView
    
    #pragma mark Mouse Events
    
    - (void)mouseDown:(NSEvent *)theEvent
    {
        self.startPoint = [self convertPoint:[theEvent locationInWindow] fromView:nil];
    
        // create and configure shape layer
    
        self.shapeLayer = [CAShapeLayer layer];
        self.shapeLayer.lineWidth = 1.0;
        self.shapeLayer.strokeColor = [[NSColor blackColor] CGColor];
        self.shapeLayer.fillColor = [[NSColor clearColor] CGColor];
        self.shapeLayer.lineDashPattern = @[@10, @5];
        [self.layer addSublayer:self.shapeLayer];
    
        // create animation for the layer
    
        CABasicAnimation *dashAnimation;
        dashAnimation = [CABasicAnimation animationWithKeyPath:@"lineDashPhase"];
        [dashAnimation setFromValue:@0.0f];
        [dashAnimation setToValue:@15.0f];
        [dashAnimation setDuration:0.75f];
        [dashAnimation setRepeatCount:HUGE_VALF];
        [self.shapeLayer addAnimation:dashAnimation forKey:@"linePhase"];
    }
    
    - (void)mouseDragged:(NSEvent *)theEvent
    {
        NSPoint point = [self convertPoint:[theEvent locationInWindow] fromView:nil];
    
        // create path for the shape layer
    
        CGMutablePathRef path = CGPathCreateMutable();
        CGPathMoveToPoint(path, NULL, self.startPoint.x, self.startPoint.y);
        CGPathAddLineToPoint(path, NULL, self.startPoint.x, point.y);
        CGPathAddLineToPoint(path, NULL, point.x, point.y);
        CGPathAddLineToPoint(path, NULL, point.x, self.startPoint.y);
        CGPathCloseSubpath(path);
    
        // set the shape layer's path
    
        self.shapeLayer.path = path;
    
        CGPathRelease(path);
    }
    
    - (void)mouseUp:(NSEvent *)theEvent
    {
        [self.shapeLayer removeFromSuperlayer];
        self.shapeLayer = nil;
    }
    
    @end
    

    这样,Core Animation 会为你照顾行军的蚂蚁。

    【讨论】:

    • 太好了。不过要澄清一下,这是否会在视图上方创建一个动画层(即不使用drawRect:,因为该层被保留)?
    • @JohnSmith 正确,不需要drawRect(至少对于行军蚂蚁选择框)。如果您在drawRect 中做其他事情,请随意拥有一个。但是选择框不需要它。
    • 很好的答案!只是想知道本世纪我们是否还在做蚂蚁行军……似乎有点 1980/1990 年代的风格:-)
    • 如果你真的想要一个点粗的线,你需要将每个坐标四舍五入到最近的点半。
    【解决方案2】:

    swift 3 版本:

    import Cocoa
    import QuartzCore
    
    class myView: NSView {
    
        //MARK:Properties
        var startPoint : NSPoint!
        var shapeLayer : CAShapeLayer!
    
        override func draw(_ dirtyRect: NSRect) {
            super.draw(dirtyRect)
    
            // Drawing code here.
        }
    
    
        override func mouseDown(with event: NSEvent) {
    
            self.startPoint = self.convert(event.locationInWindow, from: nil)
    
            shapeLayer = CAShapeLayer()
            shapeLayer.lineWidth = 1.0
            shapeLayer.fillColor = NSColor.clear.cgColor
            shapeLayer.strokeColor = NSColor.black.cgColor
            shapeLayer.lineDashPattern = [10,5]
            self.layer?.addSublayer(shapeLayer)
    
            var dashAnimation = CABasicAnimation()
            dashAnimation = CABasicAnimation(keyPath: "lineDashPhase")
            dashAnimation.duration = 0.75
            dashAnimation.fromValue = 0.0
            dashAnimation.toValue = 15.0
            dashAnimation.repeatCount = .infinity
            shapeLayer.add(dashAnimation, forKey: "linePhase")
    
    
    
    
        }
    
        override func mouseDragged(with event: NSEvent) {
    
            let point : NSPoint = self.convert(event.locationInWindow, from: nil)
            let path = CGMutablePath()
            path.move(to: self.startPoint)
            path.addLine(to: NSPoint(x: self.startPoint.x, y: point.y))
            path.addLine(to: point)
            path.addLine(to: NSPoint(x:point.x,y:self.startPoint.y))
            path.closeSubpath()
            self.shapeLayer.path = path
        }
    
        override func mouseUp(with event: NSEvent) {
            self.shapeLayer.removeFromSuperlayer()
            self.shapeLayer = nil
        }
    
    
    }
    

    【讨论】:

      【解决方案3】:

      这篇文章有点老了,但我在网上仍然没有找到好的解决方案(框架)。但我想这是每个人总有一天都必须掌握的任务(内容选择),而且苹果没有为此提供 API。不过我自己做了框架,放到 Github 上:https://github.com/ckteebe/MultiSelectionSuiteFramework.

      【讨论】:

        【解决方案4】:

        如果有人需要 Swift 2.0 版本,这里是:

        import Cocoa
        import QuartzCore
        
        
        class myView: NSView {
        
        var startPoint : NSPoint!
        var shapeLayer : CAShapeLayer!
        
        
        
        override func drawRect(dirtyRect: NSRect) {
            super.drawRect(dirtyRect)
        
            // Drawing code here.
        }
        
        
        override func mouseDown(theEvent: NSEvent) {
        
            self.startPoint = self.convertPoint(theEvent.locationInWindow, fromView: nil)
        
            shapeLayer = CAShapeLayer()
            shapeLayer.lineWidth = 1.0
            shapeLayer.fillColor = NSColor.clearColor().CGColor
            shapeLayer.strokeColor = NSColor.blackColor().CGColor
            shapeLayer.lineDashPattern = [10,5]
            self.layer?.addSublayer(shapeLayer)
        
            var dashAnimation = CABasicAnimation()
            dashAnimation = CABasicAnimation(keyPath: "lineDashPhase")
            dashAnimation.duration = 0.75
            dashAnimation.fromValue = 0.0
            dashAnimation.toValue = 15.0
            dashAnimation.repeatCount = .infinity
            shapeLayer.addAnimation(dashAnimation, forKey: "linePhase")
        
        
        
        
        }
        
        override func mouseDragged(theEvent: NSEvent) {
        
            let point : NSPoint = self.convertPoint(theEvent.locationInWindow, fromView: nil)
            let path = CGPathCreateMutable()
            CGPathMoveToPoint(path, nil, self.startPoint.x, self.startPoint.y)
            CGPathAddLineToPoint(path, nil, self.startPoint.x, point.y)
            CGPathAddLineToPoint(path, nil, point.x, point.y)
            CGPathAddLineToPoint(path, nil, point.x, self.startPoint.y)
            CGPathCloseSubpath(path)
            self.shapeLayer.path = path
        }
        
        override func mouseUp(theEvent: NSEvent) {
            self.shapeLayer.removeFromSuperlayer()
            self.shapeLayer = nil
        }
        
        
        
        }
        

        【讨论】:

          猜你喜欢
          • 2019-09-05
          • 2017-05-22
          • 1970-01-01
          • 2014-09-21
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多