Как вы рисуете линию программно из контроллера представления?

У меня есть UIViewController. Как нарисовать линию в одном из программно созданных видов?

Ответ 1

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

  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 в проект "Связать <QuartzCore/QuartzCore.h> с библиотеками" и импортировать <QuartzCore/QuartzCore.h> в файл .m, но это больше не требуется (если у вас есть Включены настройки сборки "Включить модули" и "Автоматически связывать фреймворки").

  2. Другой подход заключается в UIView подкласса 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 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 программно.

Ответ 2

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

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

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

Ответ 3

Здесь вы можете найти полезную технику: Использование блоков для рисования во избежание подклассов в Objective-C

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

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

Ответ 4

Вы можете использовать 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();

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

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

Ответ 5

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)

Ответ 6

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

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

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

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

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

Ответ 7

Чтобы рисовать внутри вашего представления очень просто, @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);
}

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