2013-12-03 4 views
9

В настоящее время я реализовал простой блок выбора с использованием событий мыши и перерисовку прямоугольника при перетаскивании мышью. Вот мой код:Ящик выбора чертежа (резиновые ленты, маршевые муравьи) в Cocoa, ObjectiveC

-(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]; 
} 

Ref: http://cocoadev.com/HowToCreateWalkingAnts

Вопросы:

Является ли это самый эффективный способ сделать это? Если представление было сложным, было бы более эффективным сделать прозрачный вид над основным видом вместо непрерывного перерисовки представления на время перетаскивания мышью (http://www.cocoabuilder.com/archive/cocoa/99877-drawing-selection-rectangle.html)? Как это делается? Кажется, я не могу найти примеров.

ответ

25

Вы можете использовать QuartzCore для анимации «маршевых муравьев» для вас, если хотите. Это полностью избавляет вас от мира, используя ручную коробку для выбора резины. Вы просто определяете путь, который определяет это поле, и пусть Core Animation позаботится о том, чтобы рисовать окно, а также его анимацию.

В «View Effects» Инспектор XIb, включите на «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 заботится о муравьиной для вас.

marching ants demo

+0

Это здорово. Чтобы прояснить это, создает ли это анимированный слой над представлением (т. Е. Не использует 'drawRect:', потому что этот слой сохраняется)? –

+0

@JohnSmith Правильно, не требуется «drawRect» (по крайней мере, для коробки выбора маршевых муравьев). Если вы делаете что-то еще в 'drawRect', не стесняйтесь иметь его. Но это не нужно для окна выбора. – Rob

+1

Отличный ответ! Просто интересно, будем ли мы все еще делать марш в этом столетии. Кажется, совсем немного стиля 1980/1990-х годов :-) – Jay

4

Этот пост немного старше, но я до сих пор не нашел хорошее решение (Framework) в Интернете. Но я думаю, что это задача (выбор контента), которую каждый должен освоить когда-нибудь, и для нее нет API от Apple. Однако я сделал свой собственный фреймворк и поставил Github: https://github.com/ckteebe/MultiSelectionSuiteFramework.

5

Если кто-то нуждается в версии 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 
} 



} 
4

скор 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 
    } 


} 
Смежные вопросы