2013-05-30 2 views
74

У меня есть UIViewController. Я хочу нарисовать линию в одном из ее программно созданных представлений. Кажется довольно простым, но я не нашел пример кода, который работает.Как вы черпаете линию программно с контроллера вида?

+2

Нет, вы не можете. Рисование должно выполняться по представлению, а не по контроллеру. Вы должны изменить свой дизайн. –

+1

@xlc Вы можете сделать это с VC, как показывает ответ Роба. Если вы действительно хотите быть полезными, объясните, в чем вред в технике Безье. – mkc842

+9

«Закрыто как не настоящий вопрос». «Трудно сказать, что здесь задают». «Не может быть разумного ответа». Ну и шутка! Вопрос совершенно ясен, и у Роба, похоже, не было никаких проблем с его ответом. Если у вас возникла проблема с моим вопросом, почему бы не объяснить вашу проблему, а не закрыть ее на явно ложных основаниях? – mkc842

ответ

168

Есть два распространенных методов.

  1. Использование CAShapeLayer:

    • Создать UIBezierPath (заменить координаты с тем, что вы хотите):

      UIBezierPath *path = [UIBezierPath bezierPath]; 
      [path moveToPoint:CGPointMake(10.0, 10.0)]; 
      [path addLineToPoint:CGPointMake(100.0, 100.0)]; 
      
    • Создать CAShapeLayer, который использует, что UIBezierPath:

      CAShapeLayer *shapeLayer = [CAShapeLayer layer]; 
      shapeLayer.path = [path CGPath]; 
      shapeLayer.strokeColor = [[UIColor blueColor] CGColor]; 
      shapeLayer.lineWidth = 3.0; 
      shapeLayer.fillColor = [[UIColor clearColor] CGColor]; 
      
    • Добавим, что CAShapeLayer к слою ваш взгляд в:

      [self.view.layer addSublayer:shapeLayer]; 
      

    В предыдущих версиях Xcode, приходилось вручную добавлять QuartzCore.framework to your project's "Link Binary with Libraries" и импортировать <QuartzCore/QuartzCore.h> заголовок в файле .m, но это не обязательно (если у вас есть встроенные настройки «Включить модули» и «Автоматически компоновка ссылок»).

  2. Другой подход к подклассу UIView, а затем использовать CoreGraphics вызовы в методе drawRect:

    • Создать UIView подкласс и определить drawRect, что черпает свою линию.

      Вы можете сделать это с Core Graphics:

      - (void)drawRect:(CGRect)rect { 
          CGContextRef context = UIGraphicsGetCurrentContext(); 
      
          CGContextSetStrokeColorWithColor(context, [[UIColor blueColor] CGColor]); 
          CGContextSetLineWidth(context, 3.0); 
          CGContextMoveToPoint(context, 10.0, 10.0); 
          CGContextAddLineToPoint(context, 100.0, 100.0); 
          CGContextDrawPath(context, kCGPathStroke); 
      } 
      

      Или с помощью UIKit:

      - (void)drawRect:(CGRect)rect { 
          UIBezierPath *path = [UIBezierPath bezierPath]; 
          [path moveToPoint:CGPointMake(10.0, 10.0)]; 
          [path addLineToPoint:CGPointMake(100.0, 100.0)]; 
          path.lineWidth = 3; 
          [[UIColor blueColor] setStroke]; 
          [path stroke]; 
      } 
      
    • Затем вы можете использовать этот вид класс в качестве базового класса для вашего NIB/раскадровки или зрения , или вы можете программным способом добавить ваш контроллер просмотра в качестве подсмотра:

      PathView *pathView = [[PathView alloc] initWithFrame:self.view.bounds]; 
      pathView.backgroundColor = [UIColor clearColor]; 
      
      [self.view addSubview: pathView]; 
      

