web-dev-qa-db-fra.com

Comment dessinez-vous une ligne par programme à partir d'un contrôleur de vue?

J'ai un UIViewController. Comment tracer une ligne dans l'une de ses vues créées par programme?

80
mkc842

Il existe deux techniques courantes.

  1. Utiliser CAShapeLayer :

    • Créez un UIBezierPath (remplacez les coordonnées par ce que vous voulez):

      UIBezierPath *path = [UIBezierPath bezierPath];
      [path moveToPoint:CGPointMake(10.0, 10.0)];
      [path addLineToPoint:CGPointMake(100.0, 100.0)];
      
    • Créez un CAShapeLayer qui utilise ce UIBezierPath:

      CAShapeLayer *shapeLayer = [CAShapeLayer layer];
      shapeLayer.path = [path CGPath];
      shapeLayer.strokeColor = [[UIColor blueColor] CGColor];
      shapeLayer.lineWidth = 3.0;
      shapeLayer.fillColor = [[UIColor clearColor] CGColor];
      
    • Ajoutez ce CAShapeLayer au calque de votre vue:

      [self.view.layer addSublayer:shapeLayer];
      

    Dans les versions précédentes de Xcode, vous deviez ajouter manuellement QuartzCore.framework au "Link Binary with Libraries" de votre projet et importer le fichier <QuartzCore/QuartzCore.h> en-tête dans votre fichier .m, mais ce n’est plus nécessaire (si les paramètres de construction "Activer les modules" et "Lier automatiquement les cadres" sont activés).

  2. L’autre approche consiste à sous-classer UIView et à utiliser ensuite CoreGraphics appelle dans la méthode drawRect :

    • Créez une sous-classe UIView et définissez un drawRect qui dessine votre ligne.

      Vous pouvez le faire avec 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);
      }
      

      Ou en utilisant 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];
      }
      
    • Vous pouvez ensuite utiliser cette classe de vue comme classe de base pour votre NIB/storyboard ou votre vue, ou vous pouvez demander à votre contrôleur de vue de l'ajouter par programmation en tant que sous-vue:

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

Les rendus Swift des deux approches ci-dessus sont les suivants:

  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 sous-classe:

    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()
        }
    
    }
    

    Et ajoutez-le à votre hiérarchie de vues:

    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
    

    Ci-dessus, j'ajoute PathView par programmation, mais vous pouvez aussi l'ajouter via IB, et définissez simplement sa path par programmation.

179
Rob

Créez un UIView et ajoutez-le en tant que sous-vue de la vue de votre contrôleur de vue. Vous pouvez modifier la hauteur ou la largeur de cette sous-vue pour qu'elle soit très petite, afin qu'elle ressemble à une ligne. Si vous devez tracer une ligne diagonale, vous pouvez modifier la propriété de transformation des sous-vues.

par exemple. tracer une ligne horizontale noire. Ceci est appelé depuis l'implémentation de votre contrôleur de vue

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

12
Jeff Ames

Voici une technique intéressante qui pourrait vous être utile: tilisation de blocs de dessin pour éviter les sous-classes dans Objective-C

Incluez la sous-classe de vue à usage général de l'article dans votre projet. Il s'agit du type de code que vous pouvez mettre dans votre contrôleur de vue pour créer une vue à la volée qui trace une ligne:

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];
8
Pierre Houston

Vous pouvez utiliser UIImageView pour dessiner des lignes.

Cela permet toutefois de sauter le sous-classement. Et comme je suis peu enclin à Core Graphics, je peux toujours l'utiliser. Vous pouvez simplement le mettre dans - 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();

Ajout à la réponse de Rob, Pour un coup de œil, la troisième approche consiste à utiliser un UIImageView - le recouvrir - la vue de xib. (C’est l’apparence par défaut de UIImageView lorsqu’il est glissé sur xib dans xcode 5)

Vive et +1!

6
khunshan

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
Baraa Al-Tabbaa

Vous ne devriez pas vraiment, mais si pour une raison quelconque cela vous semble logique, vous pouvez créer une sous-classe d’UIView, appelée DelegateDrawView par exemple, qui prend un délégué qui implémente une méthode telle que

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

puis dans les méthodes - [DelegateDrawView drawRect:], vous appelez votre méthode déléguée.

Mais pourquoi voudriez-vous mettre le code de vue dans votre contrôleur?.

Vous feriez mieux de créer une sous-classe de UIView, qui trace une ligne entre deux de ses coins, vous pouvez avoir une propriété pour définir laquelle et ensuite positionner la vue où vous le souhaitez depuis votre contrôleur de vue.

2
Nathan Day

Dessiner à l'intérieur de votre vue est très simple, @ Mr.ROB a déclaré 2 méthode j'ai pris la première méthode.

Il suffit de copier coller le code où vous le voulez.

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

Il va tracer comme une ligne, où le doigt se déplace

1
Kishore Kumar