як вы праведзяце лінію праграмна з кантролера прадстаўлення?

У мяне ёсць UIViewController . Я хачу, каб намаляваць лінію ў адным са сваіх праграмна створаных уяўленняў. Здаецца, дастаткова проста, але я не знайшоў прыклад кода, які працуе.

74
Ці можам мы ўбачыць код? Я згодны, гэта рэальны пытанне, але я (магчыма мы) лепш за ўсё рэагуюць закадаваць дэманстрацыі таго, што вы кажаце.
дададзена аўтар bugmagnet, крыніца
@xlc Вы можаце зрабіць гэта з ВК, як адказ паказвае Роба. Калі вы сапраўды хочаце, каб быць карысным, растлумачыць, што шкода ў тэхніцы Без'е.
дададзена аўтар mkc842, крыніца
«Закрыты ня рэальны пытанне.» «Цяжка сказаць, што пытаюцца тут.» «Не можа быць абгрунтавана адказаў.» Якая жарт! Пытанне зусім ясна, і Роб, падобна, не маюць якіх-небудзь праблем з адказам гэта выдатна. Калі ў вас ёсць праблемы з маім пытаннем, чаму б не растлумачыць праблему замест таго, каб закрыць яго на заведама непраўдзівых падставах?
дададзена аўтар mkc842, крыніца
Не, вы не можаце. Нанясенне павінна быць зроблена на ўвазе не кантролерам. Вы павінны змяніць свой дызайн.
дададзена аўтар Bryan Chen, крыніца
Гэта здаецца цалкам правільны пытанне не павінен быць зачынены.
дададзена аўтар Justin Ohms, крыніца

7 адказы

Ёсць два распаўсюджаных метадаў.

  1. Using CAShapeLayer:

    • Create a UIBezierPath (replace the coordinates with whatever you want):

      UIBezierPath *path = [UIBezierPath bezierPath];
      [path moveToPoint:CGPointMake(10.0, 10.0)];
      [path addLineToPoint:CGPointMake(100.0, 100.0)];
      
    • Create a CAShapeLayer that uses that UIBezierPath:

      CAShapeLayer *shapeLayer = [CAShapeLayer layer];
      shapeLayer.path = [path CGPath];
      shapeLayer.strokeColor = [[UIColor blueColor] CGColor];
      shapeLayer.lineWidth = 3.0;
      shapeLayer.fillColor = [[UIColor clearColor] CGColor];
      
    • Add that CAShapeLayer to your view's layer:

      [self.view.layer addSublayer:shapeLayer];
      

    In previous versions of Xcode, you had to manually add QuartzCore.framework to your project's "Link Binary with Libraries" and import the header in your .m file, but that's not necessary anymore (if you have the "Enable Modules" and "Link Frameworks Automatically" build settings turned on).

  2. The other approach is to subclass UIView and then use CoreGraphics calls in the drawRect method:

    • Create a UIView subclass and define a drawRect that draws your line.

      You can do this with 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);
      }
      

      Or using 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];
      }
      
    • Then you can either use this view class as the base class for your NIB/storyboard or view, or you can have your view controller programmatically add it as a subview:

      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 subclass:

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

    And add it to your view hierarchy:

    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
    

    Above, I'm adding PathView programmatically, but you can add it via IB, too, and just set its path programmatically.