Свифта исполнениями двух вышеуказанных подходов заключаются в следующем:

  1. CAShapeLayer:

    // create path 
    
    let path = UIBezierPath() 
    path.move(to: CGPoint(x: 10, y: 10)) 
    path.addLine(to: CGPoint(x: 100, y: 100)) 
    
    // Create a `CAShapeLayer` that uses that `UIBezierPath`: 
    
    let shapeLayer = CAShapeLayer() 
    shapeLayer.path = path.cgPath 
    shapeLayer.strokeColor = UIColor.blue.cgColor 
    shapeLayer.fillColor = UIColor.clear.cgColor 
    shapeLayer.lineWidth = 3 
    
    // Add that `CAShapeLayer` to your view's layer: 
    
    view.layer.addSublayer(shapeLayer) 
    
  2. UIView подкласса:

    class PathView: UIView { 
    
        var path: UIBezierPath?   { didSet { setNeedsDisplay() } } 
        var pathColor: UIColor = .blue { didSet { setNeedsDisplay() } } 
    
        override func draw(_ rect: CGRect) { 
         // stroke the path 
    
         pathColor.setStroke() 
         path?.stroke() 
        } 
    
    } 
    

    и добавить его в иерархии представлений:

    let pathView = PathView() 
    pathView.translatesAutoresizingMaskIntoConstraints = false 
    view.addSubview(pathView) 
    
    NSLayoutConstraint.activate([ 
        pathView.leadingAnchor.constraint(equalTo: view.leadingAnchor), 
        pathView.trailingAnchor.constraint(equalTo: view.trailingAnchor), 
        pathView.topAnchor.constraint(equalTo: view.topAnchor), 
        pathView.bottomAnchor.constraint(equalTo: view.bottomAnchor) 
    ]) 
    
    pathView.backgroundColor = .clear 
    
    let path = UIBezierPath() 
    path.move(to: CGPoint(x: 10, y: 10)) 
    path.addLine(to: CGPoint(x: 100, y: 100)) 
    path.lineWidth = 3 
    
    pathView.path = path 
    

    Выше я добавляю PathView программно, но вы можете добавить его через IB, тоже, и просто установить его path программно.

+3

Awesome. Спасибо за тщательный ответ. – mkc842

+0

Большое вам спасибо. Был поиск вашего ответа в течение нескольких дней. – eneskaya

+0

@Rob: Это работает отлично. Я хочу спросить вас, что у меня есть расстояние по прямой AB и угол от AB, а затем, как получить начальную и конечную точки в этой ситуации? Пожалуйста, помогите мне. – Manthan

11

Создайте UIView и добавьте его в качестве подзаголовка вашего представления контроллера. Вы можете изменить высоту или ширину этого подвью, чтобы они были очень маленькими, чтобы она выглядела как линия. Если вам нужно нарисовать диагональную линию, вы можете изменить свойство преобразования subviews.

например. черную горизонтальную линию. Это вызывается из реализации вашей точки зрения контроллера

UIView *lineView = [[UIView alloc] initWithFrame:CGRectMake(0,0, self.view.frame.size.width, 1)]; lineView.backgroundColor = [UIColor blackColor]; [self.view addSubview:lineView];

+0

Может быть, ужасная идея, но она работает и проста. – sangony

+0

Я был бы склонен согласиться с тем, что для разделительного элемента (например, линии между элементами UI) это путь наименьшего сопротивления. Альтернатива либо рендеринга в растровое изображение для поддержки слоя CoreAnimation, либо реализация обработчика рисования в пользовательском представлении гораздо более активна. Вероятно, аппаратное ускорение также улучшается, если только одна строка. – marko

+0

интересная мысль, спасибо – mkc842

2

Вы не должны действительно, но если по какой-то причине это имеет смысл для вас, вы можете создать подкласс UIView, который называется DelegateDrawView, например, который принимает делегат, который реализует метод, как

- (void)delegateDrawView:(DelegateDrawView *)aDelegateDrawView drawRect:(NSRect)dirtyRect 

, а затем в методах - [DelegateDrawView drawRect:] вы вызываете свой метод делегирования.

Но почему вы хотите поместить код просмотра в свой контроллер.

Вам лучше создать подкласс UIView, который рисует линию между двумя его углами, вы можете иметь свойство устанавливать, какие два, а затем позиционировать вид, где вы хотите, чтобы вы видели контроллер.

8

Вот крутая техника, которую вы могли бы оказаться полезными: Using blocks for drawing to avoid subclassing in Objective-C

Включить общего назначения вида подкласса артикля в проекте, то это своего рода код, который вы можете поместить в ваш контроллер представления, чтобы создать вид на fly, который рисует линию:

DrawView* drawableView = [[[DrawView alloc] initWithFrame:CGRectMake(0,0,320,50)] autorelease]; 
drawableView.drawBlock = ^(UIView* v,CGContextRef context) 
{ 
    CGPoint startPoint = CGPointMake(0,v.bounds.size.height-1); 
    CGPoint endPoint = CGPointMake(v.bounds.size.width,v.bounds.size.height-1); 

    CGContextSetStrokeColorWithColor(context, [UIColor grayColor].CGColor); 
    CGContextSetLineWidth(context, 1); 
    CGContextMoveToPoint(context, startPoint.x + 0.5, startPoint.y + 0.5); 
    CGContextAddLineToPoint(context, endPoint.x + 0.5, endPoint.y + 0.5); 
    CGContextStrokePath(context); 
}; 
[self.view addSubview:drawableView]; 
5

Вы можете использовать UIImageView для рисования линий.

Это, однако, позволяет пропустить подкласс. И поскольку я немного склонен к Core Graphics, он все равно может его использовать.Вы можете просто положить его в - ViewDidLoad

UIGraphicsBeginImageContext(self.view.frame.size); 
    [self.myImageView.image drawInRect:CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height)]; 
    CGContextSetLineCap(UIGraphicsGetCurrentContext(), kCGLineCapRound); 
    CGContextSetLineWidth(UIGraphicsGetCurrentContext(), brush); 

    CGContextMoveToPoint(UIGraphicsGetCurrentContext(), 50, 50); 
    CGContextAddLineToPoint(UIGraphicsGetCurrentContext(), 200, 200); 
    CGContextStrokePath(UIGraphicsGetCurrentContext()); 
    CGContextFlush(UIGraphicsGetCurrentContext()); 
    self.myImageView.image = UIGraphicsGetImageFromCurrentImageContext(); 
    UIGraphicsEndImageContext(); 

Дополнение к ответу Роба Для Quicke, третий подход заключается в использовании UIImageView - прикрывать с ней - вид XIb. (Это вид UIImageView по умолчанию при перетаскивании на xib в xcode 5)

Приветствия и +1!

0

Чтобы сделать внутри ваше мнение очень просто, @ Mr.ROB сказал, что 2 метода я взял первый метод.

Просто скопируйте код, в котором вы его хотите.

-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event 
{ 
    UITouch *touch = [[event allTouches] anyObject]; 
    startingPoint = [touch locationInView:self.view]; 

    NSLog(@"Touch starting point = x : %f Touch Starting Point = y : %f", touchPoint.x, touchPoint.y); 
} 
-(void)touchesCancelled:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event 
{ 

} 
-(void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event 
{ 
    UITouch *touch = [[event allTouches] anyObject]; 
    touchPoint = [touch locationInView:self.view]; 

    NSLog(@"Touch end point =x : %f Touch end point =y : %f", touchPoint.x, touchPoint.y); 
} 
-(void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event 
{ 

    UITouch *touch = [[event allTouches] anyObject]; 
    touchPoint = [touch locationInView:self.view]; 
    UIBezierPath *path = [UIBezierPath bezierPath]; 
    [path moveToPoint:CGPointMake(touchPoint.x,touchPoint.y)]; 
    [path addLineToPoint:CGPointMake(startingPoint.x,startingPoint.y)]; 
    startingPoint=touchPoint; 
    CAShapeLayer *shapeLayer = [CAShapeLayer layer]; 
    shapeLayer.path = [path CGPath]; 
    shapeLayer.strokeColor = [[UIColor blueColor] CGColor]; 
    shapeLayer.lineWidth = 3.0; 
    shapeLayer.fillColor = [[UIColor redColor] CGColor]; 
    [self.view.layer addSublayer:shapeLayer]; 

    NSLog(@"Touch moving point =x : %f Touch moving point =y : %f", touchPoint.x, touchPoint.y); 
    [self.view setNeedsDisplay]; 


} 
- (void)tapGestureRecognizer:(UIGestureRecognizer *)recognizer { 
    CGPoint tappedPoint = [recognizer locationInView:self.view]; 
    CGFloat xCoordinate = tappedPoint.x; 
    CGFloat yCoordinate = tappedPoint.y; 

    NSLog(@"Touch Using UITapGestureRecognizer x : %f y : %f", xCoordinate, yCoordinate); 
} 

Он будет рисовать, как линии, где палец движется не собирается

4

Swift 3:

let path = UIBezierPath() 
path.move(to: CGPoint(x: 10, y: 10)) 
path.addLine(to: CGPoint(x: 100, y: 100)) 

let shapeLayer = CAShapeLayer() 
shapeLayer.path = path.cgPath 
shapeLayer.strokeColor = UIColor.blue.cgColor 
shapeLayer.lineWidth = 3.0 

view.layer.addSublayer(shapeLayer) 
+0

Это здорово! Спасибо. – Zhanserik

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