170
дададзена
Высокі. Дзякуй за грунтоўны адказ.
дададзена аўтар mkc842, крыніца
@Rob: Гэта працуе выдатна. Я хачу спытаць вас, што ў мяне ёсць адлегласць да лініі АВ і кут ад АВ, то, як атрымаць пачатковую і канчатковыя кропкі ў гэтай сітуацыі? Калі ласка, дапамажы мне.
дададзена аўтар Manthan, крыніца
Пры выкарыстанні метаду CAShapeLayer вы можаце (і, верагодна, будзе хацець) ўсталяваць лінію вечка для закруглены так, што лініі выглядаюць гладкімі, як яны злучаюцца, shapeLayer.lineCap = kCALineCapRound;
дададзена аўтар Albert Renshaw, крыніца
я дадаў uigesture на мой погляд, і ў мяне ёсць сенсарны адпраўная кропка і рухалася кропка, калі я дадам, што ў вышэй каментарыю прамым працую належным чынам. калі я пакратаць на баку ад пачатковай кропкі сам яго займае колер @Rob
дададзена аўтар Kishore Kumar, крыніца
@Rob як выдаліць радок з поля зроку, abouve 1 метад ..
дададзена аўтар Kishore Kumar, крыніца
@Rob Угу дзякуй за дапамогу, вы качалка бог дабраслаўляе вас ....
дададзена аўтар Kishore Kumar, крыніца
Ці, калі ў вас ёсць некалькі радкоў, якія вы хочаце, каб выглядаць гладкай, як яны злучаюцца, вы таксама можаце мець адзіны UIBezierPath , з паўторным addLineToPoint / AddLine (для: ) званкі. Затым вы можаце выбраць, аддаеце перавагу Ці вы shapeLayer.lineJoin = kCALineJoinRound або kCALineJoinBevel або kCALineJoinMiter .
дададзена аўтар Rob, крыніца
Вялікае вам дзякуй. Шукаў ваш адказ на працягу некалькіх дзён.
дададзена аўтар eneskaya, крыніца

Стварэнне UIView і дадаць яго ў якасці падвіда гледжання вашага пункту гледжання кантролера. Вы можаце змяніць вышыню ці шырыню гэтага падвід, каб быць вельмі маленькім, так што яна выглядае як лінія. Калі вам трэба намаляваць дыяганальную лінію вы можаце мадыфікаваць падвіды ўласцівасць трансфармавацца.

напрыклад намаляваць чорную гарызантальную лінію. Гэта выклікаецца з рэалізацыі вашага пункту гледжання кантролера

<�Код> UIView * lineView = [[UIView Alloc] initWithFrame: CGRectMake (0,0, self.view.frame.size.width, 1)]; lineView.backgroundColor = [UIColor blackColor]; [Self.view addSubview: lineView];

11
дададзена
цікавая думка, дзякуй
дададзена аўтар mkc842, крыніца
Можа быць страшная думка, але яна працуе і простая.
дададзена аўтар sangony, крыніца
@sangony Я выкарыстоўваю гэтую тэхніку таксама ў маім кодзе. Я таксама задаюся пытаннем, чаму гэта жахлівая ідэя? Калі ласка, дапамажыце растлумачыць.
дададзена аўтар Joe Huang, крыніца
Я схільны пагадзіцца, што для раздзяляльнага элемента (напрыклад, лінію паміж элементамі карыстацкага інтэрфейсу), гэта шлях найменшага супраціву. Альтэрнатывай альбо рэндэрынг ў растравы малюнак назад у CoreAnimation пласт або рэалізацыі апрацоўшчыка адмалёўкі ў наладжвальнае ўяўленне значна складаней. Гэта, верагодна, апаратнае паскарэнне лепш таксама, пры ўмове, што гэта толькі адна лінія.
дададзена аўтар marko, крыніца
Мне цікава, развагі пра тое, чаму гэта жахлівая ідэя. Я хацеў бы пазбегнуць якіх-небудзь праблем, гэта рашэнне можа выклікаць у маім ўласным кодзе.
дададзена аўтар Jeff Ames, крыніца

Here's a cool technique you might find useful: Using blocks for drawing to avoid subclassing in 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];
8
дададзена

<�Моцны> 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
дададзена
Гэта цудоўна! Дзякуй.
дададзена аўтар Zhanserik, крыніца

Вы можаце выкарыстоўваць 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!

5
дададзена

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

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

а затым у метадах - [DelegateDrawView DrawRect:] выклік метаду дэлегаты.

Але чаму вы хочаце змясціць выгляд кода ў кантролеры.

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

2
дададзена

Для таго, каб намаляваць ўнутры вашага пункту гледжання вельмі проста, @ Mr.ROB сказаў 2 метад я зрабіў першы метад.

Проста скапіруйце устаўце код туды, дзе вы, хлопцы, жадаеце.

-(void)touchesBegan:(NSSet *)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 *)touches withEvent:(UIEvent *)event
{

}
-(void)touchesEnded:(NSSet *)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 *)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);
}

Ён будзе маляваць, як лініі, дзе палец рухаецца збіраецца

0
дададзена